@pipecat-ai/websocket-transport 1.5.0 → 1.6.1
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.d.ts.map +1 -1
- package/dist/index.js +171 -91
- package/dist/index.js.map +1 -1
- package/dist/index.module.js +171 -91
- package/dist/index.module.js.map +1 -1
- package/package.json +11 -4
package/dist/index.module.js
CHANGED
|
@@ -75,11 +75,11 @@ import {mulaw as $kR6tG$mulaw} from "x-law";
|
|
|
75
75
|
const { bitsPerSample: bitsPerSample, channels: channels, data: data } = audio;
|
|
76
76
|
const output = [
|
|
77
77
|
// Header
|
|
78
|
-
|
|
78
|
+
"RIFF",
|
|
79
79
|
this._packData(1, 52),
|
|
80
|
-
|
|
80
|
+
"WAVE",
|
|
81
81
|
// chunk 1
|
|
82
|
-
|
|
82
|
+
"fmt ",
|
|
83
83
|
this._packData(1, 16),
|
|
84
84
|
this._packData(0, 1),
|
|
85
85
|
this._packData(0, channels.length),
|
|
@@ -88,12 +88,12 @@ import {mulaw as $kR6tG$mulaw} from "x-law";
|
|
|
88
88
|
this._packData(0, channels.length * bitsPerSample / 8),
|
|
89
89
|
this._packData(0, bitsPerSample),
|
|
90
90
|
// chunk 2
|
|
91
|
-
|
|
91
|
+
"data",
|
|
92
92
|
this._packData(1, channels[0].length * channels.length * bitsPerSample / 8),
|
|
93
93
|
data
|
|
94
94
|
];
|
|
95
95
|
const blob = new Blob(output, {
|
|
96
|
-
type:
|
|
96
|
+
type: "audio/mpeg"
|
|
97
97
|
});
|
|
98
98
|
const url = URL.createObjectURL(blob);
|
|
99
99
|
return {
|
|
@@ -130,18 +130,18 @@ const $03f71ce85e00ada6$var$octave8Frequencies = [
|
|
|
130
130
|
];
|
|
131
131
|
// Labels for each of the above frequencies
|
|
132
132
|
const $03f71ce85e00ada6$var$octave8FrequencyLabels = [
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
133
|
+
"C",
|
|
134
|
+
"C#",
|
|
135
|
+
"D",
|
|
136
|
+
"D#",
|
|
137
|
+
"E",
|
|
138
|
+
"F",
|
|
139
|
+
"F#",
|
|
140
|
+
"G",
|
|
141
|
+
"G#",
|
|
142
|
+
"A",
|
|
143
|
+
"A#",
|
|
144
|
+
"B"
|
|
145
145
|
];
|
|
146
146
|
const $03f71ce85e00ada6$export$776c63898ae5b636 = [];
|
|
147
147
|
const $03f71ce85e00ada6$export$facd167cc27ea9b0 = [];
|
|
@@ -176,7 +176,7 @@ class $f32f064564ee62f6$export$2c3136da0bf130f9 {
|
|
|
176
176
|
* @param {number} [minDecibels] default -100
|
|
177
177
|
* @param {number} [maxDecibels] default -30
|
|
178
178
|
* @returns {AudioAnalysisOutputType}
|
|
179
|
-
*/ static getFrequencies(analyser, sampleRate, fftResult, analysisType =
|
|
179
|
+
*/ static getFrequencies(analyser, sampleRate, fftResult, analysisType = "frequency", minDecibels = -100, maxDecibels = -30) {
|
|
180
180
|
if (!fftResult) {
|
|
181
181
|
fftResult = new Float32Array(analyser.frequencyBinCount);
|
|
182
182
|
analyser.getFloatFrequencyData(fftResult);
|
|
@@ -186,8 +186,8 @@ class $f32f064564ee62f6$export$2c3136da0bf130f9 {
|
|
|
186
186
|
let outputValues;
|
|
187
187
|
let frequencies;
|
|
188
188
|
let labels;
|
|
189
|
-
if (analysisType ===
|
|
190
|
-
const useFrequencies = analysisType ===
|
|
189
|
+
if (analysisType === "music" || analysisType === "voice") {
|
|
190
|
+
const useFrequencies = analysisType === "voice" ? (0, $03f71ce85e00ada6$export$dbc1581ed2cfa183) : (0, $03f71ce85e00ada6$export$776c63898ae5b636);
|
|
191
191
|
const aggregateOutput = Array(useFrequencies.length).fill(minDecibels);
|
|
192
192
|
for(let i = 0; i < fftResult.length; i++){
|
|
193
193
|
const frequency = i * frequencyStep;
|
|
@@ -198,8 +198,8 @@ class $f32f064564ee62f6$export$2c3136da0bf130f9 {
|
|
|
198
198
|
}
|
|
199
199
|
}
|
|
200
200
|
outputValues = aggregateOutput;
|
|
201
|
-
frequencies = analysisType ===
|
|
202
|
-
labels = analysisType ===
|
|
201
|
+
frequencies = analysisType === "voice" ? (0, $03f71ce85e00ada6$export$dbc1581ed2cfa183) : (0, $03f71ce85e00ada6$export$776c63898ae5b636);
|
|
202
|
+
labels = analysisType === "voice" ? (0, $03f71ce85e00ada6$export$30a6f2881311088f) : (0, $03f71ce85e00ada6$export$facd167cc27ea9b0);
|
|
203
203
|
} else {
|
|
204
204
|
outputValues = Array.from(fftResult);
|
|
205
205
|
frequencies = outputValues.map((_, i)=>frequencyStep * i);
|
|
@@ -285,7 +285,7 @@ class $f32f064564ee62f6$export$2c3136da0bf130f9 {
|
|
|
285
285
|
* @param {number} [minDecibels] default -100
|
|
286
286
|
* @param {number} [maxDecibels] default -30
|
|
287
287
|
* @returns {AudioAnalysisOutputType}
|
|
288
|
-
*/ getFrequencies(analysisType =
|
|
288
|
+
*/ getFrequencies(analysisType = "frequency", minDecibels = -100, maxDecibels = -30) {
|
|
289
289
|
let fftResult = null;
|
|
290
290
|
if (this.audioBuffer && this.fftResults.length) {
|
|
291
291
|
const pct = this.audio.currentTime / this.audio.duration;
|
|
@@ -299,7 +299,7 @@ class $f32f064564ee62f6$export$2c3136da0bf130f9 {
|
|
|
299
299
|
* user interaction when the AudioAnalysis was instantiated.
|
|
300
300
|
* @returns {Promise<true>}
|
|
301
301
|
*/ async resumeIfSuspended() {
|
|
302
|
-
if (this.context.state ===
|
|
302
|
+
if (this.context.state === "suspended") await this.context.resume();
|
|
303
303
|
return true;
|
|
304
304
|
}
|
|
305
305
|
}
|
|
@@ -399,7 +399,7 @@ registerProcessor('stream_processor', StreamProcessor);
|
|
|
399
399
|
const $29a8a70a9466b14f$var$script = new Blob([
|
|
400
400
|
$29a8a70a9466b14f$export$50b76700e2b15e9
|
|
401
401
|
], {
|
|
402
|
-
type:
|
|
402
|
+
type: "application/javascript"
|
|
403
403
|
});
|
|
404
404
|
const $29a8a70a9466b14f$var$src = URL.createObjectURL($29a8a70a9466b14f$var$script);
|
|
405
405
|
const $29a8a70a9466b14f$export$bfa8c596114d74df = $29a8a70a9466b14f$var$src;
|
|
@@ -754,7 +754,7 @@ registerProcessor('audio_processor', AudioProcessor);
|
|
|
754
754
|
const $8e1d1e6ff08f6fb5$var$script = new Blob([
|
|
755
755
|
$8e1d1e6ff08f6fb5$var$AudioProcessorWorklet
|
|
756
756
|
], {
|
|
757
|
-
type:
|
|
757
|
+
type: "application/javascript"
|
|
758
758
|
});
|
|
759
759
|
const $8e1d1e6ff08f6fb5$var$src = URL.createObjectURL($8e1d1e6ff08f6fb5$var$script);
|
|
760
760
|
const $8e1d1e6ff08f6fb5$export$1f65f50a8cbff43c = $8e1d1e6ff08f6fb5$var$src;
|
|
@@ -818,7 +818,7 @@ class $62bc376044a05513$export$439b217ca659a877 {
|
|
|
818
818
|
blob = new Blob([
|
|
819
819
|
arrayBuffer
|
|
820
820
|
], {
|
|
821
|
-
type:
|
|
821
|
+
type: "audio/wav"
|
|
822
822
|
});
|
|
823
823
|
} else {
|
|
824
824
|
let float32Array;
|
|
@@ -873,9 +873,9 @@ class $62bc376044a05513$export$439b217ca659a877 {
|
|
|
873
873
|
* Retrieves the current status of the recording
|
|
874
874
|
* @returns {"ended"|"paused"|"recording"}
|
|
875
875
|
*/ getStatus() {
|
|
876
|
-
if (!this.processor) return
|
|
877
|
-
else if (!this.recording) return
|
|
878
|
-
else return
|
|
876
|
+
if (!this.processor) return "ended";
|
|
877
|
+
else if (!this.recording) return "paused";
|
|
878
|
+
else return "recording";
|
|
879
879
|
}
|
|
880
880
|
/**
|
|
881
881
|
* Sends an event to the AudioWorklet
|
|
@@ -886,7 +886,7 @@ class $62bc376044a05513$export$439b217ca659a877 {
|
|
|
886
886
|
* @returns {Promise<{[key: string]: any}>}
|
|
887
887
|
*/ async _event(name, data = {}, _processor = null) {
|
|
888
888
|
_processor = _processor || this.processor;
|
|
889
|
-
if (!_processor) throw new Error(
|
|
889
|
+
if (!_processor) throw new Error("Can not send events without recording first");
|
|
890
890
|
const message = {
|
|
891
891
|
event: name,
|
|
892
892
|
id: this._lastEventId++,
|
|
@@ -908,7 +908,7 @@ class $62bc376044a05513$export$439b217ca659a877 {
|
|
|
908
908
|
* @returns {true}
|
|
909
909
|
*/ listenForDeviceChange(callback) {
|
|
910
910
|
if (callback === null && this._deviceChangeCallback) {
|
|
911
|
-
navigator.mediaDevices.removeEventListener(
|
|
911
|
+
navigator.mediaDevices.removeEventListener("devicechange", this._deviceChangeCallback);
|
|
912
912
|
this._deviceChangeCallback = null;
|
|
913
913
|
} else if (callback !== null) {
|
|
914
914
|
// Basically a debounce; we only want this called once when devices change
|
|
@@ -916,7 +916,7 @@ class $62bc376044a05513$export$439b217ca659a877 {
|
|
|
916
916
|
// if a few are operating at the same time
|
|
917
917
|
let lastId = 0;
|
|
918
918
|
let lastDevices = [];
|
|
919
|
-
const serializeDevices = (devices)=>devices.map((d)=>d.deviceId).sort().join(
|
|
919
|
+
const serializeDevices = (devices)=>devices.map((d)=>d.deviceId).sort().join(",");
|
|
920
920
|
const cb = async ()=>{
|
|
921
921
|
let id = ++lastId;
|
|
922
922
|
const devices = await this.listDevices();
|
|
@@ -927,7 +927,7 @@ class $62bc376044a05513$export$439b217ca659a877 {
|
|
|
927
927
|
}
|
|
928
928
|
}
|
|
929
929
|
};
|
|
930
|
-
navigator.mediaDevices.addEventListener(
|
|
930
|
+
navigator.mediaDevices.addEventListener("devicechange", cb);
|
|
931
931
|
cb();
|
|
932
932
|
this._deviceChangeCallback = cb;
|
|
933
933
|
}
|
|
@@ -945,9 +945,9 @@ class $62bc376044a05513$export$439b217ca659a877 {
|
|
|
945
945
|
* @returns {Promise<true>}
|
|
946
946
|
*/ async requestPermission() {
|
|
947
947
|
const permissionStatus = await navigator.permissions.query({
|
|
948
|
-
name:
|
|
948
|
+
name: "microphone"
|
|
949
949
|
});
|
|
950
|
-
if (permissionStatus.state ===
|
|
950
|
+
if (permissionStatus.state === "denied") {
|
|
951
951
|
if (this._deviceErrorCallback) this._deviceErrorCallback({
|
|
952
952
|
devices: [
|
|
953
953
|
"mic"
|
|
@@ -955,7 +955,7 @@ class $62bc376044a05513$export$439b217ca659a877 {
|
|
|
955
955
|
type: "unknown",
|
|
956
956
|
error: new Error("Microphone access denied")
|
|
957
957
|
});
|
|
958
|
-
} else if (permissionStatus.state ===
|
|
958
|
+
} else if (permissionStatus.state === "prompt") try {
|
|
959
959
|
const stream = await navigator.mediaDevices.getUserMedia({
|
|
960
960
|
audio: true
|
|
961
961
|
});
|
|
@@ -977,10 +977,10 @@ class $62bc376044a05513$export$439b217ca659a877 {
|
|
|
977
977
|
* List all eligible devices for recording, will request permission to use microphone
|
|
978
978
|
* @returns {Promise<Array<MediaDeviceInfo & {default: boolean}>>}
|
|
979
979
|
*/ async listDevices() {
|
|
980
|
-
if (!navigator.mediaDevices || !(
|
|
980
|
+
if (!navigator.mediaDevices || !("enumerateDevices" in navigator.mediaDevices)) throw new Error("Could not request user devices");
|
|
981
981
|
await this.requestPermission();
|
|
982
982
|
const devices = await navigator.mediaDevices.enumerateDevices();
|
|
983
|
-
const audioDevices = devices.filter((device)=>device.kind ===
|
|
983
|
+
const audioDevices = devices.filter((device)=>device.kind === "audioinput");
|
|
984
984
|
return audioDevices;
|
|
985
985
|
// const defaultDeviceIndex = audioDevices.findIndex(
|
|
986
986
|
// (device) => device.deviceId === 'default'
|
|
@@ -1006,7 +1006,7 @@ class $62bc376044a05513$export$439b217ca659a877 {
|
|
|
1006
1006
|
* @returns {Promise<true>}
|
|
1007
1007
|
*/ async begin(deviceId) {
|
|
1008
1008
|
if (this.processor) throw new Error(`Already connected: please call .end() to start a new session`);
|
|
1009
|
-
if (!navigator.mediaDevices || !(
|
|
1009
|
+
if (!navigator.mediaDevices || !("getUserMedia" in navigator.mediaDevices)) {
|
|
1010
1010
|
if (this._deviceErrorCallback) this._deviceErrorCallback({
|
|
1011
1011
|
devices: [
|
|
1012
1012
|
"mic",
|
|
@@ -1014,7 +1014,7 @@ class $62bc376044a05513$export$439b217ca659a877 {
|
|
|
1014
1014
|
],
|
|
1015
1015
|
type: "undefined-mediadevices"
|
|
1016
1016
|
});
|
|
1017
|
-
throw new Error(
|
|
1017
|
+
throw new Error("Could not request user media");
|
|
1018
1018
|
}
|
|
1019
1019
|
deviceId = deviceId ?? this.deviceSelection?.deviceId;
|
|
1020
1020
|
try {
|
|
@@ -1035,13 +1035,13 @@ class $62bc376044a05513$export$439b217ca659a877 {
|
|
|
1035
1035
|
type: "unknown",
|
|
1036
1036
|
error: err
|
|
1037
1037
|
});
|
|
1038
|
-
throw new Error(
|
|
1038
|
+
throw new Error("Could not start media stream");
|
|
1039
1039
|
}
|
|
1040
1040
|
this.listDevices().then((devices)=>{
|
|
1041
1041
|
deviceId = this.stream.getAudioTracks()[0].getSettings().deviceId;
|
|
1042
|
-
console.log(
|
|
1042
|
+
console.log("find current device", devices, deviceId, this.stream.getAudioTracks()[0].getSettings());
|
|
1043
1043
|
this.deviceSelection = devices.find((d)=>d.deviceId === deviceId);
|
|
1044
|
-
console.log(
|
|
1044
|
+
console.log("current device", this.deviceSelection);
|
|
1045
1045
|
});
|
|
1046
1046
|
const context = new AudioContext({
|
|
1047
1047
|
sampleRate: this.sampleRate
|
|
@@ -1054,11 +1054,11 @@ class $62bc376044a05513$export$439b217ca659a877 {
|
|
|
1054
1054
|
console.error(e);
|
|
1055
1055
|
throw new Error(`Could not add audioWorklet module: ${this.scriptSrc}`);
|
|
1056
1056
|
}
|
|
1057
|
-
const processor = new AudioWorkletNode(context,
|
|
1057
|
+
const processor = new AudioWorkletNode(context, "audio_processor");
|
|
1058
1058
|
processor.port.onmessage = (e)=>{
|
|
1059
1059
|
const { event: event, id: id, data: data } = e.data;
|
|
1060
|
-
if (event ===
|
|
1061
|
-
else if (event ===
|
|
1060
|
+
if (event === "receipt") this.eventReceipts[id] = data;
|
|
1061
|
+
else if (event === "chunk") {
|
|
1062
1062
|
if (this._chunkProcessorSize) {
|
|
1063
1063
|
const buffer = this._chunkProcessorBuffer;
|
|
1064
1064
|
this._chunkProcessorBuffer = {
|
|
@@ -1089,7 +1089,7 @@ class $62bc376044a05513$export$439b217ca659a877 {
|
|
|
1089
1089
|
this.node = node;
|
|
1090
1090
|
this.analyser = analyser;
|
|
1091
1091
|
this.processor = processor;
|
|
1092
|
-
console.log(
|
|
1092
|
+
console.log("begin completed");
|
|
1093
1093
|
return true;
|
|
1094
1094
|
}
|
|
1095
1095
|
/**
|
|
@@ -1098,8 +1098,8 @@ class $62bc376044a05513$export$439b217ca659a877 {
|
|
|
1098
1098
|
* @param {number} [minDecibels] default -100
|
|
1099
1099
|
* @param {number} [maxDecibels] default -30
|
|
1100
1100
|
* @returns {import('./analysis/audio_analysis.js').AudioAnalysisOutputType}
|
|
1101
|
-
*/ getFrequencies(analysisType =
|
|
1102
|
-
if (!this.processor) throw new Error(
|
|
1101
|
+
*/ getFrequencies(analysisType = "frequency", minDecibels = -100, maxDecibels = -30) {
|
|
1102
|
+
if (!this.processor) throw new Error("Session ended: please call .begin() first");
|
|
1103
1103
|
return (0, $f32f064564ee62f6$export$2c3136da0bf130f9).getFrequencies(this.analyser, this.sampleRate, null, analysisType, minDecibels, maxDecibels);
|
|
1104
1104
|
}
|
|
1105
1105
|
/**
|
|
@@ -1107,11 +1107,11 @@ class $62bc376044a05513$export$439b217ca659a877 {
|
|
|
1107
1107
|
* Keeps microphone stream open but halts storage of audio
|
|
1108
1108
|
* @returns {Promise<true>}
|
|
1109
1109
|
*/ async pause() {
|
|
1110
|
-
if (!this.processor) throw new Error(
|
|
1111
|
-
else if (!this.recording) throw new Error(
|
|
1110
|
+
if (!this.processor) throw new Error("Session ended: please call .begin() first");
|
|
1111
|
+
else if (!this.recording) throw new Error("Already paused: please call .record() first");
|
|
1112
1112
|
if (this._chunkProcessorBuffer.raw.byteLength) this._chunkProcessor(this._chunkProcessorBuffer);
|
|
1113
|
-
this.log(
|
|
1114
|
-
await this._event(
|
|
1113
|
+
this.log("Pausing ...");
|
|
1114
|
+
await this._event("stop");
|
|
1115
1115
|
this.recording = false;
|
|
1116
1116
|
return true;
|
|
1117
1117
|
}
|
|
@@ -1121,17 +1121,17 @@ class $62bc376044a05513$export$439b217ca659a877 {
|
|
|
1121
1121
|
* @param {number} [chunkSize] chunkProcessor will not be triggered until this size threshold met in mono audio
|
|
1122
1122
|
* @returns {Promise<true>}
|
|
1123
1123
|
*/ async record(chunkProcessor = ()=>{}, chunkSize = 8192) {
|
|
1124
|
-
if (!this.processor) throw new Error(
|
|
1125
|
-
else if (this.recording) throw new Error(
|
|
1126
|
-
else if (typeof chunkProcessor !==
|
|
1124
|
+
if (!this.processor) throw new Error("Session ended: please call .begin() first");
|
|
1125
|
+
else if (this.recording) throw new Error("Already recording: please call .pause() first");
|
|
1126
|
+
else if (typeof chunkProcessor !== "function") throw new Error(`chunkProcessor must be a function`);
|
|
1127
1127
|
this._chunkProcessor = chunkProcessor;
|
|
1128
1128
|
this._chunkProcessorSize = chunkSize;
|
|
1129
1129
|
this._chunkProcessorBuffer = {
|
|
1130
1130
|
raw: new ArrayBuffer(0),
|
|
1131
1131
|
mono: new ArrayBuffer(0)
|
|
1132
1132
|
};
|
|
1133
|
-
this.log(
|
|
1134
|
-
await this._event(
|
|
1133
|
+
this.log("Recording ...");
|
|
1134
|
+
await this._event("start");
|
|
1135
1135
|
this.recording = true;
|
|
1136
1136
|
return true;
|
|
1137
1137
|
}
|
|
@@ -1139,17 +1139,17 @@ class $62bc376044a05513$export$439b217ca659a877 {
|
|
|
1139
1139
|
* Clears the audio buffer, empties stored recording
|
|
1140
1140
|
* @returns {Promise<true>}
|
|
1141
1141
|
*/ async clear() {
|
|
1142
|
-
if (!this.processor) throw new Error(
|
|
1143
|
-
await this._event(
|
|
1142
|
+
if (!this.processor) throw new Error("Session ended: please call .begin() first");
|
|
1143
|
+
await this._event("clear");
|
|
1144
1144
|
return true;
|
|
1145
1145
|
}
|
|
1146
1146
|
/**
|
|
1147
1147
|
* Reads the current audio stream data
|
|
1148
1148
|
* @returns {Promise<{meanValues: Float32Array, channels: Array<Float32Array>}>}
|
|
1149
1149
|
*/ async read() {
|
|
1150
|
-
if (!this.processor) throw new Error(
|
|
1151
|
-
this.log(
|
|
1152
|
-
const result = await this._event(
|
|
1150
|
+
if (!this.processor) throw new Error("Session ended: please call .begin() first");
|
|
1151
|
+
this.log("Reading ...");
|
|
1152
|
+
const result = await this._event("read");
|
|
1153
1153
|
return result;
|
|
1154
1154
|
}
|
|
1155
1155
|
/**
|
|
@@ -1157,10 +1157,10 @@ class $62bc376044a05513$export$439b217ca659a877 {
|
|
|
1157
1157
|
* @param {boolean} [force] Force saving while still recording
|
|
1158
1158
|
* @returns {Promise<import('./wav_packer.js').WavPackerAudioType>}
|
|
1159
1159
|
*/ async save(force = false) {
|
|
1160
|
-
if (!this.processor) throw new Error(
|
|
1161
|
-
if (!force && this.recording) throw new Error(
|
|
1162
|
-
this.log(
|
|
1163
|
-
const exportData = await this._event(
|
|
1160
|
+
if (!this.processor) throw new Error("Session ended: please call .begin() first");
|
|
1161
|
+
if (!force && this.recording) throw new Error("Currently recording: please call .pause() first, or call .save(true) to force");
|
|
1162
|
+
this.log("Exporting ...");
|
|
1163
|
+
const exportData = await this._event("export");
|
|
1164
1164
|
const packer = new (0, $6d4b7449a1e1544a$export$13afda237b1c9846)();
|
|
1165
1165
|
const result = packer.pack(this.sampleRate, exportData.audio);
|
|
1166
1166
|
return result;
|
|
@@ -1169,15 +1169,15 @@ class $62bc376044a05513$export$439b217ca659a877 {
|
|
|
1169
1169
|
* Ends the current recording session and saves the result
|
|
1170
1170
|
* @returns {Promise<import('./wav_packer.js').WavPackerAudioType>}
|
|
1171
1171
|
*/ async end() {
|
|
1172
|
-
if (!this.processor) throw new Error(
|
|
1172
|
+
if (!this.processor) throw new Error("Session ended: please call .begin() first");
|
|
1173
1173
|
const _processor = this.processor;
|
|
1174
|
-
this.log(
|
|
1175
|
-
await this._event(
|
|
1174
|
+
this.log("Stopping ...");
|
|
1175
|
+
await this._event("stop");
|
|
1176
1176
|
this.recording = false;
|
|
1177
1177
|
const tracks = this.stream.getTracks();
|
|
1178
1178
|
tracks.forEach((track)=>track.stop());
|
|
1179
|
-
this.log(
|
|
1180
|
-
const exportData = await this._event(
|
|
1179
|
+
this.log("Exporting ...");
|
|
1180
|
+
const exportData = await this._event("export", {}, _processor);
|
|
1181
1181
|
this.processor.disconnect();
|
|
1182
1182
|
this.source.disconnect();
|
|
1183
1183
|
this.node.disconnect();
|
|
@@ -1208,6 +1208,29 @@ globalThis.WavRecorder = $62bc376044a05513$export$439b217ca659a877;
|
|
|
1208
1208
|
|
|
1209
1209
|
|
|
1210
1210
|
|
|
1211
|
+
/**
|
|
1212
|
+
* Resamples audio data from one sample rate to another using linear interpolation
|
|
1213
|
+
* @param {ArrayBuffer} inputBuffer - Input audio data as Int16 PCM
|
|
1214
|
+
* @param {number} inputSampleRate - Sample rate of input audio
|
|
1215
|
+
* @param {number} outputSampleRate - Desired output sample rate
|
|
1216
|
+
* @returns {ArrayBuffer} - Resampled audio data as Int16 PCM
|
|
1217
|
+
*/ function $5fc11d7bc0d20724$var$resampleAudioBuffer(inputBuffer, inputSampleRate, outputSampleRate) {
|
|
1218
|
+
if (inputSampleRate === outputSampleRate) return inputBuffer;
|
|
1219
|
+
const inputView = new Int16Array(inputBuffer);
|
|
1220
|
+
const ratio = inputSampleRate / outputSampleRate;
|
|
1221
|
+
const outputLength = Math.round(inputView.length / ratio);
|
|
1222
|
+
const outputBuffer = new ArrayBuffer(outputLength * 2);
|
|
1223
|
+
const outputView = new Int16Array(outputBuffer);
|
|
1224
|
+
for(let i = 0; i < outputLength; i++){
|
|
1225
|
+
const srcIndex = i * ratio;
|
|
1226
|
+
const srcIndexFloor = Math.floor(srcIndex);
|
|
1227
|
+
const srcIndexCeil = Math.min(srcIndexFloor + 1, inputView.length - 1);
|
|
1228
|
+
const t = srcIndex - srcIndexFloor;
|
|
1229
|
+
// Linear interpolation
|
|
1230
|
+
outputView[i] = Math.round(inputView[srcIndexFloor] * (1 - t) + inputView[srcIndexCeil] * t);
|
|
1231
|
+
}
|
|
1232
|
+
return outputBuffer;
|
|
1233
|
+
}
|
|
1211
1234
|
class $5fc11d7bc0d20724$export$2934cf2d25c67a48 {
|
|
1212
1235
|
/**
|
|
1213
1236
|
* Create a new MediaStreamRecorder instance
|
|
@@ -1296,9 +1319,21 @@ class $5fc11d7bc0d20724$export$2934cf2d25c67a48 {
|
|
|
1296
1319
|
this.stream = new MediaStream([
|
|
1297
1320
|
audioTrack
|
|
1298
1321
|
]);
|
|
1299
|
-
|
|
1322
|
+
// Firefox workaround: Firefox doesn't support connecting AudioNodes from
|
|
1323
|
+
// AudioContexts with different sample rates. So we create the AudioContext
|
|
1324
|
+
// at the native sample rate and resample manually.
|
|
1325
|
+
// This workaround may be temporary; Firefox is in the process of adding
|
|
1326
|
+
// support for this.
|
|
1327
|
+
// See: https://bugzilla.mozilla.org/show_bug.cgi?id=1674892
|
|
1328
|
+
const isFirefox = navigator.userAgent.toLowerCase().includes("firefox");
|
|
1329
|
+
let context;
|
|
1330
|
+
if (isFirefox) // Firefox: Use native sample rate and resample manually
|
|
1331
|
+
context = new AudioContext();
|
|
1332
|
+
else // Other browsers: Let the AudioContext handle resampling
|
|
1333
|
+
context = new AudioContext({
|
|
1300
1334
|
sampleRate: this.sampleRate
|
|
1301
1335
|
});
|
|
1336
|
+
const contextSampleRate = context.sampleRate;
|
|
1302
1337
|
const source = context.createMediaStreamSource(this.stream);
|
|
1303
1338
|
// Load and execute the module script.
|
|
1304
1339
|
try {
|
|
@@ -1312,11 +1347,17 @@ class $5fc11d7bc0d20724$export$2934cf2d25c67a48 {
|
|
|
1312
1347
|
const { event: event, id: id, data: data } = e.data;
|
|
1313
1348
|
if (event === "receipt") this.eventReceipts[id] = data;
|
|
1314
1349
|
else if (event === "chunk") {
|
|
1350
|
+
// Resample chunk data from native sample rate to target sample rate
|
|
1351
|
+
// (no-op if rates match, i.e. for non-Firefox browsers)
|
|
1352
|
+
const resampledData = {
|
|
1353
|
+
raw: $5fc11d7bc0d20724$var$resampleAudioBuffer(data.raw, contextSampleRate, this.sampleRate),
|
|
1354
|
+
mono: $5fc11d7bc0d20724$var$resampleAudioBuffer(data.mono, contextSampleRate, this.sampleRate)
|
|
1355
|
+
};
|
|
1315
1356
|
if (this._chunkProcessorSize) {
|
|
1316
1357
|
const buffer = this._chunkProcessorBuffer;
|
|
1317
1358
|
this._chunkProcessorBuffer = {
|
|
1318
|
-
raw: (0, $6d4b7449a1e1544a$export$13afda237b1c9846).mergeBuffers(buffer.raw,
|
|
1319
|
-
mono: (0, $6d4b7449a1e1544a$export$13afda237b1c9846).mergeBuffers(buffer.mono,
|
|
1359
|
+
raw: (0, $6d4b7449a1e1544a$export$13afda237b1c9846).mergeBuffers(buffer.raw, resampledData.raw),
|
|
1360
|
+
mono: (0, $6d4b7449a1e1544a$export$13afda237b1c9846).mergeBuffers(buffer.mono, resampledData.mono)
|
|
1320
1361
|
};
|
|
1321
1362
|
if (this._chunkProcessorBuffer.mono.byteLength >= this._chunkProcessorSize) {
|
|
1322
1363
|
this._chunkProcessor(this._chunkProcessorBuffer);
|
|
@@ -1325,7 +1366,7 @@ class $5fc11d7bc0d20724$export$2934cf2d25c67a48 {
|
|
|
1325
1366
|
mono: new ArrayBuffer(0)
|
|
1326
1367
|
};
|
|
1327
1368
|
}
|
|
1328
|
-
} else this._chunkProcessor(
|
|
1369
|
+
} else this._chunkProcessor(resampledData);
|
|
1329
1370
|
}
|
|
1330
1371
|
};
|
|
1331
1372
|
const node = source.connect(processor);
|
|
@@ -2457,26 +2498,64 @@ var $22ece045290c996a$export$c95c65abc5f47125 = /** @class */ function(_super) {
|
|
|
2457
2498
|
};
|
|
2458
2499
|
DailyMediaManager.prototype.updateSpeaker = function(speakerId) {
|
|
2459
2500
|
return $22ece045290c996a$var$__awaiter(this, void 0, Promise, function() {
|
|
2460
|
-
var sID, speakers, defaultSpeaker_1, defaultSpeakerCp;
|
|
2501
|
+
var dInfo, e_1, sID, speakers, defaultSpeaker_1, defaultSpeakerCp;
|
|
2461
2502
|
var _this = this;
|
|
2462
|
-
var _a, _b;
|
|
2463
|
-
return $22ece045290c996a$var$__generator(this, function(
|
|
2464
|
-
switch(
|
|
2503
|
+
var _a, _b, _c, _d;
|
|
2504
|
+
return $22ece045290c996a$var$__generator(this, function(_e) {
|
|
2505
|
+
switch(_e.label){
|
|
2465
2506
|
case 0:
|
|
2507
|
+
if (!!this._wavStreamPlayer) return [
|
|
2508
|
+
3 /*break*/ ,
|
|
2509
|
+
5
|
|
2510
|
+
];
|
|
2511
|
+
_e.label = 1;
|
|
2512
|
+
case 1:
|
|
2513
|
+
_e.trys.push([
|
|
2514
|
+
1,
|
|
2515
|
+
3,
|
|
2516
|
+
,
|
|
2517
|
+
4
|
|
2518
|
+
]);
|
|
2519
|
+
return [
|
|
2520
|
+
4 /*yield*/ ,
|
|
2521
|
+
this._daily.setOutputDeviceAsync({
|
|
2522
|
+
outputDeviceId: speakerId
|
|
2523
|
+
})
|
|
2524
|
+
];
|
|
2525
|
+
case 2:
|
|
2526
|
+
dInfo = _e.sent();
|
|
2527
|
+
this._selectedSpeaker = dInfo.speaker;
|
|
2528
|
+
(_b = (_a = this._callbacks).onSpeakerUpdated) === null || _b === void 0 || _b.call(_a, this._selectedSpeaker);
|
|
2529
|
+
return [
|
|
2530
|
+
3 /*break*/ ,
|
|
2531
|
+
4
|
|
2532
|
+
];
|
|
2533
|
+
case 3:
|
|
2534
|
+
e_1 = _e.sent();
|
|
2535
|
+
console.error("Error setting output device", e_1);
|
|
2536
|
+
return [
|
|
2537
|
+
3 /*break*/ ,
|
|
2538
|
+
4
|
|
2539
|
+
];
|
|
2540
|
+
case 4:
|
|
2541
|
+
return [
|
|
2542
|
+
2 /*return*/
|
|
2543
|
+
];
|
|
2544
|
+
case 5:
|
|
2466
2545
|
if (speakerId !== "default" && this._selectedSpeaker.deviceId === speakerId) return [
|
|
2467
2546
|
2 /*return*/
|
|
2468
2547
|
];
|
|
2469
2548
|
sID = speakerId;
|
|
2470
2549
|
if (!(sID === "default")) return [
|
|
2471
2550
|
3 /*break*/ ,
|
|
2472
|
-
|
|
2551
|
+
7
|
|
2473
2552
|
];
|
|
2474
2553
|
return [
|
|
2475
2554
|
4 /*yield*/ ,
|
|
2476
2555
|
this.getAllSpeakers()
|
|
2477
2556
|
];
|
|
2478
|
-
case
|
|
2479
|
-
speakers =
|
|
2557
|
+
case 6:
|
|
2558
|
+
speakers = _e.sent();
|
|
2480
2559
|
defaultSpeaker_1 = speakers.find(function(s) {
|
|
2481
2560
|
return s.deviceId === "default";
|
|
2482
2561
|
});
|
|
@@ -2490,10 +2569,10 @@ var $22ece045290c996a$export$c95c65abc5f47125 = /** @class */ function(_super) {
|
|
|
2490
2569
|
defaultSpeakerCp = speakers.find(function(s) {
|
|
2491
2570
|
return defaultSpeaker_1.label.includes(s.label);
|
|
2492
2571
|
});
|
|
2493
|
-
sID = (
|
|
2494
|
-
|
|
2495
|
-
case
|
|
2496
|
-
(
|
|
2572
|
+
sID = (_c = defaultSpeakerCp === null || defaultSpeakerCp === void 0 ? void 0 : defaultSpeakerCp.deviceId) !== null && _c !== void 0 ? _c : speakerId;
|
|
2573
|
+
_e.label = 7;
|
|
2574
|
+
case 7:
|
|
2575
|
+
(_d = this._wavStreamPlayer) === null || _d === void 0 || _d.updateSpeaker(sID).then(function() {
|
|
2497
2576
|
var _a, _b;
|
|
2498
2577
|
_this._selectedSpeaker = {
|
|
2499
2578
|
deviceId: speakerId
|
|
@@ -2680,7 +2759,7 @@ var $22ece045290c996a$export$c95c65abc5f47125 = /** @class */ function(_super) {
|
|
|
2680
2759
|
};
|
|
2681
2760
|
DailyMediaManager.prototype.handleTrackStarted = function(event) {
|
|
2682
2761
|
return $22ece045290c996a$var$__awaiter(this, void 0, void 0, function() {
|
|
2683
|
-
var status, _a,
|
|
2762
|
+
var status, _a, e_2, e_3;
|
|
2684
2763
|
var _b, _c, _d, _e;
|
|
2685
2764
|
return $22ece045290c996a$var$__generator(this, function(_f) {
|
|
2686
2765
|
switch(_f.label){
|
|
@@ -2744,7 +2823,7 @@ var $22ece045290c996a$export$c95c65abc5f47125 = /** @class */ function(_super) {
|
|
|
2744
2823
|
4
|
|
2745
2824
|
];
|
|
2746
2825
|
case 3:
|
|
2747
|
-
|
|
2826
|
+
e_2 = _f.sent();
|
|
2748
2827
|
return [
|
|
2749
2828
|
3 /*break*/ ,
|
|
2750
2829
|
4
|
|
@@ -2791,7 +2870,7 @@ var $22ece045290c996a$export$c95c65abc5f47125 = /** @class */ function(_super) {
|
|
|
2791
2870
|
11
|
|
2792
2871
|
];
|
|
2793
2872
|
case 10:
|
|
2794
|
-
|
|
2873
|
+
e_3 = _f.sent();
|
|
2795
2874
|
return [
|
|
2796
2875
|
3 /*break*/ ,
|
|
2797
2876
|
11
|
|
@@ -4083,6 +4162,7 @@ class $7f42eda74f1b1632$export$de21836fc42c6f9c extends (0, $kR6tG$Transport) {
|
|
|
4083
4162
|
this._mediaManager.setUserAudioCallback(this.handleUserAudioStream.bind(this));
|
|
4084
4163
|
this._ws = null;
|
|
4085
4164
|
this._serializer = opts.serializer || new (0, $a6c080dc51c9687f$export$4b2026f8e11b148a)();
|
|
4165
|
+
this._maxMessageSize = 1048576; // python websockets default to 1MB
|
|
4086
4166
|
}
|
|
4087
4167
|
initialize(options, messageHandler) {
|
|
4088
4168
|
this._options = options;
|