@pipecat-ai/daily-transport 1.6.8 → 1.7.0

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 CHANGED
@@ -1,5 +1,6 @@
1
- var $jrPAn$dailycodailyjs = require("@daily-co/daily-js");
2
- var $jrPAn$pipecataiclientjs = require("@pipecat-ai/client-js");
1
+ var $1clrS$dailycodailyjs = require("@daily-co/daily-js");
2
+ var $1clrS$pipecataiclientjs = require("@pipecat-ai/client-js");
3
+ var $1clrS$events = require("events");
3
4
 
4
5
 
5
6
  function $parcel$exportWildcard(dest, source) {
@@ -26,13 +27,49 @@ function $parcel$interopDefault(a) {
26
27
  function $parcel$export(e, n, v, s) {
27
28
  Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});
28
29
  }
29
- var $28bdeb35415d61e8$exports = {};
30
+ var $1c83796b12dd4e49$exports = {};
30
31
 
31
- $parcel$export($28bdeb35415d61e8$exports, "DailyRTVIMessageType", () => $28bdeb35415d61e8$export$ef180de88fd317cc);
32
- $parcel$export($28bdeb35415d61e8$exports, "DailyTransport", () => $28bdeb35415d61e8$export$b1ca982aa1e488c1);
32
+ $parcel$export($1c83796b12dd4e49$exports, "DailyRTVIMessageType", () => $1c83796b12dd4e49$export$ef180de88fd317cc);
33
+ $parcel$export($1c83796b12dd4e49$exports, "DailyTransport", () => $1c83796b12dd4e49$export$b1ca982aa1e488c1);
33
34
 
34
35
 
35
36
  /**
37
+ * Whether this browser can share a screen. Most mobile browsers, including
38
+ * iOS Safari, have no `getDisplayMedia`.
39
+ */ function $15398512372f76d1$export$7f8f33b9b54c8307() {
40
+ return typeof navigator?.mediaDevices?.getDisplayMedia === "function";
41
+ }
42
+
43
+
44
+ /*!
45
+ * wavtools is adapted from openai-realtime-console
46
+ * (https://github.com/openai/openai-realtime-console) and modified by Daily.
47
+ *
48
+ * @license MIT
49
+ *
50
+ * Copyright (c) 2024 OpenAI
51
+ *
52
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
53
+ * of this software and associated documentation files (the "Software"), to deal
54
+ * in the Software without restriction, including without limitation the rights
55
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
56
+ * copies of the Software, and to permit persons to whom the Software is
57
+ * furnished to do so, subject to the following conditions:
58
+ *
59
+ * The above copyright notice and this permission notice shall be included in all
60
+ * copies or substantial portions of the Software.
61
+ *
62
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
63
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
64
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
65
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
66
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
67
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
68
+ * SOFTWARE.
69
+ */ /*!
70
+ * Adapted from openai-realtime-console (https://github.com/openai/openai-realtime-console).
71
+ * Copyright (c) 2024 OpenAI. Modified by Daily. MIT License; see wavtools/index.js.
72
+ */ /**
36
73
  * Raw wav audio file contents
37
74
  * @typedef {Object} WavPackerAudioType
38
75
  * @property {Blob} blob
@@ -43,7 +80,7 @@ $parcel$export($28bdeb35415d61e8$exports, "DailyTransport", () => $28bdeb35415d6
43
80
  */ /**
44
81
  * Utility class for assembling PCM16 "audio/wav" data
45
82
  * @class
46
- */ class $a61750b8fbee4dae$export$13afda237b1c9846 {
83
+ */ class $45766326c6faa3c4$export$13afda237b1c9846 {
47
84
  /**
48
85
  * Converts Float32Array of amplitude data to ArrayBuffer in Int16Array format
49
86
  * @param {Float32Array} float32Array
@@ -131,16 +168,22 @@ $parcel$export($28bdeb35415d61e8$exports, "DailyTransport", () => $28bdeb35415d6
131
168
  };
132
169
  }
133
170
  }
134
- globalThis.WavPacker = $a61750b8fbee4dae$export$13afda237b1c9846;
171
+ globalThis.WavPacker = $45766326c6faa3c4$export$13afda237b1c9846;
135
172
 
136
173
 
137
- /**
174
+ /*!
175
+ * Adapted from openai-realtime-console (https://github.com/openai/openai-realtime-console).
176
+ * Copyright (c) 2024 OpenAI. Modified by Daily. MIT License; see wavtools/index.js.
177
+ */ /*!
178
+ * Adapted from openai-realtime-console (https://github.com/openai/openai-realtime-console).
179
+ * Copyright (c) 2024 OpenAI. Modified by Daily. MIT License; see wavtools/index.js.
180
+ */ /**
138
181
  * Constants for help with visualization
139
182
  * Helps map frequency ranges from Fast Fourier Transform
140
183
  * to human-interpretable ranges, notably music ranges and
141
184
  * human vocal ranges.
142
185
  */ // Eighth octave frequencies
143
- const $e10a9de47f58e137$var$octave8Frequencies = [
186
+ const $550c0e438054ce18$var$octave8Frequencies = [
144
187
  4186.01,
145
188
  4434.92,
146
189
  4698.63,
@@ -155,7 +198,7 @@ const $e10a9de47f58e137$var$octave8Frequencies = [
155
198
  7902.13
156
199
  ];
157
200
  // Labels for each of the above frequencies
158
- const $e10a9de47f58e137$var$octave8FrequencyLabels = [
201
+ const $550c0e438054ce18$var$octave8FrequencyLabels = [
159
202
  "C",
160
203
  "C#",
161
204
  "D",
@@ -169,29 +212,29 @@ const $e10a9de47f58e137$var$octave8FrequencyLabels = [
169
212
  "A#",
170
213
  "B"
171
214
  ];
172
- const $e10a9de47f58e137$export$776c63898ae5b636 = [];
173
- const $e10a9de47f58e137$export$facd167cc27ea9b0 = [];
174
- for(let i = 1; i <= 8; i++)for(let f = 0; f < $e10a9de47f58e137$var$octave8Frequencies.length; f++){
175
- const freq = $e10a9de47f58e137$var$octave8Frequencies[f];
176
- $e10a9de47f58e137$export$776c63898ae5b636.push(freq / Math.pow(2, 8 - i));
177
- $e10a9de47f58e137$export$facd167cc27ea9b0.push($e10a9de47f58e137$var$octave8FrequencyLabels[f] + i);
215
+ const $550c0e438054ce18$export$776c63898ae5b636 = [];
216
+ const $550c0e438054ce18$export$facd167cc27ea9b0 = [];
217
+ for(let i = 1; i <= 8; i++)for(let f = 0; f < $550c0e438054ce18$var$octave8Frequencies.length; f++){
218
+ const freq = $550c0e438054ce18$var$octave8Frequencies[f];
219
+ $550c0e438054ce18$export$776c63898ae5b636.push(freq / Math.pow(2, 8 - i));
220
+ $550c0e438054ce18$export$facd167cc27ea9b0.push($550c0e438054ce18$var$octave8FrequencyLabels[f] + i);
178
221
  }
179
222
  /**
180
223
  * Subset of the note frequencies between 32 and 2000 Hz
181
224
  * 6 octave range: C1 to B6
182
- */ const $e10a9de47f58e137$var$voiceFrequencyRange = [
225
+ */ const $550c0e438054ce18$var$voiceFrequencyRange = [
183
226
  32.0,
184
227
  2000.0
185
228
  ];
186
- const $e10a9de47f58e137$export$dbc1581ed2cfa183 = $e10a9de47f58e137$export$776c63898ae5b636.filter((_, i)=>{
187
- return $e10a9de47f58e137$export$776c63898ae5b636[i] > $e10a9de47f58e137$var$voiceFrequencyRange[0] && $e10a9de47f58e137$export$776c63898ae5b636[i] < $e10a9de47f58e137$var$voiceFrequencyRange[1];
229
+ const $550c0e438054ce18$export$dbc1581ed2cfa183 = $550c0e438054ce18$export$776c63898ae5b636.filter((_, i)=>{
230
+ return $550c0e438054ce18$export$776c63898ae5b636[i] > $550c0e438054ce18$var$voiceFrequencyRange[0] && $550c0e438054ce18$export$776c63898ae5b636[i] < $550c0e438054ce18$var$voiceFrequencyRange[1];
188
231
  });
189
- const $e10a9de47f58e137$export$30a6f2881311088f = $e10a9de47f58e137$export$facd167cc27ea9b0.filter((_, i)=>{
190
- return $e10a9de47f58e137$export$776c63898ae5b636[i] > $e10a9de47f58e137$var$voiceFrequencyRange[0] && $e10a9de47f58e137$export$776c63898ae5b636[i] < $e10a9de47f58e137$var$voiceFrequencyRange[1];
232
+ const $550c0e438054ce18$export$30a6f2881311088f = $550c0e438054ce18$export$facd167cc27ea9b0.filter((_, i)=>{
233
+ return $550c0e438054ce18$export$776c63898ae5b636[i] > $550c0e438054ce18$var$voiceFrequencyRange[0] && $550c0e438054ce18$export$776c63898ae5b636[i] < $550c0e438054ce18$var$voiceFrequencyRange[1];
191
234
  });
192
235
 
193
236
 
194
- class $5853841ab58516d4$export$2c3136da0bf130f9 {
237
+ class $3f7a723e434a4b86$export$2c3136da0bf130f9 {
195
238
  /**
196
239
  * Retrieves frequency domain data from an AnalyserNode adjusted to a decibel range
197
240
  * returns human-readable formatting and labels
@@ -213,7 +256,7 @@ class $5853841ab58516d4$export$2c3136da0bf130f9 {
213
256
  let frequencies;
214
257
  let labels;
215
258
  if (analysisType === "music" || analysisType === "voice") {
216
- const useFrequencies = analysisType === "voice" ? (0, $e10a9de47f58e137$export$dbc1581ed2cfa183) : (0, $e10a9de47f58e137$export$776c63898ae5b636);
259
+ const useFrequencies = analysisType === "voice" ? (0, $550c0e438054ce18$export$dbc1581ed2cfa183) : (0, $550c0e438054ce18$export$776c63898ae5b636);
217
260
  const aggregateOutput = Array(useFrequencies.length).fill(minDecibels);
218
261
  for(let i = 0; i < fftResult.length; i++){
219
262
  const frequency = i * frequencyStep;
@@ -224,8 +267,8 @@ class $5853841ab58516d4$export$2c3136da0bf130f9 {
224
267
  }
225
268
  }
226
269
  outputValues = aggregateOutput;
227
- frequencies = analysisType === "voice" ? (0, $e10a9de47f58e137$export$dbc1581ed2cfa183) : (0, $e10a9de47f58e137$export$776c63898ae5b636);
228
- labels = analysisType === "voice" ? (0, $e10a9de47f58e137$export$30a6f2881311088f) : (0, $e10a9de47f58e137$export$facd167cc27ea9b0);
270
+ frequencies = analysisType === "voice" ? (0, $550c0e438054ce18$export$dbc1581ed2cfa183) : (0, $550c0e438054ce18$export$776c63898ae5b636);
271
+ labels = analysisType === "voice" ? (0, $550c0e438054ce18$export$30a6f2881311088f) : (0, $550c0e438054ce18$export$facd167cc27ea9b0);
229
272
  } else {
230
273
  outputValues = Array.from(fftResult);
231
274
  frequencies = outputValues.map((_, i)=>frequencyStep * i);
@@ -318,7 +361,7 @@ class $5853841ab58516d4$export$2c3136da0bf130f9 {
318
361
  const index = Math.min(pct * this.fftResults.length | 0, this.fftResults.length - 1);
319
362
  fftResult = this.fftResults[index];
320
363
  }
321
- return $5853841ab58516d4$export$2c3136da0bf130f9.getFrequencies(this.analyser, this.sampleRate, fftResult, analysisType, minDecibels, maxDecibels);
364
+ return $3f7a723e434a4b86$export$2c3136da0bf130f9.getFrequencies(this.analyser, this.sampleRate, fftResult, analysisType, minDecibels, maxDecibels);
322
365
  }
323
366
  /**
324
367
  * Resume the internal AudioContext if it was suspended due to the lack of
@@ -329,10 +372,16 @@ class $5853841ab58516d4$export$2c3136da0bf130f9 {
329
372
  return true;
330
373
  }
331
374
  }
332
- globalThis.AudioAnalysis = $5853841ab58516d4$export$2c3136da0bf130f9;
375
+ globalThis.AudioAnalysis = $3f7a723e434a4b86$export$2c3136da0bf130f9;
333
376
 
334
377
 
335
- const $d6d3743ef65c7519$export$50b76700e2b15e9 = `
378
+ /*!
379
+ * Adapted from openai-realtime-console (https://github.com/openai/openai-realtime-console).
380
+ * Copyright (c) 2024 OpenAI. Modified by Daily. MIT License; see wavtools/index.js.
381
+ */ /*!
382
+ * Adapted from openai-realtime-console (https://github.com/openai/openai-realtime-console).
383
+ * Copyright (c) 2024 OpenAI. Modified by Daily. MIT License; see wavtools/index.js.
384
+ */ const $ff75ae50979bb4fc$export$50b76700e2b15e9 = `
336
385
  class StreamProcessor extends AudioWorkletProcessor {
337
386
  constructor() {
338
387
  super();
@@ -422,23 +471,23 @@ class StreamProcessor extends AudioWorkletProcessor {
422
471
 
423
472
  registerProcessor('stream_processor', StreamProcessor);
424
473
  `;
425
- const $d6d3743ef65c7519$var$script = new Blob([
426
- $d6d3743ef65c7519$export$50b76700e2b15e9
474
+ const $ff75ae50979bb4fc$var$script = new Blob([
475
+ $ff75ae50979bb4fc$export$50b76700e2b15e9
427
476
  ], {
428
477
  type: "application/javascript"
429
478
  });
430
- const $d6d3743ef65c7519$var$src = URL.createObjectURL($d6d3743ef65c7519$var$script);
431
- const $d6d3743ef65c7519$export$bfa8c596114d74df = $d6d3743ef65c7519$var$src;
479
+ const $ff75ae50979bb4fc$var$src = URL.createObjectURL($ff75ae50979bb4fc$var$script);
480
+ const $ff75ae50979bb4fc$export$bfa8c596114d74df = $ff75ae50979bb4fc$var$src;
432
481
 
433
482
 
434
483
 
435
- class $1e7ce9484a3c4077$export$9698d62c78b8f366 {
484
+ class $347522367945ce82$export$9698d62c78b8f366 {
436
485
  /**
437
486
  * Creates a new WavStreamPlayer instance
438
487
  * @param {{sampleRate?: number}} options
439
488
  * @returns {WavStreamPlayer}
440
489
  */ constructor({ sampleRate: sampleRate = 44100 } = {}){
441
- this.scriptSrc = (0, $d6d3743ef65c7519$export$bfa8c596114d74df);
490
+ this.scriptSrc = (0, $ff75ae50979bb4fc$export$bfa8c596114d74df);
442
491
  this.sampleRate = sampleRate;
443
492
  this.context = null;
444
493
  this.stream = null;
@@ -475,7 +524,7 @@ class $1e7ce9484a3c4077$export$9698d62c78b8f366 {
475
524
  * @returns {import('./analysis/audio_analysis.js').AudioAnalysisOutputType}
476
525
  */ getFrequencies(analysisType = "frequency", minDecibels = -100, maxDecibels = -30) {
477
526
  if (!this.analyser) throw new Error("Not connected, please call .connect() first");
478
- return (0, $5853841ab58516d4$export$2c3136da0bf130f9).getFrequencies(this.analyser, this.sampleRate, null, analysisType, minDecibels, maxDecibels);
527
+ return (0, $3f7a723e434a4b86$export$2c3136da0bf130f9).getFrequencies(this.analyser, this.sampleRate, null, analysisType, minDecibels, maxDecibels);
479
528
  }
480
529
  /**
481
530
  * @param {string} speaker deviceId
@@ -566,10 +615,16 @@ class $1e7ce9484a3c4077$export$9698d62c78b8f366 {
566
615
  return this.getTrackSampleOffset(true);
567
616
  }
568
617
  }
569
- globalThis.WavStreamPlayer = $1e7ce9484a3c4077$export$9698d62c78b8f366;
618
+ globalThis.WavStreamPlayer = $347522367945ce82$export$9698d62c78b8f366;
570
619
 
571
620
 
572
- const $2cf6a2d8a6d031bc$var$AudioProcessorWorklet = `
621
+ /*!
622
+ * Adapted from openai-realtime-console (https://github.com/openai/openai-realtime-console).
623
+ * Copyright (c) 2024 OpenAI. Modified by Daily. MIT License; see wavtools/index.js.
624
+ */ /*!
625
+ * Adapted from openai-realtime-console (https://github.com/openai/openai-realtime-console).
626
+ * Copyright (c) 2024 OpenAI. Modified by Daily. MIT License; see wavtools/index.js.
627
+ */ const $5a5c5ac16a3be24c$var$AudioProcessorWorklet = `
573
628
  class AudioProcessor extends AudioWorkletProcessor {
574
629
 
575
630
  constructor() {
@@ -777,25 +832,25 @@ class AudioProcessor extends AudioWorkletProcessor {
777
832
 
778
833
  registerProcessor('audio_processor', AudioProcessor);
779
834
  `;
780
- const $2cf6a2d8a6d031bc$var$script = new Blob([
781
- $2cf6a2d8a6d031bc$var$AudioProcessorWorklet
835
+ const $5a5c5ac16a3be24c$var$script = new Blob([
836
+ $5a5c5ac16a3be24c$var$AudioProcessorWorklet
782
837
  ], {
783
838
  type: "application/javascript"
784
839
  });
785
- const $2cf6a2d8a6d031bc$var$src = URL.createObjectURL($2cf6a2d8a6d031bc$var$script);
786
- const $2cf6a2d8a6d031bc$export$1f65f50a8cbff43c = $2cf6a2d8a6d031bc$var$src;
840
+ const $5a5c5ac16a3be24c$var$src = URL.createObjectURL($5a5c5ac16a3be24c$var$script);
841
+ const $5a5c5ac16a3be24c$export$1f65f50a8cbff43c = $5a5c5ac16a3be24c$var$src;
787
842
 
788
843
 
789
844
 
790
845
 
791
- class $0d471c38435bdab6$export$439b217ca659a877 {
846
+ class $35ad6181fc724add$export$439b217ca659a877 {
792
847
  /**
793
848
  * Create a new WavRecorder instance
794
849
  * @param {{sampleRate?: number, outputToSpeakers?: boolean, debug?: boolean}} [options]
795
850
  * @returns {WavRecorder}
796
851
  */ constructor({ sampleRate: sampleRate = 44100, outputToSpeakers: outputToSpeakers = false, debug: debug = false } = {}){
797
852
  // Script source
798
- this.scriptSrc = (0, $2cf6a2d8a6d031bc$export$1f65f50a8cbff43c);
853
+ this.scriptSrc = (0, $5a5c5ac16a3be24c$export$1f65f50a8cbff43c);
799
854
  // Config
800
855
  this.sampleRate = sampleRate;
801
856
  this.outputToSpeakers = outputToSpeakers;
@@ -858,7 +913,7 @@ class $0d471c38435bdab6$export$439b217ca659a877 {
858
913
  else throw new Error(`"audioData" must be one of: Blob, Float32Arrray, Int16Array, ArrayBuffer, Array<number>`);
859
914
  if (fromSampleRate === -1) throw new Error(`Must specify "fromSampleRate" when reading from Float32Array, In16Array or Array`);
860
915
  else if (fromSampleRate < 3000) throw new Error(`Minimum "fromSampleRate" is 3000 (3kHz)`);
861
- if (!data) data = (0, $a61750b8fbee4dae$export$13afda237b1c9846).floatTo16BitPCM(float32Array);
916
+ if (!data) data = (0, $45766326c6faa3c4$export$13afda237b1c9846).floatTo16BitPCM(float32Array);
862
917
  const audio = {
863
918
  bitsPerSample: 16,
864
919
  channels: [
@@ -866,7 +921,7 @@ class $0d471c38435bdab6$export$439b217ca659a877 {
866
921
  ],
867
922
  data: data
868
923
  };
869
- const packer = new (0, $a61750b8fbee4dae$export$13afda237b1c9846)();
924
+ const packer = new (0, $45766326c6faa3c4$export$13afda237b1c9846)();
870
925
  const result = packer.pack(fromSampleRate, audio);
871
926
  blob = result.blob;
872
927
  arrayBuffer = await blob.arrayBuffer();
@@ -1088,8 +1143,8 @@ class $0d471c38435bdab6$export$439b217ca659a877 {
1088
1143
  if (this._chunkProcessorSize) {
1089
1144
  const buffer = this._chunkProcessorBuffer;
1090
1145
  this._chunkProcessorBuffer = {
1091
- raw: (0, $a61750b8fbee4dae$export$13afda237b1c9846).mergeBuffers(buffer.raw, data.raw),
1092
- mono: (0, $a61750b8fbee4dae$export$13afda237b1c9846).mergeBuffers(buffer.mono, data.mono)
1146
+ raw: (0, $45766326c6faa3c4$export$13afda237b1c9846).mergeBuffers(buffer.raw, data.raw),
1147
+ mono: (0, $45766326c6faa3c4$export$13afda237b1c9846).mergeBuffers(buffer.mono, data.mono)
1093
1148
  };
1094
1149
  if (this._chunkProcessorBuffer.mono.byteLength >= this._chunkProcessorSize) {
1095
1150
  this._chunkProcessor(this._chunkProcessorBuffer);
@@ -1126,7 +1181,7 @@ class $0d471c38435bdab6$export$439b217ca659a877 {
1126
1181
  * @returns {import('./analysis/audio_analysis.js').AudioAnalysisOutputType}
1127
1182
  */ getFrequencies(analysisType = "frequency", minDecibels = -100, maxDecibels = -30) {
1128
1183
  if (!this.processor) throw new Error("Session ended: please call .begin() first");
1129
- return (0, $5853841ab58516d4$export$2c3136da0bf130f9).getFrequencies(this.analyser, this.sampleRate, null, analysisType, minDecibels, maxDecibels);
1184
+ return (0, $3f7a723e434a4b86$export$2c3136da0bf130f9).getFrequencies(this.analyser, this.sampleRate, null, analysisType, minDecibels, maxDecibels);
1130
1185
  }
1131
1186
  /**
1132
1187
  * Pauses the recording
@@ -1143,7 +1198,7 @@ class $0d471c38435bdab6$export$439b217ca659a877 {
1143
1198
  }
1144
1199
  /**
1145
1200
  * Start recording stream and storing to memory from the connected audio source
1146
- * @param {(data: { mono: Int16Array; raw: Int16Array }) => any} [chunkProcessor]
1201
+ * @param {(data: { mono: ArrayBuffer; raw: ArrayBuffer }) => any} [chunkProcessor]
1147
1202
  * @param {number} [chunkSize] chunkProcessor will not be triggered until this size threshold met in mono audio
1148
1203
  * @returns {Promise<true>}
1149
1204
  */ async record(chunkProcessor = ()=>{}, chunkSize = 8192) {
@@ -1187,7 +1242,7 @@ class $0d471c38435bdab6$export$439b217ca659a877 {
1187
1242
  if (!force && this.recording) throw new Error("Currently recording: please call .pause() first, or call .save(true) to force");
1188
1243
  this.log("Exporting ...");
1189
1244
  const exportData = await this._event("export");
1190
- const packer = new (0, $a61750b8fbee4dae$export$13afda237b1c9846)();
1245
+ const packer = new (0, $45766326c6faa3c4$export$13afda237b1c9846)();
1191
1246
  const result = packer.pack(this.sampleRate, exportData.audio);
1192
1247
  return result;
1193
1248
  }
@@ -1212,7 +1267,7 @@ class $0d471c38435bdab6$export$439b217ca659a877 {
1212
1267
  this.processor = null;
1213
1268
  this.source = null;
1214
1269
  this.node = null;
1215
- const packer = new (0, $a61750b8fbee4dae$export$13afda237b1c9846)();
1270
+ const packer = new (0, $45766326c6faa3c4$export$13afda237b1c9846)();
1216
1271
  const result = packer.pack(this.sampleRate, exportData.audio);
1217
1272
  return result;
1218
1273
  }
@@ -1228,10 +1283,13 @@ class $0d471c38435bdab6$export$439b217ca659a877 {
1228
1283
  return true;
1229
1284
  }
1230
1285
  }
1231
- globalThis.WavRecorder = $0d471c38435bdab6$export$439b217ca659a877;
1232
-
1286
+ globalThis.WavRecorder = $35ad6181fc724add$export$439b217ca659a877;
1233
1287
 
1234
1288
 
1289
+ /*!
1290
+ * Adapted from openai-realtime-console (https://github.com/openai/openai-realtime-console).
1291
+ * Copyright (c) 2024 OpenAI. Modified by Daily. MIT License; see wavtools/index.js.
1292
+ */
1235
1293
 
1236
1294
 
1237
1295
  /**
@@ -1240,7 +1298,7 @@ globalThis.WavRecorder = $0d471c38435bdab6$export$439b217ca659a877;
1240
1298
  * @param {number} inputSampleRate - Sample rate of input audio
1241
1299
  * @param {number} outputSampleRate - Desired output sample rate
1242
1300
  * @returns {ArrayBuffer} - Resampled audio data as Int16 PCM
1243
- */ function $7cef7a69bdf8f84d$var$resampleAudioBuffer(inputBuffer, inputSampleRate, outputSampleRate) {
1301
+ */ function $ab812aec7679ec67$var$resampleAudioBuffer(inputBuffer, inputSampleRate, outputSampleRate) {
1244
1302
  if (inputSampleRate === outputSampleRate) return inputBuffer;
1245
1303
  const inputView = new Int16Array(inputBuffer);
1246
1304
  const ratio = inputSampleRate / outputSampleRate;
@@ -1257,14 +1315,14 @@ globalThis.WavRecorder = $0d471c38435bdab6$export$439b217ca659a877;
1257
1315
  }
1258
1316
  return outputBuffer;
1259
1317
  }
1260
- class $7cef7a69bdf8f84d$export$2934cf2d25c67a48 {
1318
+ class $ab812aec7679ec67$export$2934cf2d25c67a48 {
1261
1319
  /**
1262
1320
  * Create a new MediaStreamRecorder instance
1263
1321
  * @param {{sampleRate?: number, outputToSpeakers?: boolean, debug?: boolean}} [options]
1264
1322
  * @returns {MediaStreamRecorder}
1265
1323
  */ constructor({ sampleRate: sampleRate = 44100, outputToSpeakers: outputToSpeakers = false, debug: debug = false } = {}){
1266
1324
  // Script source
1267
- this.scriptSrc = (0, $2cf6a2d8a6d031bc$export$1f65f50a8cbff43c);
1325
+ this.scriptSrc = (0, $5a5c5ac16a3be24c$export$1f65f50a8cbff43c);
1268
1326
  // Config
1269
1327
  this.sampleRate = sampleRate;
1270
1328
  this.outputToSpeakers = outputToSpeakers;
@@ -1376,14 +1434,14 @@ class $7cef7a69bdf8f84d$export$2934cf2d25c67a48 {
1376
1434
  // Resample chunk data from native sample rate to target sample rate
1377
1435
  // (no-op if rates match, i.e. for non-Firefox browsers)
1378
1436
  const resampledData = {
1379
- raw: $7cef7a69bdf8f84d$var$resampleAudioBuffer(data.raw, contextSampleRate, this.sampleRate),
1380
- mono: $7cef7a69bdf8f84d$var$resampleAudioBuffer(data.mono, contextSampleRate, this.sampleRate)
1437
+ raw: $ab812aec7679ec67$var$resampleAudioBuffer(data.raw, contextSampleRate, this.sampleRate),
1438
+ mono: $ab812aec7679ec67$var$resampleAudioBuffer(data.mono, contextSampleRate, this.sampleRate)
1381
1439
  };
1382
1440
  if (this._chunkProcessorSize) {
1383
1441
  const buffer = this._chunkProcessorBuffer;
1384
1442
  this._chunkProcessorBuffer = {
1385
- raw: (0, $a61750b8fbee4dae$export$13afda237b1c9846).mergeBuffers(buffer.raw, resampledData.raw),
1386
- mono: (0, $a61750b8fbee4dae$export$13afda237b1c9846).mergeBuffers(buffer.mono, resampledData.mono)
1443
+ raw: (0, $45766326c6faa3c4$export$13afda237b1c9846).mergeBuffers(buffer.raw, resampledData.raw),
1444
+ mono: (0, $45766326c6faa3c4$export$13afda237b1c9846).mergeBuffers(buffer.mono, resampledData.mono)
1387
1445
  };
1388
1446
  if (this._chunkProcessorBuffer.mono.byteLength >= this._chunkProcessorSize) {
1389
1447
  this._chunkProcessor(this._chunkProcessorBuffer);
@@ -1419,7 +1477,7 @@ class $7cef7a69bdf8f84d$export$2934cf2d25c67a48 {
1419
1477
  * @returns {import('./analysis/audio_analysis.js').AudioAnalysisOutputType}
1420
1478
  */ getFrequencies(analysisType = "frequency", minDecibels = -100, maxDecibels = -30) {
1421
1479
  if (!this.processor) throw new Error("Session ended: please call .begin() first");
1422
- return (0, $5853841ab58516d4$export$2c3136da0bf130f9).getFrequencies(this.analyser, this.sampleRate, null, analysisType, minDecibels, maxDecibels);
1480
+ return (0, $3f7a723e434a4b86$export$2c3136da0bf130f9).getFrequencies(this.analyser, this.sampleRate, null, analysisType, minDecibels, maxDecibels);
1423
1481
  }
1424
1482
  /**
1425
1483
  * Pauses the recording
@@ -1436,7 +1494,7 @@ class $7cef7a69bdf8f84d$export$2934cf2d25c67a48 {
1436
1494
  }
1437
1495
  /**
1438
1496
  * Start recording stream and storing to memory from the connected audio source
1439
- * @param {(data: { mono: Int16Array; raw: Int16Array }) => any} [chunkProcessor]
1497
+ * @param {(data: { mono: ArrayBuffer; raw: ArrayBuffer }) => any} [chunkProcessor]
1440
1498
  * @param {number} [chunkSize] chunkProcessor will not be triggered until this size threshold met in mono audio
1441
1499
  * @returns {Promise<true>}
1442
1500
  */ async record(chunkProcessor = ()=>{}, chunkSize = 8192) {
@@ -1480,7 +1538,7 @@ class $7cef7a69bdf8f84d$export$2934cf2d25c67a48 {
1480
1538
  if (!force && this.recording) throw new Error("Currently recording: please call .pause() first, or call .save(true) to force");
1481
1539
  this.log("Exporting ...");
1482
1540
  const exportData = await this._event("export");
1483
- const packer = new (0, $a61750b8fbee4dae$export$13afda237b1c9846)();
1541
+ const packer = new (0, $45766326c6faa3c4$export$13afda237b1c9846)();
1484
1542
  const result = packer.pack(this.sampleRate, exportData.audio);
1485
1543
  return result;
1486
1544
  }
@@ -1503,7 +1561,7 @@ class $7cef7a69bdf8f84d$export$2934cf2d25c67a48 {
1503
1561
  this.processor = null;
1504
1562
  this.source = null;
1505
1563
  this.node = null;
1506
- const packer = new (0, $a61750b8fbee4dae$export$13afda237b1c9846)();
1564
+ const packer = new (0, $45766326c6faa3c4$export$13afda237b1c9846)();
1507
1565
  const result = packer.pack(this.sampleRate, exportData.audio);
1508
1566
  return result;
1509
1567
  }
@@ -1522,16 +1580,986 @@ globalThis.WavRecorder = WavRecorder;
1522
1580
 
1523
1581
 
1524
1582
 
1525
- var $c2e964a535c1120e$exports = {};
1526
- $c2e964a535c1120e$exports = JSON.parse("{\"name\":\"@pipecat-ai/daily-transport\",\"version\":\"1.6.8\",\"license\":\"BSD-2-Clause\",\"main\":\"dist/index.js\",\"module\":\"dist/index.module.js\",\"types\":\"dist/index.d.ts\",\"source\":\"src/index.ts\",\"repository\":{\"type\":\"git\",\"url\":\"git+https://github.com/pipecat-ai/pipecat-client-web-transports.git\"},\"exports\":{\".\":{\"types\":\"./dist/index.d.ts\",\"import\":\"./dist/index.module.js\",\"require\":\"./dist/index.js\"}},\"files\":[\"dist\",\"package.json\",\"README.md\"],\"scripts\":{\"build\":\"parcel build --no-cache\",\"dev\":\"parcel watch\",\"lint\":\"eslint . --ext ts --report-unused-disable-directives --max-warnings 0\"},\"devDependencies\":{\"@pipecat-ai/client-js\":\"^1.13.0\",\"eslint\":\"9.39.1\",\"eslint-config-prettier\":\"^9.1.0\",\"eslint-plugin-simple-import-sort\":\"^12.1.1\"},\"peerDependencies\":{\"@pipecat-ai/client-js\":\"~1.13.0\"},\"dependencies\":{\"@daily-co/daily-js\":\"^0.90.0\"},\"description\":\"Pipecat Daily Transport Package\",\"author\":\"Daily.co\",\"bugs\":{\"url\":\"https://github.com/pipecat-ai/pipecat-client-web-transports/issues\"},\"homepage\":\"https://github.com/pipecat-ai/pipecat-client-web-transports/blob/main/transports/daily-webrtc/README.md\"}");
1583
+
1584
+ class $48faeb169c82673e$export$4a0c46dbbe2ddb67 {
1585
+ constructor(){
1586
+ this._callbacks = {};
1587
+ this._micEnabled = true;
1588
+ this._camEnabled = false;
1589
+ this._supportsScreenShare = false;
1590
+ }
1591
+ setUserAudioCallback(userAudioCallback) {
1592
+ this._userAudioCallback = userAudioCallback;
1593
+ }
1594
+ setClientOptions(options, override = false) {
1595
+ if (this._options && !override) return;
1596
+ this._options = options;
1597
+ this._callbacks = options.callbacks ?? {};
1598
+ this._micEnabled = options.enableMic ?? true;
1599
+ this._camEnabled = options.enableCam ?? false;
1600
+ }
1601
+ get supportsScreenShare() {
1602
+ return this._supportsScreenShare;
1603
+ }
1604
+ /**
1605
+ * The kinds of media this media manager can capture, for the transport's
1606
+ * `mediaSupport`. `false` rules a kind out, and a missing key leaves it unknown.
1607
+ * By default only screen share can be ruled out: `screenShare` is `false` when
1608
+ * `supportsScreenShare` is, because this media manager or the browser can't
1609
+ * share the screen. Media managers that know more override this.
1610
+ */ get mediaSupport() {
1611
+ return this._supportsScreenShare ? {} : {
1612
+ screenShare: false
1613
+ };
1614
+ }
1615
+ }
1616
+ class $48faeb169c82673e$export$45c5b9bfba2f6304 extends $48faeb169c82673e$export$4a0c46dbbe2ddb67 {
1617
+ constructor(recorderChunkSize, recorderSampleRate = 24000){
1618
+ super();
1619
+ this._initialized = false;
1620
+ this._recorderChunkSize = undefined;
1621
+ this._recorderChunkSize = recorderChunkSize;
1622
+ this._wavRecorder = new (0, $35ad6181fc724add$export$439b217ca659a877)({
1623
+ sampleRate: recorderSampleRate
1624
+ });
1625
+ this._wavStreamPlayer = new (0, $347522367945ce82$export$9698d62c78b8f366)({
1626
+ sampleRate: 24000
1627
+ });
1628
+ }
1629
+ /** Captures the microphone only. */ get mediaSupport() {
1630
+ return {
1631
+ mic: true,
1632
+ cam: false,
1633
+ screenShare: false
1634
+ };
1635
+ }
1636
+ async initialize() {
1637
+ try {
1638
+ await this._wavRecorder.begin();
1639
+ } catch (error) {
1640
+ // void. swallow the error. we still want to set up
1641
+ // the listeners and the player.
1642
+ }
1643
+ this._wavRecorder.listenForDeviceChange(null);
1644
+ this._wavRecorder.listenForDeviceChange(this._handleAvailableDevicesUpdated.bind(this));
1645
+ this._wavRecorder.listenForDeviceErrors(null);
1646
+ this._wavRecorder.listenForDeviceErrors(this._handleDeviceError.bind(this));
1647
+ await this._wavStreamPlayer.connect();
1648
+ this._initialized = true;
1649
+ }
1650
+ async connect() {
1651
+ if (!this._initialized) await this.initialize();
1652
+ const isAlreadyRecording = this._wavRecorder.getStatus() == "recording";
1653
+ if (this._micEnabled && !isAlreadyRecording) await this._startRecording();
1654
+ if (this._camEnabled) console.warn("WavMediaManager does not support video input.");
1655
+ }
1656
+ async disconnect() {
1657
+ if (!this._initialized) return;
1658
+ await this._wavRecorder.end();
1659
+ await this._wavStreamPlayer.interrupt();
1660
+ this._initialized = false;
1661
+ }
1662
+ async interruptBotAudio() {
1663
+ return this._wavStreamPlayer.interrupt();
1664
+ }
1665
+ bufferBotAudio(data, id) {
1666
+ return this._wavStreamPlayer.add16BitPCM(data, id);
1667
+ }
1668
+ getAllMics() {
1669
+ return this._wavRecorder.listDevices();
1670
+ }
1671
+ getAllCams() {
1672
+ // TODO: Video not supported yet
1673
+ return Promise.resolve([]);
1674
+ }
1675
+ getAllSpeakers() {
1676
+ // TODO: Implement speaker support
1677
+ return Promise.resolve([]);
1678
+ }
1679
+ async updateMic(micId) {
1680
+ const prevMic = this._wavRecorder.deviceSelection;
1681
+ if (this._wavRecorder.getStatus() !== "ended") await this._wavRecorder.end();
1682
+ try {
1683
+ await this._wavRecorder.begin(micId);
1684
+ if (this._micEnabled) await this._startRecording();
1685
+ const curMic = this._wavRecorder.deviceSelection;
1686
+ if (curMic && prevMic && prevMic.label !== curMic.label) this._callbacks.onMicUpdated?.(curMic);
1687
+ } catch (error) {
1688
+ // void. If begin() fails, it will have already logged and called
1689
+ // onDeviceError if necessary.
1690
+ }
1691
+ }
1692
+ updateCam(camId) {
1693
+ // TODO: Video not supported yet
1694
+ }
1695
+ updateSpeaker(speakerId) {
1696
+ // TODO: Implement speaker support
1697
+ }
1698
+ get selectedMic() {
1699
+ return this._wavRecorder.deviceSelection ?? {};
1700
+ }
1701
+ get selectedCam() {
1702
+ // TODO: Video not supported yet
1703
+ return {};
1704
+ }
1705
+ get selectedSpeaker() {
1706
+ // TODO: Implement speaker support
1707
+ return {};
1708
+ }
1709
+ async enableMic(enable) {
1710
+ this._micEnabled = enable;
1711
+ if (!this._wavRecorder.stream) return;
1712
+ this._wavRecorder.stream.getAudioTracks().forEach((track)=>{
1713
+ track.enabled = enable;
1714
+ if (!enable) this._callbacks.onTrackStopped?.(track, $48faeb169c82673e$var$localParticipant());
1715
+ });
1716
+ if (enable) await this._startRecording();
1717
+ else await this._wavRecorder.pause();
1718
+ }
1719
+ enableCam(enable) {
1720
+ // TODO: Video not supported yet
1721
+ console.warn("WavMediaManager does not support video input.");
1722
+ }
1723
+ enableScreenShare(enable) {
1724
+ // TODO: Screensharing not supported yet
1725
+ console.warn("WavMediaManager does not support screen sharing.");
1726
+ }
1727
+ get isCamEnabled() {
1728
+ // TODO: Video not supported yet
1729
+ return false;
1730
+ }
1731
+ get isMicEnabled() {
1732
+ return this._micEnabled;
1733
+ }
1734
+ get isSharingScreen() {
1735
+ // TODO: Screensharing not supported yet
1736
+ return false;
1737
+ }
1738
+ tracks() {
1739
+ const tracks = this._wavRecorder.stream?.getTracks()[0];
1740
+ return {
1741
+ local: tracks ? {
1742
+ audio: tracks
1743
+ } : {}
1744
+ };
1745
+ }
1746
+ async _startRecording() {
1747
+ await this._wavRecorder.record((data)=>{
1748
+ this._userAudioCallback?.(data.mono);
1749
+ }, this._recorderChunkSize);
1750
+ const track = this._wavRecorder.stream?.getAudioTracks()[0];
1751
+ if (track) this._callbacks.onTrackStarted?.(track, $48faeb169c82673e$var$localParticipant());
1752
+ }
1753
+ _handleAvailableDevicesUpdated(devices) {
1754
+ this._callbacks.onAvailableCamsUpdated?.(devices.filter((d)=>d.kind === "videoinput"));
1755
+ this._callbacks.onAvailableMicsUpdated?.(devices.filter((d)=>d.kind === "audioinput"));
1756
+ // if the current device went away or we're using the default and
1757
+ // the default changed, reset the mic.
1758
+ const defaultDevice = devices.find((d)=>d.deviceId === "default");
1759
+ const currentDevice = this._wavRecorder.deviceSelection;
1760
+ if (currentDevice && (!devices.some((d)=>d.deviceId === currentDevice.deviceId) || currentDevice.deviceId === "default" && currentDevice.label !== defaultDevice?.label)) this.updateMic("");
1761
+ }
1762
+ _handleDeviceError({ devices: devices, type: type, error: error }) {
1763
+ const deviceError = new (0, $1clrS$pipecataiclientjs.DeviceError)(devices, type, error?.message, error ? {
1764
+ sourceError: error
1765
+ } : undefined);
1766
+ this._callbacks.onDeviceError?.(deviceError);
1767
+ }
1768
+ }
1769
+ const $48faeb169c82673e$var$localParticipant = ()=>{
1770
+ return {
1771
+ id: "local",
1772
+ name: "",
1773
+ local: true
1774
+ };
1775
+ };
1776
+
1777
+
1778
+
1779
+
1780
+
1527
1781
 
1528
1782
 
1529
- var $28bdeb35415d61e8$export$ef180de88fd317cc;
1783
+ class $00a190ef6aa79f0d$export$c95c65abc5f47125 extends (0, $48faeb169c82673e$export$4a0c46dbbe2ddb67) {
1784
+ constructor(enablePlayer = true, enableRecording = true, onTrackStartedCallback, onTrackStoppedCallback, recorderChunkSize, recorderSampleRate = 24000, playerSampleRate = 24000){
1785
+ super();
1786
+ this._selectedCam = {};
1787
+ this._selectedMic = {};
1788
+ this._selectedSpeaker = {};
1789
+ this._remoteAudioLevelInterval = null;
1790
+ this._recorderChunkSize = undefined;
1791
+ this._initialized = false;
1792
+ this._connected = false;
1793
+ this._currentAudioTrack = null;
1794
+ this._connectResolve = null;
1795
+ this.onTrackStartedCallback = onTrackStartedCallback;
1796
+ this.onTrackStoppedCallback = onTrackStoppedCallback;
1797
+ this._recorderChunkSize = recorderChunkSize;
1798
+ this._supportsScreenShare = (0, $15398512372f76d1$export$7f8f33b9b54c8307)();
1799
+ this._daily = (0, ($parcel$interopDefault($1clrS$dailycodailyjs))).getCallInstance() ?? (0, ($parcel$interopDefault($1clrS$dailycodailyjs))).createCallObject();
1800
+ if (enableRecording) this._mediaStreamRecorder = new (0, $ab812aec7679ec67$export$2934cf2d25c67a48)({
1801
+ sampleRate: recorderSampleRate
1802
+ });
1803
+ if (enablePlayer) this._wavStreamPlayer = new (0, $347522367945ce82$export$9698d62c78b8f366)({
1804
+ sampleRate: playerSampleRate
1805
+ });
1806
+ this._daily.on("track-started", this.handleTrackStarted.bind(this));
1807
+ this._daily.on("track-stopped", this.handleTrackStopped.bind(this));
1808
+ this._daily.on("available-devices-updated", this._handleAvailableDevicesUpdated.bind(this));
1809
+ this._daily.on("selected-devices-updated", this._handleSelectedDevicesUpdated.bind(this));
1810
+ this._daily.on("camera-error", this.handleDeviceError.bind(this));
1811
+ this._daily.on("local-audio-level", this._handleLocalAudioLevel.bind(this));
1812
+ }
1813
+ async initialize() {
1814
+ if (this._initialized) {
1815
+ console.warn("DailyMediaManager already initialized");
1816
+ return;
1817
+ }
1818
+ const infos = await this._daily.startCamera({
1819
+ startVideoOff: !this._camEnabled,
1820
+ startAudioOff: !this._micEnabled,
1821
+ dailyConfig: {
1822
+ useDevicePreferenceCookies: true
1823
+ }
1824
+ });
1825
+ const { devices: devices } = await this._daily.enumerateDevices();
1826
+ const cams = devices.filter((d)=>d.kind === "videoinput");
1827
+ const mics = devices.filter((d)=>d.kind === "audioinput");
1828
+ const speakers = devices.filter((d)=>d.kind === "audiooutput");
1829
+ this._callbacks.onAvailableCamsUpdated?.(cams);
1830
+ this._callbacks.onAvailableMicsUpdated?.(mics);
1831
+ this._callbacks.onAvailableSpeakersUpdated?.(speakers);
1832
+ this._selectedCam = infos.camera;
1833
+ this._callbacks.onCamUpdated?.(infos.camera);
1834
+ this._selectedMic = infos.mic;
1835
+ this._callbacks.onMicUpdated?.(infos.mic);
1836
+ this._selectedSpeaker = infos.speaker;
1837
+ this._callbacks.onSpeakerUpdated?.(infos.speaker);
1838
+ // Instantiate audio observers
1839
+ if (!this._daily.isLocalAudioLevelObserverRunning()) await this._daily.startLocalAudioLevelObserver(100);
1840
+ if (this._wavStreamPlayer) {
1841
+ await this._wavStreamPlayer.connect();
1842
+ if (!this._remoteAudioLevelInterval) this._remoteAudioLevelInterval = setInterval(()=>{
1843
+ const frequencies = this._wavStreamPlayer.getFrequencies();
1844
+ let aveVal = 0;
1845
+ if (frequencies.values?.length) aveVal = frequencies.values.reduce((a, c)=>a + c, 0) / frequencies.values.length;
1846
+ this._handleRemoteAudioLevel(aveVal);
1847
+ }, 100);
1848
+ }
1849
+ this._initialized = true;
1850
+ }
1851
+ async connect() {
1852
+ if (this._connected) {
1853
+ console.warn("DailyMediaManager already connected");
1854
+ return;
1855
+ }
1856
+ this._connected = true;
1857
+ if (!this._initialized) return new Promise((resolve)=>{
1858
+ (async ()=>{
1859
+ this._connectResolve = resolve;
1860
+ await this.initialize();
1861
+ // Without a recorder, handleTrackStarted never fires to resolve this
1862
+ // promise, so resolve here once initialization is complete.
1863
+ if (this._connectResolve && !this._mediaStreamRecorder) {
1864
+ this._connectResolve();
1865
+ this._connectResolve = null;
1866
+ }
1867
+ })();
1868
+ });
1869
+ if (this._micEnabled) this._startRecording();
1870
+ }
1871
+ async disconnect() {
1872
+ if (this._remoteAudioLevelInterval) clearInterval(this._remoteAudioLevelInterval);
1873
+ this._remoteAudioLevelInterval = null;
1874
+ this._daily.leave();
1875
+ this._currentAudioTrack = null;
1876
+ await this._mediaStreamRecorder?.end();
1877
+ this._wavStreamPlayer?.interrupt();
1878
+ this._initialized = false;
1879
+ this._connected = false;
1880
+ }
1881
+ async interruptBotAudio() {
1882
+ return this._wavStreamPlayer?.interrupt();
1883
+ }
1884
+ bufferBotAudio(data, id) {
1885
+ return this._wavStreamPlayer?.add16BitPCM(data, id);
1886
+ }
1887
+ async getAllMics() {
1888
+ let devices = (await this._daily.enumerateDevices()).devices;
1889
+ return devices.filter((device)=>device.kind === "audioinput");
1890
+ }
1891
+ async getAllCams() {
1892
+ let devices = (await this._daily.enumerateDevices()).devices;
1893
+ return devices.filter((device)=>device.kind === "videoinput");
1894
+ }
1895
+ async getAllSpeakers() {
1896
+ let devices = (await this._daily.enumerateDevices()).devices;
1897
+ return devices.filter((device)=>device.kind === "audiooutput");
1898
+ }
1899
+ updateMic(micId) {
1900
+ this._daily.setInputDevicesAsync({
1901
+ audioDeviceId: micId
1902
+ }).then((deviceInfo)=>{
1903
+ this._selectedMic = deviceInfo.mic;
1904
+ });
1905
+ }
1906
+ updateCam(camId) {
1907
+ this._daily.setInputDevicesAsync({
1908
+ videoDeviceId: camId
1909
+ }).then((deviceInfo)=>{
1910
+ this._selectedCam = deviceInfo.camera;
1911
+ });
1912
+ }
1913
+ async updateSpeaker(speakerId) {
1914
+ if (!this._wavStreamPlayer) {
1915
+ try {
1916
+ const dInfo = await this._daily.setOutputDeviceAsync({
1917
+ outputDeviceId: speakerId
1918
+ });
1919
+ this._selectedSpeaker = dInfo.speaker;
1920
+ this._callbacks.onSpeakerUpdated?.(this._selectedSpeaker);
1921
+ } catch (e) {
1922
+ console.error("Error setting output device", e);
1923
+ }
1924
+ return;
1925
+ }
1926
+ if (speakerId !== "default" && this._selectedSpeaker.deviceId === speakerId) return;
1927
+ let sID = speakerId;
1928
+ if (sID === "default") {
1929
+ const speakers = await this.getAllSpeakers();
1930
+ const defaultSpeaker = speakers.find((s)=>s.deviceId === "default");
1931
+ if (!defaultSpeaker) {
1932
+ console.warn("No default speaker found");
1933
+ return;
1934
+ }
1935
+ speakers.splice(speakers.indexOf(defaultSpeaker), 1);
1936
+ const defaultSpeakerCp = speakers.find((s)=>defaultSpeaker.label.includes(s.label));
1937
+ sID = defaultSpeakerCp?.deviceId ?? speakerId;
1938
+ }
1939
+ this._wavStreamPlayer?.updateSpeaker(sID).then(()=>{
1940
+ this._selectedSpeaker = {
1941
+ deviceId: speakerId
1942
+ };
1943
+ this._callbacks.onSpeakerUpdated?.(this._selectedSpeaker);
1944
+ });
1945
+ }
1946
+ get selectedMic() {
1947
+ return this._selectedMic;
1948
+ }
1949
+ get selectedCam() {
1950
+ return this._selectedCam;
1951
+ }
1952
+ get selectedSpeaker() {
1953
+ return this._selectedSpeaker;
1954
+ }
1955
+ async enableMic(enable) {
1956
+ this._micEnabled = enable;
1957
+ if (!this._daily.participants()?.local) return;
1958
+ this._daily.setLocalAudio(enable);
1959
+ if (this._mediaStreamRecorder) {
1960
+ if (enable) {
1961
+ if (this._mediaStreamRecorder.getStatus() === "paused") this._startRecording();
1962
+ // else, we'll record on the track-started event
1963
+ } else if (this._mediaStreamRecorder.getStatus() === "recording") this._mediaStreamRecorder.pause();
1964
+ }
1965
+ }
1966
+ enableCam(enable) {
1967
+ this._camEnabled = enable;
1968
+ this._daily.setLocalVideo(enable);
1969
+ }
1970
+ enableScreenShare(enable) {
1971
+ if (enable) this._daily.startScreenShare();
1972
+ else this._daily.stopScreenShare();
1973
+ }
1974
+ // NOTE: deliberately not `this._daily.localVideo()` / `localAudio()`. Daily
1975
+ // fires 'track-started'/'track-stopped' *before* it commits the new state
1976
+ // to the participant object those getters read from (see daily-js's
1977
+ // DAILY_EVENT_PARTICIPANT_UPDATED handling: maybeEventTrackStopped/Started
1978
+ // run, then `this._participants[id]` is reassigned). Callers that react to
1979
+ // TrackStarted/TrackStopped by reading isCamEnabled/isMicEnabled — e.g. to
1980
+ // resync UI state — would otherwise always observe the pre-toggle value.
1981
+ // _camEnabled/_micEnabled are updated synchronously in
1982
+ // handleTrackStarted/handleTrackStopped below, before those callbacks fire.
1983
+ get isCamEnabled() {
1984
+ return this._camEnabled;
1985
+ }
1986
+ get isMicEnabled() {
1987
+ return this._micEnabled;
1988
+ }
1989
+ /** Captures the microphone, the camera and, where the browser can, the screen. */ get mediaSupport() {
1990
+ return {
1991
+ mic: true,
1992
+ cam: true,
1993
+ screenShare: this._supportsScreenShare
1994
+ };
1995
+ }
1996
+ get isSharingScreen() {
1997
+ return this._daily.localScreenAudio() || this._daily.localScreenVideo();
1998
+ }
1999
+ tracks() {
2000
+ const participants = this._daily.participants();
2001
+ return {
2002
+ local: {
2003
+ audio: participants?.local?.tracks?.audio?.persistentTrack,
2004
+ screenAudio: participants?.local?.tracks?.screenAudio?.persistentTrack,
2005
+ screenVideo: participants?.local?.tracks?.screenVideo?.persistentTrack,
2006
+ video: participants?.local?.tracks?.video?.persistentTrack
2007
+ }
2008
+ };
2009
+ }
2010
+ _startRecording() {
2011
+ if (!this._connected || !this._mediaStreamRecorder) return;
2012
+ try {
2013
+ this._mediaStreamRecorder.record((data)=>{
2014
+ this._userAudioCallback(data.mono);
2015
+ }, this._recorderChunkSize);
2016
+ } catch (e) {
2017
+ const err = e;
2018
+ if (!err.message.includes("Already recording")) console.error("Error starting recording", e);
2019
+ }
2020
+ }
2021
+ _handleAvailableDevicesUpdated(event) {
2022
+ this._callbacks.onAvailableCamsUpdated?.(event.availableDevices.filter((d)=>d.kind === "videoinput"));
2023
+ this._callbacks.onAvailableMicsUpdated?.(event.availableDevices.filter((d)=>d.kind === "audioinput"));
2024
+ this._callbacks.onAvailableSpeakersUpdated?.(event.availableDevices.filter((d)=>d.kind === "audiooutput"));
2025
+ if (this._selectedSpeaker.deviceId === "default") this.updateSpeaker("default");
2026
+ }
2027
+ _handleSelectedDevicesUpdated(event) {
2028
+ if (this._selectedCam?.deviceId !== event.devices.camera) {
2029
+ this._selectedCam = event.devices.camera;
2030
+ this._callbacks.onCamUpdated?.(event.devices.camera);
2031
+ }
2032
+ if (this._selectedMic?.deviceId !== event.devices.mic) {
2033
+ this._selectedMic = event.devices.mic;
2034
+ this._callbacks.onMicUpdated?.(event.devices.mic);
2035
+ }
2036
+ }
2037
+ handleDeviceError(ev) {
2038
+ const generateDeviceError = (error)=>{
2039
+ const devices = [];
2040
+ switch(error.type){
2041
+ case "permissions":
2042
+ error.blockedMedia.forEach((d)=>{
2043
+ devices.push(d === "video" ? "cam" : "mic");
2044
+ });
2045
+ return new (0, $1clrS$pipecataiclientjs.DeviceError)(devices, error.type, error.msg, {
2046
+ blockedBy: error.blockedBy
2047
+ });
2048
+ case "not-found":
2049
+ error.missingMedia.forEach((d)=>{
2050
+ devices.push(d === "video" ? "cam" : "mic");
2051
+ });
2052
+ return new (0, $1clrS$pipecataiclientjs.DeviceError)(devices, error.type, error.msg);
2053
+ case "constraints":
2054
+ error.failedMedia.forEach((d)=>{
2055
+ devices.push(d === "video" ? "cam" : "mic");
2056
+ });
2057
+ return new (0, $1clrS$pipecataiclientjs.DeviceError)(devices, error.type, error.msg, {
2058
+ reason: error.reason
2059
+ });
2060
+ case "cam-in-use":
2061
+ devices.push("cam");
2062
+ return new (0, $1clrS$pipecataiclientjs.DeviceError)(devices, "in-use", error.msg);
2063
+ case "mic-in-use":
2064
+ devices.push("mic");
2065
+ return new (0, $1clrS$pipecataiclientjs.DeviceError)(devices, "in-use", error.msg);
2066
+ case "cam-mic-in-use":
2067
+ devices.push("cam");
2068
+ devices.push("mic");
2069
+ return new (0, $1clrS$pipecataiclientjs.DeviceError)(devices, "in-use", error.msg);
2070
+ case "undefined-mediadevices":
2071
+ case "unknown":
2072
+ default:
2073
+ devices.push("cam");
2074
+ devices.push("mic");
2075
+ return new (0, $1clrS$pipecataiclientjs.DeviceError)(devices, error.type, error.msg);
2076
+ }
2077
+ };
2078
+ const deviceError = generateDeviceError(ev.error);
2079
+ // enableMic()/enableCam() set _micEnabled/_camEnabled optimistically,
2080
+ // but setLocalAudio()/setLocalVideo() are fire-and-forget — no promise,
2081
+ // no synchronous failure signal — so a failed request (blocked
2082
+ // permission, device in use, etc.) leaves that optimistic value wrong
2083
+ // with nothing to correct it: no track-started/stopped ever fires for
2084
+ // an operation that didn't actually take effect. This is the only
2085
+ // signal we get that the request failed, so resync from Daily's actual
2086
+ // state for whichever device(s) it implicates.
2087
+ if (deviceError.devices.includes("mic")) this._micEnabled = this._daily.localAudio();
2088
+ if (deviceError.devices.includes("cam")) this._camEnabled = this._daily.localVideo();
2089
+ this._callbacks.onDeviceError?.(deviceError);
2090
+ }
2091
+ _handleLocalAudioLevel(ev) {
2092
+ this._callbacks.onLocalAudioLevel?.(ev.audioLevel);
2093
+ }
2094
+ _handleRemoteAudioLevel(audioLevel) {
2095
+ this._callbacks.onRemoteAudioLevel?.(audioLevel, $00a190ef6aa79f0d$var$botParticipant());
2096
+ }
2097
+ async handleTrackStarted(event) {
2098
+ if (!event.participant?.local) return;
2099
+ if (event.track.kind === "audio") {
2100
+ this._micEnabled = true;
2101
+ if (this._mediaStreamRecorder) {
2102
+ const status = this._mediaStreamRecorder.getStatus();
2103
+ switch(status){
2104
+ case "ended":
2105
+ try {
2106
+ await this._mediaStreamRecorder.begin(event.track);
2107
+ if (this._connected) {
2108
+ this._startRecording();
2109
+ if (this._connectResolve) {
2110
+ this._connectResolve();
2111
+ this._connectResolve = null;
2112
+ }
2113
+ }
2114
+ } catch (e) {
2115
+ // void. nothing to do.
2116
+ }
2117
+ break;
2118
+ case "paused":
2119
+ this._startRecording();
2120
+ break;
2121
+ case "recording":
2122
+ default:
2123
+ if (this._currentAudioTrack !== event.track) {
2124
+ await this._mediaStreamRecorder.end();
2125
+ try {
2126
+ await this._mediaStreamRecorder.begin(event.track);
2127
+ this._startRecording();
2128
+ } catch (e) {
2129
+ // void. nothing to do.
2130
+ }
2131
+ } else console.warn("track-started event received for current track and already recording");
2132
+ break;
2133
+ }
2134
+ }
2135
+ this._currentAudioTrack = event.track;
2136
+ } else if (event.track.kind === "video") this._camEnabled = true;
2137
+ this._callbacks.onTrackStarted?.(event.track, event.participant ? $00a190ef6aa79f0d$var$dailyParticipantToParticipant(event.participant) : undefined);
2138
+ this.onTrackStartedCallback?.(event);
2139
+ }
2140
+ handleTrackStopped(event) {
2141
+ if (!event.participant?.local) return;
2142
+ if (event.track.kind === "audio") {
2143
+ this._micEnabled = false;
2144
+ if (this._mediaStreamRecorder && this._mediaStreamRecorder.getStatus() === "recording") this._mediaStreamRecorder.pause();
2145
+ } else if (event.track.kind === "video") this._camEnabled = false;
2146
+ this._callbacks.onTrackStopped?.(event.track, event.participant ? $00a190ef6aa79f0d$var$dailyParticipantToParticipant(event.participant) : undefined);
2147
+ this.onTrackStoppedCallback?.(event);
2148
+ }
2149
+ }
2150
+ const $00a190ef6aa79f0d$var$dailyParticipantToParticipant = (p)=>({
2151
+ id: p.user_id,
2152
+ local: p.local,
2153
+ name: p.user_name
2154
+ });
2155
+ const $00a190ef6aa79f0d$var$botParticipant = ()=>({
2156
+ id: "bot",
2157
+ local: false,
2158
+ name: "Bot"
2159
+ });
2160
+
2161
+
2162
+
2163
+ const $7f41aaa208a19660$var$readyStates = [
2164
+ "CONNECTING",
2165
+ "OPEN",
2166
+ "CLOSING",
2167
+ "CLOSED"
2168
+ ];
2169
+ const $7f41aaa208a19660$var$KEEP_ALIVE_INTERVAL = 5000;
2170
+ const $7f41aaa208a19660$var$KEEP_ALIVE_TIMEOUT = 15000;
2171
+ // client side code in soupSFU has a timeout of 15 seconds for command response
2172
+ // 5 seconds seems reasonable that it provides roughly 3 retry attempts
2173
+ const $7f41aaa208a19660$var$WEBSOCKET_CONNECTION_TIMEOUT = 150000;
2174
+ const $7f41aaa208a19660$var$DEFAULT_RECONNECT_ATTEMPTS = 2;
2175
+ const $7f41aaa208a19660$var$MAX_RECONNECT_ATTEMPTS = 10;
2176
+ const $7f41aaa208a19660$var$DEFAULT_RECONNECT_INTERVAL = 1000;
2177
+ const $7f41aaa208a19660$var$MAX_RECONNECT_INTERVAL = 30000;
2178
+ const $7f41aaa208a19660$var$DEFAULT_RECONNECT_DECAY = 1.5;
2179
+ const $7f41aaa208a19660$var$WEBSOCKET_TIMEOUT_CODE = 4100;
2180
+ const $7f41aaa208a19660$var$SIG_CONNECTION_CANCELED = "SIG_CONNECTION_CANCELED";
2181
+ const $7f41aaa208a19660$var$WEBSOCKET_ERROR = "WEBSOCKET_ERROR";
2182
+ var $7f41aaa208a19660$var$LOG_LEVEL;
2183
+ (function(LOG_LEVEL) {
2184
+ LOG_LEVEL[LOG_LEVEL["DEBUG"] = 0] = "DEBUG";
2185
+ LOG_LEVEL[LOG_LEVEL["ERROR"] = 1] = "ERROR";
2186
+ LOG_LEVEL[LOG_LEVEL["INFO"] = 2] = "INFO";
2187
+ LOG_LEVEL[LOG_LEVEL["WARN"] = 3] = "WARN";
2188
+ })($7f41aaa208a19660$var$LOG_LEVEL || ($7f41aaa208a19660$var$LOG_LEVEL = {}));
2189
+ class $7f41aaa208a19660$var$rWebSocket {
2190
+ constructor(url, protocols){
2191
+ this._closedManually = false;
2192
+ this._errored = false;
2193
+ this._rejected = false;
2194
+ this._timed_out = false;
2195
+ this._initialConnectionOk = false;
2196
+ this._ws = new WebSocket(url, protocols);
2197
+ }
2198
+ addEventListener(type, listener) {
2199
+ this._ws.addEventListener(type, listener);
2200
+ }
2201
+ // Add other WebSocket methods as needed
2202
+ close(code, reason) {
2203
+ this._ws.close(code, reason);
2204
+ }
2205
+ send(data) {
2206
+ this._ws.send(data);
2207
+ }
2208
+ // Add getters for WebSocket properties
2209
+ get url() {
2210
+ return this._ws.url;
2211
+ }
2212
+ get readyState() {
2213
+ return this._ws.readyState;
2214
+ }
2215
+ }
2216
+ class $7f41aaa208a19660$export$4f3d0ffd941ebefb extends (0, $1clrS$events.EventEmitter) {
2217
+ constructor(address, protocols, options = {}){
2218
+ super();
2219
+ if (!address) throw new Error("Need a valid WebSocket URL");
2220
+ this._ws = null;
2221
+ this._url = address;
2222
+ this._protocols = protocols;
2223
+ this._parseBlobToJson = options?.parseBlobToJson ?? true;
2224
+ this.init();
2225
+ }
2226
+ init() {
2227
+ this._keepAliveTimeout = $7f41aaa208a19660$var$KEEP_ALIVE_TIMEOUT;
2228
+ this._keepAliveInterval = $7f41aaa208a19660$var$KEEP_ALIVE_INTERVAL;
2229
+ this._disconnected = false;
2230
+ this._keepIntervalID = null;
2231
+ this._shouldRetryFn = null;
2232
+ this._connectionTimeout = $7f41aaa208a19660$var$WEBSOCKET_CONNECTION_TIMEOUT;
2233
+ this._reconnectAttempts = 0;
2234
+ this._allowedReconnectAttempts = $7f41aaa208a19660$var$DEFAULT_RECONNECT_ATTEMPTS;
2235
+ this._reconnectInterval = $7f41aaa208a19660$var$DEFAULT_RECONNECT_INTERVAL;
2236
+ this._maxReconnectInterval = $7f41aaa208a19660$var$MAX_RECONNECT_INTERVAL;
2237
+ this._reconnectDecay = $7f41aaa208a19660$var$DEFAULT_RECONNECT_DECAY;
2238
+ }
2239
+ async connect() {
2240
+ return new Promise((resolve, reject)=>{
2241
+ this._disconnected = false;
2242
+ this.clearReconnectTimeout();
2243
+ let ws = new $7f41aaa208a19660$var$rWebSocket(this._url, this._protocols);
2244
+ this.setConnectionTimeout();
2245
+ ws.addEventListener("close", (evt)=>{
2246
+ const closeEvent = evt;
2247
+ let code = ws._timed_out ? $7f41aaa208a19660$var$WEBSOCKET_TIMEOUT_CODE : closeEvent.code;
2248
+ let reason = ws._timed_out ? "websocket connection timed out" : closeEvent.reason;
2249
+ ws._timed_out = false;
2250
+ if (!ws._closedManually && ws._initialConnectionOk) {
2251
+ console.warn(`signaling socket closed unexpectedly: ${code}${reason ? " " + reason : ""}`);
2252
+ this._closeSocket();
2253
+ this.emit("close", code, reason);
2254
+ } else this.log("signaling socket closed");
2255
+ if (!ws._closedManually && (ws._errored || ws._timed_out)) {
2256
+ console.warn(`signaling socket closed on error: ${code}${reason ? " " + reason : ""}`);
2257
+ if (!ws._rejected) {
2258
+ ws._rejected = true;
2259
+ const err = new Error(`WebSocket connection error (${code}): ${reason}`);
2260
+ err.name = $7f41aaa208a19660$var$WEBSOCKET_ERROR;
2261
+ reject(err);
2262
+ }
2263
+ }
2264
+ });
2265
+ ws.addEventListener("open", (evt)=>{
2266
+ this.log("wss connection opened to", $7f41aaa208a19660$var$LOG_LEVEL.DEBUG, this._url);
2267
+ this.clearConnectionTimeout();
2268
+ // now that the timeout closes the socket, in theory this onopen
2269
+ // callback should never happen in the first place, but seems
2270
+ // harmless to leave these safeguards in
2271
+ if (ws._rejected || ws._timed_out) return;
2272
+ if (ws._closedManually || this._ws && this._ws !== ws) {
2273
+ ws._rejected = true;
2274
+ ws.close();
2275
+ let err = Error("wss connection interrupted by disconnect or newer connection");
2276
+ err.name = $7f41aaa208a19660$var$SIG_CONNECTION_CANCELED;
2277
+ reject(err);
2278
+ return;
2279
+ }
2280
+ ws._initialConnectionOk = this._url;
2281
+ this._lastMsgRecvTime = Date.now();
2282
+ if (this._keepAliveInterval) this._keepIntervalID = setInterval(()=>this.checkSocketHealthAndSendKeepAlive(), this._keepAliveInterval);
2283
+ this._ws = ws;
2284
+ this.emit("open");
2285
+ resolve(ws);
2286
+ });
2287
+ ws.addEventListener("error", (evt)=>{
2288
+ // fyi: evt is an Event here, with 0 amount of helpful info. If there
2289
+ // happens to be info about the error, it's included in the
2290
+ // accompanying close event (because that make sense. shakes head)
2291
+ // SO. We do not reject here. Instead, we just set the _errored
2292
+ // flag on the socket so when the close event occurs, it knows to
2293
+ // reject the promise
2294
+ if (!ws._closedManually) {
2295
+ const wsTarget = evt.currentTarget;
2296
+ this.log(`websocket error event: ${wsTarget?.url}`);
2297
+ }
2298
+ ws._errored = true;
2299
+ });
2300
+ ws.addEventListener("message", (msg)=>{
2301
+ this._handleMessage(msg);
2302
+ });
2303
+ });
2304
+ }
2305
+ setConnectionTimeout() {
2306
+ this._connectionTimeoutID = setTimeout(async ()=>{
2307
+ this.log("Connection reconnect attempt timed out.");
2308
+ this.emit("connection-timeout");
2309
+ this.clearConnectionTimeout();
2310
+ await this._closeSocket();
2311
+ }, this._connectionTimeout);
2312
+ }
2313
+ clearConnectionTimeout() {
2314
+ clearTimeout(this._connectionTimeoutID);
2315
+ this._connectionTimeoutID = undefined;
2316
+ }
2317
+ clearReconnectTimeout() {
2318
+ clearTimeout(this._reconnectTimeoutID);
2319
+ this._reconnectTimeoutID = undefined;
2320
+ }
2321
+ clearKeepAliveInterval() {
2322
+ if (this._keepIntervalID) {
2323
+ clearInterval(this._keepIntervalID);
2324
+ this._keepIntervalID = null;
2325
+ }
2326
+ }
2327
+ async checkSocketHealthAndSendKeepAlive() {
2328
+ if (!(this._ws && this._ws.readyState === WebSocket.OPEN)) return;
2329
+ if (!this._keepAliveTimeout || !this._keepAliveInterval) return;
2330
+ // See if we haven't gotten a message back recently, and if we
2331
+ // haven't, close the socket. the os timeouts to detect if a socket
2332
+ // has gone stale are longer than we want.
2333
+ if (Date.now() - this._lastMsgRecvTime > this._keepAliveTimeout) {
2334
+ this.log("Connection is stale, need to reconnect", $7f41aaa208a19660$var$LOG_LEVEL.WARN);
2335
+ await this._closeSocket();
2336
+ return;
2337
+ }
2338
+ // Only emit the keep-alive event if we haven't sent anything else recently
2339
+ if (Date.now() - this._lastMsgSendTime < this._keepAliveInterval) return;
2340
+ this.log("Emitting keep-alive", $7f41aaa208a19660$var$LOG_LEVEL.DEBUG);
2341
+ this.emit("keep-alive");
2342
+ }
2343
+ // We use the word manually here to imply the application using this code
2344
+ // or this code itself will decide to close the socket.
2345
+ async _closeSocket() {
2346
+ this.log("Closing");
2347
+ try {
2348
+ this.clearKeepAliveInterval();
2349
+ this._lastMsgRecvTime = 0;
2350
+ if (this._ws) {
2351
+ this._ws._closedManually = true;
2352
+ this._ws.close();
2353
+ }
2354
+ // query retry function if we want to retry.
2355
+ const shouldRetry = this._ws?._initialConnectionOk && this._shouldRetryFn && this._shouldRetryFn();
2356
+ this._ws = null;
2357
+ if (shouldRetry) {
2358
+ this.log("Emitting reconnect", $7f41aaa208a19660$var$LOG_LEVEL.DEBUG);
2359
+ this.emit("reconnecting");
2360
+ await this.retryFailedConnection();
2361
+ }
2362
+ } catch (error) {
2363
+ this.log(`Error while closing and retrying: ${error}`, $7f41aaa208a19660$var$LOG_LEVEL.ERROR);
2364
+ }
2365
+ }
2366
+ async retryFailedConnection() {
2367
+ if (this._reconnectAttempts < this._allowedReconnectAttempts) {
2368
+ if (this._reconnectTimeoutID) {
2369
+ this.log("Retry already scheduled");
2370
+ return;
2371
+ }
2372
+ this.log("Retrying failed connection");
2373
+ let timeout = // The timeout logic is taken from
2374
+ // https://github.com/joewalnes/reconnecting-websocket
2375
+ this._reconnectInterval * Math.pow(this._reconnectDecay, this._reconnectAttempts);
2376
+ timeout = timeout > this._maxReconnectInterval ? this._maxReconnectInterval : timeout;
2377
+ this.log(`Reconnecting in ${timeout / 1000} seconds`);
2378
+ this._reconnectAttempts += 1;
2379
+ this._reconnectTimeoutID = setTimeout(()=>this.connect(), timeout);
2380
+ } else {
2381
+ this.log("Maximum connection retry attempts exceeded", $7f41aaa208a19660$var$LOG_LEVEL.ERROR);
2382
+ this.emit("reconnect-failed");
2383
+ }
2384
+ }
2385
+ log(msg, log_level = $7f41aaa208a19660$var$LOG_LEVEL.DEBUG, ...args) {
2386
+ switch(log_level){
2387
+ case $7f41aaa208a19660$var$LOG_LEVEL.DEBUG:
2388
+ console.debug(`websocket: ${msg}`, ...args);
2389
+ break;
2390
+ case $7f41aaa208a19660$var$LOG_LEVEL.ERROR:
2391
+ console.error(`websocket: ${msg}`, ...args);
2392
+ break;
2393
+ case $7f41aaa208a19660$var$LOG_LEVEL.WARN:
2394
+ console.warn(`websocket: ${msg}`, ...args);
2395
+ break;
2396
+ case $7f41aaa208a19660$var$LOG_LEVEL.INFO:
2397
+ default:
2398
+ console.log(`websocket: ${msg}`, ...args);
2399
+ break;
2400
+ }
2401
+ }
2402
+ async send(data) {
2403
+ try {
2404
+ if (this._ws && this._ws.readyState === WebSocket.OPEN) {
2405
+ this._lastMsgSendTime = Date.now();
2406
+ this._ws.send(data);
2407
+ } else this.log(`Failed to send data, web socket not open.`, $7f41aaa208a19660$var$LOG_LEVEL.ERROR);
2408
+ } catch (error) {
2409
+ this.log(`Failed to send data. ${error}`, $7f41aaa208a19660$var$LOG_LEVEL.ERROR);
2410
+ }
2411
+ }
2412
+ async close() {
2413
+ try {
2414
+ this.log("Closing websocket");
2415
+ this._disconnected = true;
2416
+ this.clearReconnectTimeout();
2417
+ this._closeSocket();
2418
+ } catch (error) {
2419
+ this.log(`Failed to close websocket. ${error}`);
2420
+ }
2421
+ }
2422
+ get readyState() {
2423
+ return this._ws?.readyState ?? WebSocket.CLOSED;
2424
+ }
2425
+ get url() {
2426
+ return this._url;
2427
+ }
2428
+ get keepAliveTimeout() {
2429
+ return this._keepAliveTimeout;
2430
+ }
2431
+ set keepAliveTimeout(keepAliveTimeout) {
2432
+ if (typeof keepAliveTimeout === "number") {
2433
+ this.log(`Setting ACK freshness timeout to ${keepAliveTimeout}`);
2434
+ this._keepAliveTimeout = keepAliveTimeout;
2435
+ }
2436
+ }
2437
+ get keepAliveInterval() {
2438
+ return this._keepAliveInterval;
2439
+ }
2440
+ set keepAliveInterval(keepAliveInterval) {
2441
+ if (typeof keepAliveInterval === "number") {
2442
+ this.log(`Setting keep-alive interval to ${keepAliveInterval}`);
2443
+ this._keepAliveInterval = keepAliveInterval;
2444
+ }
2445
+ }
2446
+ set shouldRetryFn(cb) {
2447
+ if (typeof cb === "function") this._shouldRetryFn = cb;
2448
+ }
2449
+ get connectionTimeout() {
2450
+ return this._connectionTimeout;
2451
+ }
2452
+ set connectionTimeout(timeout) {
2453
+ if (typeof timeout === "number") this._connectionTimeout = timeout;
2454
+ }
2455
+ get maxReconnectAttempts() {
2456
+ return this._allowedReconnectAttempts;
2457
+ }
2458
+ set maxReconnectAttempts(attempts) {
2459
+ if (attempts > 0 && attempts < $7f41aaa208a19660$var$MAX_RECONNECT_ATTEMPTS) {
2460
+ this.log(`Setting maximum connection retry attempts to ${attempts}`);
2461
+ this._allowedReconnectAttempts = attempts;
2462
+ } else this._allowedReconnectAttempts = $7f41aaa208a19660$var$DEFAULT_RECONNECT_ATTEMPTS;
2463
+ }
2464
+ get reconnectInterval() {
2465
+ return this._reconnectInterval;
2466
+ }
2467
+ set reconnectInterval(interval) {
2468
+ if (typeof interval === "number") this._reconnectInterval = interval < this._maxReconnectInterval ? interval : this._maxReconnectInterval;
2469
+ }
2470
+ async _handleMessage(event) {
2471
+ this._lastMsgRecvTime = Date.now();
2472
+ const data = event.data;
2473
+ const _parsePromise = new Promise((resolve, reject)=>{
2474
+ if (typeof data === "string") // Handle text message
2475
+ resolve(data);
2476
+ else if (data instanceof ArrayBuffer) {
2477
+ // Handle binary message
2478
+ const arrayBuffer = data;
2479
+ // Parse the ArrayBuffer as needed
2480
+ // Example: Convert ArrayBuffer to Uint8Array
2481
+ resolve(new Uint8Array(arrayBuffer));
2482
+ // Process the Uint8Array as needed
2483
+ } else if (data instanceof Blob) {
2484
+ if (!this._parseBlobToJson) {
2485
+ resolve(data);
2486
+ return;
2487
+ }
2488
+ // Handle Blob message
2489
+ const blob = data;
2490
+ // Convert Blob to ArrayBuffer
2491
+ const reader = new FileReader();
2492
+ reader.onload = ()=>{
2493
+ const text = reader.result;
2494
+ try {
2495
+ const json = JSON.parse(text);
2496
+ resolve(json);
2497
+ } catch (e) {
2498
+ console.error("Failed to parse JSON from Blob:", e);
2499
+ }
2500
+ };
2501
+ reader.readAsText(blob);
2502
+ }
2503
+ });
2504
+ let msg = await _parsePromise;
2505
+ this.emit("message", msg);
2506
+ }
2507
+ }
2508
+ [
2509
+ "binaryType",
2510
+ "bufferedAmount",
2511
+ "extensions",
2512
+ "protocol",
2513
+ "readyState",
2514
+ "url",
2515
+ "keepAliveTimeout",
2516
+ "keepAliveInterval",
2517
+ "shouldRetryFn",
2518
+ "connectionTimeout",
2519
+ "maxReconnectAttempts",
2520
+ "reconnectInterval"
2521
+ ].forEach((property)=>{
2522
+ Object.defineProperty($7f41aaa208a19660$export$4f3d0ffd941ebefb.prototype, property, {
2523
+ enumerable: true
2524
+ });
2525
+ });
2526
+ [
2527
+ "CONNECTING",
2528
+ "OPEN",
2529
+ "CLOSING",
2530
+ "CLOSED"
2531
+ ].forEach((property)=>{
2532
+ Object.defineProperty($7f41aaa208a19660$export$4f3d0ffd941ebefb.prototype, property, {
2533
+ enumerable: true,
2534
+ value: $7f41aaa208a19660$var$readyStates.indexOf(property)
2535
+ });
2536
+ });
2537
+ [
2538
+ "CONNECTING",
2539
+ "OPEN",
2540
+ "CLOSING",
2541
+ "CLOSED"
2542
+ ].forEach((property)=>{
2543
+ Object.defineProperty($7f41aaa208a19660$export$4f3d0ffd941ebefb, property, {
2544
+ enumerable: true,
2545
+ value: $7f41aaa208a19660$var$readyStates.indexOf(property)
2546
+ });
2547
+ });
2548
+
2549
+
2550
+
2551
+
2552
+
2553
+ var $48b67f1ef231aa26$exports = {};
2554
+ $48b67f1ef231aa26$exports = JSON.parse("{\"name\":\"@pipecat-ai/daily-transport\",\"version\":\"1.7.0\",\"license\":\"BSD-2-Clause\",\"main\":\"dist/index.js\",\"module\":\"dist/index.module.js\",\"types\":\"dist/index.d.ts\",\"source\":\"src/index.ts\",\"repository\":{\"type\":\"git\",\"url\":\"git+https://github.com/pipecat-ai/pipecat-client-web-transports.git\"},\"exports\":{\".\":{\"types\":\"./dist/index.d.ts\",\"import\":\"./dist/index.module.js\",\"require\":\"./dist/index.js\"}},\"files\":[\"dist\",\"package.json\",\"README.md\"],\"targets\":{\"main\":{\"includeNodeModules\":[\"@pipecat-ai/transport-lib\"]},\"module\":{\"includeNodeModules\":[\"@pipecat-ai/transport-lib\"]}},\"scripts\":{\"build\":\"parcel build --no-cache\",\"dev\":\"parcel watch\",\"lint\":\"eslint . --ext ts --report-unused-disable-directives --max-warnings 0\"},\"devDependencies\":{\"@pipecat-ai/client-js\":\"^1.14.0\",\"@pipecat-ai/transport-lib\":\"^0.2.0\",\"eslint\":\"9.39.1\",\"eslint-config-prettier\":\"^9.1.0\",\"eslint-plugin-simple-import-sort\":\"^12.1.1\"},\"peerDependencies\":{\"@pipecat-ai/client-js\":\"~1.14.0\"},\"dependencies\":{\"@daily-co/daily-js\":\"^0.94.0\"},\"description\":\"Pipecat Daily Transport Package\",\"author\":\"Daily.co\",\"bugs\":{\"url\":\"https://github.com/pipecat-ai/pipecat-client-web-transports/issues\"},\"homepage\":\"https://github.com/pipecat-ai/pipecat-client-web-transports/blob/main/transports/daily-webrtc/README.md\"}");
2555
+
2556
+
2557
+ var $1c83796b12dd4e49$export$ef180de88fd317cc;
1530
2558
  (function(DailyRTVIMessageType) {
1531
2559
  DailyRTVIMessageType["AUDIO_BUFFERING_STARTED"] = "audio-buffering-started";
1532
2560
  DailyRTVIMessageType["AUDIO_BUFFERING_STOPPED"] = "audio-buffering-stopped";
1533
- })($28bdeb35415d61e8$export$ef180de88fd317cc || ($28bdeb35415d61e8$export$ef180de88fd317cc = {}));
1534
- class $28bdeb35415d61e8$var$DailyCallWrapper {
2561
+ })($1c83796b12dd4e49$export$ef180de88fd317cc || ($1c83796b12dd4e49$export$ef180de88fd317cc = {}));
2562
+ class $1c83796b12dd4e49$var$DailyCallWrapper {
1535
2563
  constructor(daily){
1536
2564
  this._daily = daily;
1537
2565
  this._proxy = new Proxy(this._daily, {
@@ -1574,7 +2602,7 @@ class $28bdeb35415d61e8$var$DailyCallWrapper {
1574
2602
  return this._proxy;
1575
2603
  }
1576
2604
  }
1577
- class $28bdeb35415d61e8$export$b1ca982aa1e488c1 extends (0, $jrPAn$pipecataiclientjs.Transport) {
2605
+ class $1c83796b12dd4e49$export$b1ca982aa1e488c1 extends (0, $1clrS$pipecataiclientjs.Transport) {
1578
2606
  constructor(opts = {}){
1579
2607
  super();
1580
2608
  this._botId = "";
@@ -1583,6 +2611,19 @@ class $28bdeb35415d61e8$export$b1ca982aa1e488c1 extends (0, $jrPAn$pipecataiclie
1583
2611
  this._selectedSpeaker = {};
1584
2612
  this._currentAudioTrack = null;
1585
2613
  this._audioQueue = [];
2614
+ // NOTE: deliberately not read live off `this._daily.localAudio()` /
2615
+ // `localVideo()` in the isMicEnabled/isCamEnabled getters below. Daily
2616
+ // fires 'track-started'/'track-stopped' *before* it commits the new state
2617
+ // to the participant object those calls read from (daily-js emits the
2618
+ // track event from within its participant-updated handling, then
2619
+ // reassigns its internal participant cache afterwards). Code that reacts
2620
+ // to TrackStarted/TrackStopped by reading isMicEnabled/isCamEnabled to
2621
+ // resync UI state — e.g. PipecatClientState's mic/cam sync — would
2622
+ // otherwise always observe the pre-toggle value. These fields are updated
2623
+ // synchronously in enableMic/enableCam and in handleTrackStarted/
2624
+ // handleTrackStopped, before those callbacks fire.
2625
+ this._micEnabled = true;
2626
+ this._camEnabled = false;
1586
2627
  this._callbacks = {};
1587
2628
  const { bufferLocalAudioUntilBotReady: bufferLocalAudioUntilBotReady, ...dailyOpts } = opts;
1588
2629
  this._dailyFactoryOptions = dailyOpts;
@@ -1593,15 +2634,15 @@ class $28bdeb35415d61e8$export$b1ca982aa1e488c1 extends (0, $jrPAn$pipecataiclie
1593
2634
  this._dailyFactoryOptions.dailyConfig.useDevicePreferenceCookies = true;
1594
2635
  }
1595
2636
  this._bufferLocalAudioUntilBotReady = bufferLocalAudioUntilBotReady || false;
1596
- this._daily = (0, ($parcel$interopDefault($jrPAn$dailycodailyjs))).createCallObject({
2637
+ this._daily = (0, ($parcel$interopDefault($1clrS$dailycodailyjs))).createCallObject({
1597
2638
  ...this._dailyFactoryOptions,
1598
2639
  allowMultipleCallInstances: true
1599
2640
  });
1600
- this._dailyWrapper = new $28bdeb35415d61e8$var$DailyCallWrapper(this._daily);
2641
+ this._dailyWrapper = new $1c83796b12dd4e49$var$DailyCallWrapper(this._daily);
1601
2642
  }
1602
2643
  setupRecorder() {
1603
- this._mediaStreamRecorder = new (0, $7cef7a69bdf8f84d$export$2934cf2d25c67a48)({
1604
- sampleRate: $28bdeb35415d61e8$export$b1ca982aa1e488c1.RECORDER_SAMPLE_RATE
2644
+ this._mediaStreamRecorder = new (0, $ab812aec7679ec67$export$2934cf2d25c67a48)({
2645
+ sampleRate: $1c83796b12dd4e49$export$b1ca982aa1e488c1.RECORDER_SAMPLE_RATE
1605
2646
  });
1606
2647
  }
1607
2648
  handleUserAudioStream(data) {
@@ -1610,7 +2651,7 @@ class $28bdeb35415d61e8$export$b1ca982aa1e488c1 extends (0, $jrPAn$pipecataiclie
1610
2651
  flushAudioQueue() {
1611
2652
  const batchSize = 10; // Number of buffers to send in one message
1612
2653
  if (this._audioQueue.length === 0) return;
1613
- (0, $jrPAn$pipecataiclientjs.logger).debug(`Will flush audio queue: ${this._audioQueue.length}`);
2654
+ (0, $1clrS$pipecataiclientjs.logger).debug(`Will flush audio queue: ${this._audioQueue.length}`);
1614
2655
  while(this._audioQueue.length > 0){
1615
2656
  const batch = [];
1616
2657
  // Collect up to `batchSize` items
@@ -1632,7 +2673,7 @@ class $28bdeb35415d61e8$export$b1ca982aa1e488c1 extends (0, $jrPAn$pipecataiclie
1632
2673
  type: "raw-audio-batch",
1633
2674
  data: {
1634
2675
  base64AudioBatch: encodedBatch,
1635
- sampleRate: $28bdeb35415d61e8$export$b1ca982aa1e488c1.RECORDER_SAMPLE_RATE,
2676
+ sampleRate: $1c83796b12dd4e49$export$b1ca982aa1e488c1.RECORDER_SAMPLE_RATE,
1636
2677
  numChannels: 1
1637
2678
  }
1638
2679
  };
@@ -1646,9 +2687,11 @@ class $28bdeb35415d61e8$export$b1ca982aa1e488c1 extends (0, $jrPAn$pipecataiclie
1646
2687
  this._dailyFactoryOptions.startVideoOff = !(options.enableCam ?? false);
1647
2688
  if (this._dailyFactoryOptions.startAudioOff == null || options.enableMic != null) // Default is mic on
1648
2689
  this._dailyFactoryOptions.startAudioOff = !(options.enableMic ?? true);
2690
+ this._camEnabled = !this._dailyFactoryOptions.startVideoOff;
2691
+ this._micEnabled = !this._dailyFactoryOptions.startAudioOff;
1649
2692
  this.attachEventListeners();
1650
2693
  this.state = "disconnected";
1651
- (0, $jrPAn$pipecataiclientjs.logger).debug("[Daily Transport] Initialized", (0, (/*@__PURE__*/$parcel$interopDefault($c2e964a535c1120e$exports))).version);
2694
+ (0, $1clrS$pipecataiclientjs.logger).debug("[Daily Transport] Initialized", (0, (/*@__PURE__*/$parcel$interopDefault($48b67f1ef231aa26$exports))).version);
1652
2695
  }
1653
2696
  get dailyCallClient() {
1654
2697
  return this._dailyWrapper.proxy;
@@ -1702,7 +2745,7 @@ class $28bdeb35415d61e8$export$b1ca982aa1e488c1 extends (0, $jrPAn$pipecataiclie
1702
2745
  }).then((infos)=>{
1703
2746
  this._selectedSpeaker = infos.speaker;
1704
2747
  }).catch((e)=>{
1705
- this._callbacks.onDeviceError?.(new (0, $jrPAn$pipecataiclientjs.DeviceError)([
2748
+ this._callbacks.onDeviceError?.(new (0, $1clrS$pipecataiclientjs.DeviceError)([
1706
2749
  "speaker"
1707
2750
  ], e.type ?? "unknown", e.message));
1708
2751
  });
@@ -1717,17 +2760,19 @@ class $28bdeb35415d61e8$export$b1ca982aa1e488c1 extends (0, $jrPAn$pipecataiclie
1717
2760
  // joined — pre-session, daily-js can't act on the request because the
1718
2761
  // call object isn't part of a meeting yet.
1719
2762
  this._dailyFactoryOptions.startAudioOff = !enable;
2763
+ this._micEnabled = enable;
1720
2764
  if (this._daily.participants()?.local) this._daily.setLocalAudio(enable);
1721
2765
  }
1722
2766
  get isMicEnabled() {
1723
- return this._daily.localAudio();
2767
+ return this._micEnabled;
1724
2768
  }
1725
2769
  enableCam(enable) {
1726
2770
  this._dailyFactoryOptions.startVideoOff = !enable;
2771
+ this._camEnabled = enable;
1727
2772
  if (this._daily.participants()?.local) this._daily.setLocalVideo(enable);
1728
2773
  }
1729
2774
  get isCamEnabled() {
1730
- return this._daily.localVideo();
2775
+ return this._camEnabled;
1731
2776
  }
1732
2777
  enableScreenShare(enable) {
1733
2778
  if (enable) this._daily.startScreenShare();
@@ -1736,6 +2781,15 @@ class $28bdeb35415d61e8$export$b1ca982aa1e488c1 extends (0, $jrPAn$pipecataiclie
1736
2781
  get isSharingScreen() {
1737
2782
  return this._daily.localScreenAudio() || this._daily.localScreenVideo();
1738
2783
  }
2784
+ /** Carries every kind of media; screen share where the browser can. */ get mediaSupport() {
2785
+ return {
2786
+ mic: true,
2787
+ cam: true,
2788
+ screenShare: (0, $15398512372f76d1$export$7f8f33b9b54c8307)(),
2789
+ botAudio: true,
2790
+ botVideo: true
2791
+ };
2792
+ }
1739
2793
  tracks() {
1740
2794
  const participants = this._daily.participants() ?? {};
1741
2795
  const bot = participants?.[this._botId];
@@ -1755,15 +2809,15 @@ class $28bdeb35415d61e8$export$b1ca982aa1e488c1 extends (0, $jrPAn$pipecataiclie
1755
2809
  }
1756
2810
  async startRecording() {
1757
2811
  try {
1758
- (0, $jrPAn$pipecataiclientjs.logger).info("[Daily Transport] Initializing recording");
2812
+ (0, $1clrS$pipecataiclientjs.logger).info("[Daily Transport] Initializing recording");
1759
2813
  await this._mediaStreamRecorder.record((data)=>{
1760
2814
  this.handleUserAudioStream(data.mono);
1761
- }, $28bdeb35415d61e8$export$b1ca982aa1e488c1.RECORDER_CHUNK_SIZE);
2815
+ }, $1c83796b12dd4e49$export$b1ca982aa1e488c1.RECORDER_CHUNK_SIZE);
1762
2816
  this._callbacks.onAudioBufferingStarted?.();
1763
- (0, $jrPAn$pipecataiclientjs.logger).info("[Daily Transport] Recording Initialized");
2817
+ (0, $1clrS$pipecataiclientjs.logger).info("[Daily Transport] Recording Initialized");
1764
2818
  } catch (e) {
1765
2819
  const err = e;
1766
- if (!err.message.includes("Already recording")) (0, $jrPAn$pipecataiclientjs.logger).error("Error starting recording", e);
2820
+ if (!err.message.includes("Already recording")) (0, $1clrS$pipecataiclientjs.logger).error("Error starting recording", e);
1767
2821
  }
1768
2822
  }
1769
2823
  async preAuth(dailyCallOptions) {
@@ -1771,7 +2825,7 @@ class $28bdeb35415d61e8$export$b1ca982aa1e488c1 extends (0, $jrPAn$pipecataiclie
1771
2825
  await this._daily.preAuth(dailyCallOptions);
1772
2826
  }
1773
2827
  async initDevices() {
1774
- if (!this._daily) throw new (0, $jrPAn$pipecataiclientjs.RTVIError)("Transport instance not initialized");
2828
+ if (!this._daily) throw new (0, $1clrS$pipecataiclientjs.RTVIError)("Transport instance not initialized");
1775
2829
  this.state = "initializing";
1776
2830
  const infos = await this._daily.startCamera(this._dailyFactoryOptions);
1777
2831
  const { devices: devices } = await this._daily.enumerateDevices();
@@ -1787,14 +2841,20 @@ class $28bdeb35415d61e8$export$b1ca982aa1e488c1 extends (0, $jrPAn$pipecataiclie
1787
2841
  this._callbacks.onCamUpdated?.(infos.camera);
1788
2842
  this._callbacks.onMicUpdated?.(infos.mic);
1789
2843
  this._callbacks.onSpeakerUpdated?.(infos.speaker);
1790
- // Instantiate audio observers
1791
- if (!this._daily.isLocalAudioLevelObserverRunning()) await this._daily.startLocalAudioLevelObserver(100);
1792
- if (!this._daily.isRemoteParticipantsAudioLevelObserverRunning()) await this._daily.startRemoteParticipantsAudioLevelObserver(100);
2844
+ await this.startAudioLevelObservers();
1793
2845
  this.state = "initialized";
1794
2846
  }
2847
+ async startAudioLevelObservers() {
2848
+ try {
2849
+ if (!this._daily.isLocalAudioLevelObserverRunning()) await this._daily.startLocalAudioLevelObserver(100);
2850
+ if (!this._daily.isRemoteParticipantsAudioLevelObserverRunning()) await this._daily.startRemoteParticipantsAudioLevelObserver(100);
2851
+ } catch (e) {
2852
+ (0, $1clrS$pipecataiclientjs.logger).warn("[Daily Transport] Failed to start audio level observers", e);
2853
+ }
2854
+ }
1795
2855
  _validateConnectionParams(connectParams) {
1796
2856
  if (connectParams === undefined || connectParams === null) return undefined;
1797
- if (typeof connectParams !== "object") throw new (0, $jrPAn$pipecataiclientjs.RTVIError)("Invalid connection parameters");
2857
+ if (typeof connectParams !== "object") throw new (0, $1clrS$pipecataiclientjs.RTVIError)("Invalid connection parameters");
1798
2858
  const tmpParams = connectParams;
1799
2859
  if (tmpParams.room_url) {
1800
2860
  tmpParams.url = tmpParams.room_url;
@@ -1812,7 +2872,7 @@ class $28bdeb35415d61e8$export$b1ca982aa1e488c1 extends (0, $jrPAn$pipecataiclie
1812
2872
  return tmpParams;
1813
2873
  }
1814
2874
  async _connect(connectParams) {
1815
- if (!this._daily) throw new (0, $jrPAn$pipecataiclientjs.RTVIError)("Transport instance not initialized");
2875
+ if (!this._daily) throw new (0, $1clrS$pipecataiclientjs.RTVIError)("Transport instance not initialized");
1816
2876
  if (connectParams) this._dailyFactoryOptions = {
1817
2877
  ...this._dailyFactoryOptions,
1818
2878
  ...connectParams
@@ -1821,11 +2881,17 @@ class $28bdeb35415d61e8$export$b1ca982aa1e488c1 extends (0, $jrPAn$pipecataiclie
1821
2881
  try {
1822
2882
  await this._daily.join(this._dailyFactoryOptions);
1823
2883
  } catch (e) {
1824
- (0, $jrPAn$pipecataiclientjs.logger).error("Failed to join room", e);
2884
+ (0, $1clrS$pipecataiclientjs.logger).error("Failed to join room", e);
1825
2885
  this.state = "error";
1826
- throw new (0, $jrPAn$pipecataiclientjs.TransportStartError)();
2886
+ throw new (0, $1clrS$pipecataiclientjs.TransportStartError)();
1827
2887
  }
1828
2888
  if (this._abortController?.signal.aborted) return;
2889
+ // initDevices() is not guaranteed to have run before we get here:
2890
+ // PipecatClient skips it when both mic and cam start disabled, and on a
2891
+ // reconnect once devices are already initialized. _disconnect() stops
2892
+ // the observers, so make sure they are running for this session or
2893
+ // onLocalAudioLevel / onRemoteAudioLevel never fire.
2894
+ await this.startAudioLevelObservers();
1829
2895
  const r = await this._daily.room();
1830
2896
  this._maxMessageSize = r?.domainConfig?.max_app_message_size || 10485760;
1831
2897
  this.state = "connected";
@@ -1844,7 +2910,7 @@ class $28bdeb35415d61e8$export$b1ca982aa1e488c1 extends (0, $jrPAn$pipecataiclie
1844
2910
  // we've received the bot_ready signal
1845
2911
  this.state = "ready";
1846
2912
  this.flushAudioQueue();
1847
- this.sendMessage((0, $jrPAn$pipecataiclientjs.RTVIMessage).clientReady());
2913
+ this.sendMessage((0, $1clrS$pipecataiclientjs.RTVIMessage).clientReady());
1848
2914
  this.stopRecording();
1849
2915
  resolve();
1850
2916
  };
@@ -1862,7 +2928,7 @@ class $28bdeb35415d61e8$export$b1ca982aa1e488c1 extends (0, $jrPAn$pipecataiclie
1862
2928
  this._daily.off("track-started", readyHandler);
1863
2929
  // Check if it's an iOS device
1864
2930
  if (isIOS()) {
1865
- (0, $jrPAn$pipecataiclientjs.logger).debug("[Daily Transport] iOS device detected, adding 0.5 second delay before sending ready message");
2931
+ (0, $1clrS$pipecataiclientjs.logger).debug("[Daily Transport] iOS device detected, adding 0.5 second delay before sending ready message");
1866
2932
  // Add 500ms delay for iOS devices:
1867
2933
  // This is a workaround for iOS devices clipping a portion
1868
2934
  // of the audio after the track becomes playable.
@@ -1909,7 +2975,7 @@ class $28bdeb35415d61e8$export$b1ca982aa1e488c1 extends (0, $jrPAn$pipecataiclie
1909
2975
  try {
1910
2976
  this._daily.sendAppMessage(message, "*");
1911
2977
  } catch (error) {
1912
- if (error instanceof Error && error.message.includes("Message data too large")) throw new (0, $jrPAn$pipecataiclientjs.MessageTooLargeError)(error.message);
2978
+ if (error instanceof Error && error.message.includes("Message data too large")) throw new (0, $1clrS$pipecataiclientjs.MessageTooLargeError)(error.message);
1913
2979
  throw error;
1914
2980
  }
1915
2981
  }
@@ -1948,40 +3014,51 @@ class $28bdeb35415d61e8$export$b1ca982aa1e488c1 extends (0, $jrPAn$pipecataiclie
1948
3014
  error.blockedMedia.forEach((d)=>{
1949
3015
  devices.push(d === "video" ? "cam" : "mic");
1950
3016
  });
1951
- return new (0, $jrPAn$pipecataiclientjs.DeviceError)(devices, error.type, error.msg, {
3017
+ return new (0, $1clrS$pipecataiclientjs.DeviceError)(devices, error.type, error.msg, {
1952
3018
  blockedBy: error.blockedBy
1953
3019
  });
1954
3020
  case "not-found":
1955
3021
  error.missingMedia.forEach((d)=>{
1956
3022
  devices.push(d === "video" ? "cam" : "mic");
1957
3023
  });
1958
- return new (0, $jrPAn$pipecataiclientjs.DeviceError)(devices, error.type, error.msg);
3024
+ return new (0, $1clrS$pipecataiclientjs.DeviceError)(devices, error.type, error.msg);
1959
3025
  case "constraints":
1960
3026
  error.failedMedia.forEach((d)=>{
1961
3027
  devices.push(d === "video" ? "cam" : "mic");
1962
3028
  });
1963
- return new (0, $jrPAn$pipecataiclientjs.DeviceError)(devices, error.type, error.msg, {
3029
+ return new (0, $1clrS$pipecataiclientjs.DeviceError)(devices, error.type, error.msg, {
1964
3030
  reason: error.reason
1965
3031
  });
1966
3032
  case "cam-in-use":
1967
3033
  devices.push("cam");
1968
- return new (0, $jrPAn$pipecataiclientjs.DeviceError)(devices, "in-use", error.msg);
3034
+ return new (0, $1clrS$pipecataiclientjs.DeviceError)(devices, "in-use", error.msg);
1969
3035
  case "mic-in-use":
1970
3036
  devices.push("mic");
1971
- return new (0, $jrPAn$pipecataiclientjs.DeviceError)(devices, "in-use", error.msg);
3037
+ return new (0, $1clrS$pipecataiclientjs.DeviceError)(devices, "in-use", error.msg);
1972
3038
  case "cam-mic-in-use":
1973
3039
  devices.push("cam");
1974
3040
  devices.push("mic");
1975
- return new (0, $jrPAn$pipecataiclientjs.DeviceError)(devices, "in-use", error.msg);
3041
+ return new (0, $1clrS$pipecataiclientjs.DeviceError)(devices, "in-use", error.msg);
1976
3042
  case "undefined-mediadevices":
1977
3043
  case "unknown":
1978
3044
  default:
1979
3045
  devices.push("cam");
1980
3046
  devices.push("mic");
1981
- return new (0, $jrPAn$pipecataiclientjs.DeviceError)(devices, error.type, error.msg);
3047
+ return new (0, $1clrS$pipecataiclientjs.DeviceError)(devices, error.type, error.msg);
1982
3048
  }
1983
3049
  };
1984
- this._callbacks.onDeviceError?.(generateDeviceError(ev.error));
3050
+ const deviceError = generateDeviceError(ev.error);
3051
+ // enableMic()/enableCam() set _micEnabled/_camEnabled optimistically,
3052
+ // but setLocalAudio()/setLocalVideo() are fire-and-forget — no promise,
3053
+ // no synchronous failure signal — so a failed request (blocked
3054
+ // permission, device in use, etc.) leaves that optimistic value wrong
3055
+ // with nothing to correct it: no track-started/stopped ever fires for
3056
+ // an operation that didn't actually take effect. This is the only
3057
+ // signal we get that the request failed, so resync from Daily's actual
3058
+ // state for whichever device(s) it implicates.
3059
+ if (deviceError.devices.includes("mic")) this._micEnabled = this._daily.localAudio();
3060
+ if (deviceError.devices.includes("cam")) this._camEnabled = this._daily.localVideo();
3061
+ this._callbacks.onDeviceError?.(deviceError);
1985
3062
  }
1986
3063
  async handleLocalAudioTrack(track) {
1987
3064
  if (this.state == "ready" || !this._bufferLocalAudioUntilBotReady) return;
@@ -2007,31 +3084,42 @@ class $28bdeb35415d61e8$export$b1ca982aa1e488c1 extends (0, $jrPAn$pipecataiclie
2007
3084
  } catch (e) {
2008
3085
  // void. nothing to do.
2009
3086
  }
2010
- else (0, $jrPAn$pipecataiclientjs.logger).warn("track-started event received for current track and already recording");
3087
+ else (0, $1clrS$pipecataiclientjs.logger).warn("track-started event received for current track and already recording");
2011
3088
  break;
2012
3089
  }
2013
3090
  this._currentAudioTrack = track;
2014
3091
  }
2015
3092
  handleTrackStarted(ev) {
2016
- if (ev.type === "screenAudio" || ev.type === "screenVideo") this._callbacks.onScreenTrackStarted?.(ev.track, ev.participant ? $28bdeb35415d61e8$var$dailyParticipantToParticipant(ev.participant) : undefined);
3093
+ if (ev.type === "screenAudio" || ev.type === "screenVideo") this._callbacks.onScreenTrackStarted?.(ev.track, ev.participant ? $1c83796b12dd4e49$var$dailyParticipantToParticipant(ev.participant) : undefined);
2017
3094
  else {
2018
- if (ev.participant?.local && ev.track.kind === "audio") this.handleLocalAudioTrack(ev.track);
2019
- this._callbacks.onTrackStarted?.(ev.track, ev.participant ? $28bdeb35415d61e8$var$dailyParticipantToParticipant(ev.participant) : undefined);
3095
+ if (ev.participant?.local) {
3096
+ if (ev.track.kind === "audio") {
3097
+ this._micEnabled = true;
3098
+ this.handleLocalAudioTrack(ev.track);
3099
+ } else if (ev.track.kind === "video") this._camEnabled = true;
3100
+ }
3101
+ this._callbacks.onTrackStarted?.(ev.track, ev.participant ? $1c83796b12dd4e49$var$dailyParticipantToParticipant(ev.participant) : undefined);
2020
3102
  }
2021
3103
  }
2022
3104
  handleTrackStopped(ev) {
2023
- if (ev.type === "screenAudio" || ev.type === "screenVideo") this._callbacks.onScreenTrackStopped?.(ev.track, ev.participant ? $28bdeb35415d61e8$var$dailyParticipantToParticipant(ev.participant) : undefined);
2024
- else this._callbacks.onTrackStopped?.(ev.track, ev.participant ? $28bdeb35415d61e8$var$dailyParticipantToParticipant(ev.participant) : undefined);
3105
+ if (ev.type === "screenAudio" || ev.type === "screenVideo") this._callbacks.onScreenTrackStopped?.(ev.track, ev.participant ? $1c83796b12dd4e49$var$dailyParticipantToParticipant(ev.participant) : undefined);
3106
+ else {
3107
+ if (ev.participant?.local) {
3108
+ if (ev.track.kind === "audio") this._micEnabled = false;
3109
+ else if (ev.track.kind === "video") this._camEnabled = false;
3110
+ }
3111
+ this._callbacks.onTrackStopped?.(ev.track, ev.participant ? $1c83796b12dd4e49$var$dailyParticipantToParticipant(ev.participant) : undefined);
3112
+ }
2025
3113
  }
2026
3114
  handleParticipantJoined(ev) {
2027
- const p = $28bdeb35415d61e8$var$dailyParticipantToParticipant(ev.participant);
3115
+ const p = $1c83796b12dd4e49$var$dailyParticipantToParticipant(ev.participant);
2028
3116
  this._callbacks.onParticipantJoined?.(p);
2029
3117
  if (p.local) return;
2030
3118
  this._botId = ev.participant.session_id;
2031
3119
  this._callbacks.onBotConnected?.(p);
2032
3120
  }
2033
3121
  handleParticipantLeft(ev) {
2034
- const p = $28bdeb35415d61e8$var$dailyParticipantToParticipant(ev.participant);
3122
+ const p = $1c83796b12dd4e49$var$dailyParticipantToParticipant(ev.participant);
2035
3123
  this._callbacks.onParticipantLeft?.(p);
2036
3124
  if (p.local) return;
2037
3125
  this._botId = "";
@@ -2046,7 +3134,7 @@ class $28bdeb35415d61e8$export$b1ca982aa1e488c1 extends (0, $jrPAn$pipecataiclie
2046
3134
  for(let i = 0; i < ids.length; i++){
2047
3135
  const id = ids[i];
2048
3136
  const level = ev.participantsAudioLevel[id];
2049
- this._callbacks.onRemoteAudioLevel?.(level, $28bdeb35415d61e8$var$dailyParticipantToParticipant(participants[id]));
3137
+ this._callbacks.onRemoteAudioLevel?.(level, $1c83796b12dd4e49$var$dailyParticipantToParticipant(participants[id]));
2050
3138
  }
2051
3139
  }
2052
3140
  handleLeftMeeting() {
@@ -2055,10 +3143,10 @@ class $28bdeb35415d61e8$export$b1ca982aa1e488c1 extends (0, $jrPAn$pipecataiclie
2055
3143
  this._callbacks.onDisconnected?.();
2056
3144
  }
2057
3145
  handleFatalError(ev) {
2058
- (0, $jrPAn$pipecataiclientjs.logger).error("Daily fatal error", ev.errorMsg);
3146
+ (0, $1clrS$pipecataiclientjs.logger).error("Daily fatal error", ev.errorMsg);
2059
3147
  this.state = "error";
2060
3148
  this._botId = "";
2061
- this._callbacks.onError?.((0, $jrPAn$pipecataiclientjs.RTVIMessage).error(ev.errorMsg, true));
3149
+ this._callbacks.onError?.((0, $1clrS$pipecataiclientjs.RTVIMessage).error(ev.errorMsg, true));
2062
3150
  }
2063
3151
  handleNonFatalError(ev) {
2064
3152
  switch(ev.type){
@@ -2068,16 +3156,16 @@ class $28bdeb35415d61e8$export$b1ca982aa1e488c1 extends (0, $jrPAn$pipecataiclie
2068
3156
  }
2069
3157
  }
2070
3158
  }
2071
- $28bdeb35415d61e8$export$b1ca982aa1e488c1.RECORDER_SAMPLE_RATE = 16000;
2072
- $28bdeb35415d61e8$export$b1ca982aa1e488c1.RECORDER_CHUNK_SIZE = 512;
2073
- const $28bdeb35415d61e8$var$dailyParticipantToParticipant = (p)=>({
3159
+ $1c83796b12dd4e49$export$b1ca982aa1e488c1.RECORDER_SAMPLE_RATE = 16000;
3160
+ $1c83796b12dd4e49$export$b1ca982aa1e488c1.RECORDER_CHUNK_SIZE = 512;
3161
+ const $1c83796b12dd4e49$var$dailyParticipantToParticipant = (p)=>({
2074
3162
  id: p.user_id,
2075
3163
  local: p.local,
2076
3164
  name: p.user_name
2077
3165
  });
2078
3166
 
2079
3167
 
2080
- $parcel$exportWildcard(module.exports, $28bdeb35415d61e8$exports);
3168
+ $parcel$exportWildcard(module.exports, $1c83796b12dd4e49$exports);
2081
3169
 
2082
3170
 
2083
3171
  //# sourceMappingURL=index.js.map