@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.
@@ -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
- 'RIFF',
78
+ "RIFF",
79
79
  this._packData(1, 52),
80
- 'WAVE',
80
+ "WAVE",
81
81
  // chunk 1
82
- 'fmt ',
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
- 'data',
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: 'audio/mpeg'
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
- 'C',
134
- 'C#',
135
- 'D',
136
- 'D#',
137
- 'E',
138
- 'F',
139
- 'F#',
140
- 'G',
141
- 'G#',
142
- 'A',
143
- 'A#',
144
- 'B'
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 = 'frequency', minDecibels = -100, maxDecibels = -30) {
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 === 'music' || analysisType === 'voice') {
190
- const useFrequencies = analysisType === 'voice' ? (0, $03f71ce85e00ada6$export$dbc1581ed2cfa183) : (0, $03f71ce85e00ada6$export$776c63898ae5b636);
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 === 'voice' ? (0, $03f71ce85e00ada6$export$dbc1581ed2cfa183) : (0, $03f71ce85e00ada6$export$776c63898ae5b636);
202
- labels = analysisType === 'voice' ? (0, $03f71ce85e00ada6$export$30a6f2881311088f) : (0, $03f71ce85e00ada6$export$facd167cc27ea9b0);
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 = 'frequency', minDecibels = -100, maxDecibels = -30) {
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 === 'suspended') await this.context.resume();
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: 'application/javascript'
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: 'application/javascript'
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: 'audio/wav'
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 'ended';
877
- else if (!this.recording) return 'paused';
878
- else return 'recording';
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('Can not send events without recording first');
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('devicechange', this._deviceChangeCallback);
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('devicechange', cb);
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: 'microphone'
948
+ name: "microphone"
949
949
  });
950
- if (permissionStatus.state === 'denied') {
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 === 'prompt') try {
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 || !('enumerateDevices' in navigator.mediaDevices)) throw new Error('Could not request user devices');
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 === 'audioinput');
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 || !('getUserMedia' in 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('Could not request user media');
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('Could not start media stream');
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('find current device', devices, deviceId, this.stream.getAudioTracks()[0].getSettings());
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('current device', this.deviceSelection);
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, 'audio_processor');
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 === 'receipt') this.eventReceipts[id] = data;
1061
- else if (event === 'chunk') {
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('begin completed');
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 = 'frequency', minDecibels = -100, maxDecibels = -30) {
1102
- if (!this.processor) throw new Error('Session ended: please call .begin() first');
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('Session ended: please call .begin() first');
1111
- else if (!this.recording) throw new Error('Already paused: please call .record() first');
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('Pausing ...');
1114
- await this._event('stop');
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('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`);
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('Recording ...');
1134
- await this._event('start');
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('Session ended: please call .begin() first');
1143
- await this._event('clear');
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('Session ended: please call .begin() first');
1151
- this.log('Reading ...');
1152
- const result = await this._event('read');
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('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');
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('Session ended: please call .begin() first');
1172
+ if (!this.processor) throw new Error("Session ended: please call .begin() first");
1173
1173
  const _processor = this.processor;
1174
- this.log('Stopping ...');
1175
- await this._event('stop');
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('Exporting ...');
1180
- const exportData = await this._event('export', {}, _processor);
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
- const context = new AudioContext({
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, data.raw),
1319
- mono: (0, $6d4b7449a1e1544a$export$13afda237b1c9846).mergeBuffers(buffer.mono, data.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(data);
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(_c) {
2464
- switch(_c.label){
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
- 2
2551
+ 7
2473
2552
  ];
2474
2553
  return [
2475
2554
  4 /*yield*/ ,
2476
2555
  this.getAllSpeakers()
2477
2556
  ];
2478
- case 1:
2479
- speakers = _c.sent();
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 = (_a = defaultSpeakerCp === null || defaultSpeakerCp === void 0 ? void 0 : defaultSpeakerCp.deviceId) !== null && _a !== void 0 ? _a : speakerId;
2494
- _c.label = 2;
2495
- case 2:
2496
- (_b = this._wavStreamPlayer) === null || _b === void 0 || _b.updateSpeaker(sID).then(function() {
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, e_1, e_2;
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
- e_1 = _f.sent();
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
- e_2 = _f.sent();
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;