ttp-agent-sdk 2.48.2 → 2.48.7

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.
@@ -12047,7 +12047,7 @@ var TextChatSDK = /*#__PURE__*/function (_EventEmitter) {
12047
12047
 
12048
12048
  // SDK build time for debugging
12049
12049
  if (true) {
12050
- helloMessage.lastBuildTime = "2026-08-20T14:41:57.957Z";
12050
+ helloMessage.lastBuildTime = "2026-08-20T21:16:40.754Z";
12051
12051
  }
12052
12052
  try {
12053
12053
  this.ws.send(JSON.stringify(helloMessage));
@@ -21357,8 +21357,8 @@ var VoiceSDK = _v2_VoiceSDK_js__WEBPACK_IMPORTED_MODULE_0__["default"];
21357
21357
 
21358
21358
 
21359
21359
  // Version - injected at build time from package.json via webpack DefinePlugin
21360
- var VERSION = "2.48.2";
21361
- var BUILD_TIME = "2026-08-20T14:41:57.957Z";
21360
+ var VERSION = "2.48.7";
21361
+ var BUILD_TIME = "2026-08-20T21:16:40.754Z";
21362
21362
  console.log("%c TTP Agent SDK v".concat(VERSION, " (").concat(BUILD_TIME, ") "), 'background: #4f46e5; color: white; font-size: 12px; font-weight: bold; padding: 2px 6px; border-radius: 4px;');
21363
21363
 
21364
21364
  // Named exports
@@ -25569,6 +25569,49 @@ function _setPrototypeOf(t, e) { return _setPrototypeOf = Object.setPrototypeOf
25569
25569
  // so creating a new AudioContext immediately after closing the old one can fail silently.
25570
25570
  var _sharedPlayerContext = null;
25571
25571
  var _sharedPlayerSampleRate = null;
25572
+ function _sinc(x) {
25573
+ if (x === 0) return 1;
25574
+ var px = Math.PI * x;
25575
+ return Math.sin(px) / px;
25576
+ }
25577
+ function _blackman(x) {
25578
+ var n = (x + 1) / 2;
25579
+ return 0.42 - 0.5 * Math.cos(2 * Math.PI * n) + 0.08 * Math.cos(4 * Math.PI * n);
25580
+ }
25581
+
25582
+ /**
25583
+ * Windowed-sinc resampler (16 taps, anti-aliased on downsample). Used only when
25584
+ * the HTML-audio hop ended up on a low-rate context (e.g. Bluetooth hands-free
25585
+ * caps output at 16 kHz): the MediaStream → <audio> hop is not reliable unless
25586
+ * the stream honestly runs at context.sampleRate, so TTS PCM is resampled
25587
+ * before createBuffer — the same invariant ElevenLabs keeps in its
25588
+ * audioConcatProcessor worklet.
25589
+ */
25590
+ function resampleFloat32ToRate(input, fromRate, toRate) {
25591
+ if (fromRate === toRate || !input || input.length === 0) return input;
25592
+ var ratio = fromRate / toRate;
25593
+ var outLength = Math.max(1, Math.round(input.length / ratio));
25594
+ var out = new Float32Array(outLength);
25595
+ var TAPS = 16;
25596
+ var HALF = TAPS / 2;
25597
+ var cutoff = 0.92 * Math.min(1, toRate / fromRate);
25598
+ for (var i = 0; i < outLength; i++) {
25599
+ var pos = i * ratio;
25600
+ var center = Math.floor(pos);
25601
+ var sum = 0;
25602
+ var wsum = 0;
25603
+ for (var t = -HALF + 1; t <= HALF; t++) {
25604
+ var idx = center + t;
25605
+ if (idx < 0 || idx >= input.length) continue;
25606
+ var x = pos - idx;
25607
+ var w = _blackman(t / HALF) * _sinc(x * cutoff) * cutoff;
25608
+ sum += input[idx] * w;
25609
+ wsum += w;
25610
+ }
25611
+ out[i] = wsum !== 0 ? sum / wsum : 0;
25612
+ }
25613
+ return out;
25614
+ }
25572
25615
 
25573
25616
  /**
25574
25617
 
@@ -25620,6 +25663,11 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
25620
25663
  _this._mediaStreamDest = null;
25621
25664
  _this._htmlAudioRouteActive = false;
25622
25665
  _this._htmlAudioPlayOk = false;
25666
+ _this._loggedHopResample = false;
25667
+ // Greeting (and other bursts) fire many playChunk()s without await.
25668
+ // Serialize context creation so they cannot open two AudioContexts
25669
+ // at different rates in the middle of a sentence.
25670
+ _this._audioContextInitPromise = null;
25623
25671
 
25624
25672
  // Track temporary listener in waitForAudioContextReady() for cleanup
25625
25673
  _this._waitForReadyStateHandler = null;
@@ -25911,7 +25959,7 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
25911
25959
  key: "prepareChunk",
25912
25960
  value: (function () {
25913
25961
  var _prepareChunk = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2(pcmData) {
25914
- var _this$outputFormat2, processedData, padded, int16Array, float32Array, NORMALIZATION, length, i, audioDataSampleRate, audioBuffer, actualDuration, _t;
25962
+ var _this$outputFormat2, processedData, padded, int16Array, float32Array, NORMALIZATION, length, i, audioDataSampleRate, playback, audioBuffer, actualDuration, _t;
25915
25963
  return _regenerator().w(function (_context2) {
25916
25964
  while (1) switch (_context2.p = _context2.n) {
25917
25965
  case 0:
@@ -25960,11 +26008,12 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
25960
26008
 
25961
26009
  // Create audio buffer with the ACTUAL sample rate of the audio data
25962
26010
  audioDataSampleRate = ((_this$outputFormat2 = this.outputFormat) === null || _this$outputFormat2 === void 0 ? void 0 : _this$outputFormat2.sampleRate) || this.audioContext.sampleRate;
26011
+ playback = this._honestRateSamples(float32Array, audioDataSampleRate);
25963
26012
  audioBuffer = this.audioContext.createBuffer(1,
25964
26013
  // mono
25965
26014
 
25966
- float32Array.length, audioDataSampleRate);
25967
- audioBuffer.getChannelData(0).set(float32Array);
26015
+ playback.samples.length, playback.sampleRate);
26016
+ audioBuffer.getChannelData(0).set(playback.samples);
25968
26017
 
25969
26018
  // Wall-clock duration is sampleCount / TTS rate (audioBuffer.duration).
25970
26019
  // Dividing by contextSampleRate when the context is 48 kHz and TTS is
@@ -26331,7 +26380,7 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
26331
26380
  value: (function () {
26332
26381
  var _processPcmQueue = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee4() {
26333
26382
  var _this5 = this;
26334
- var _this$outputFormat3, _this$outputFormat4, pcmData, processedData, padded, int16Array, float32Array, NORMALIZATION, length, i, audioDataSampleRate, contextSampleRate, audioBuffer, source, currentTime, actualDuration, startTime, _t3;
26383
+ var _this$outputFormat3, _this$outputFormat4, pcmData, processedData, padded, int16Array, float32Array, NORMALIZATION, length, i, audioDataSampleRate, contextSampleRate, playback, audioBuffer, source, currentTime, actualDuration, startTime, _t3;
26335
26384
  return _regenerator().w(function (_context5) {
26336
26385
  while (1) switch (_context5.p = _context5.n) {
26337
26386
  case 0:
@@ -26398,10 +26447,11 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
26398
26447
  } else if (this.scheduledBuffers < 3) {
26399
26448
  console.log("\uD83C\uDFB5 AudioPlayer: Creating buffer at ".concat(audioDataSampleRate, "Hz (AudioContext: ").concat(contextSampleRate, "Hz)"));
26400
26449
  }
26450
+ playback = this._honestRateSamples(float32Array, audioDataSampleRate);
26401
26451
  audioBuffer = this.audioContext.createBuffer(1,
26402
26452
  // mono
26403
- float32Array.length, audioDataSampleRate);
26404
- audioBuffer.getChannelData(0).set(float32Array);
26453
+ playback.samples.length, playback.sampleRate);
26454
+ audioBuffer.getChannelData(0).set(playback.samples);
26405
26455
 
26406
26456
  // Schedule playback with seamless timing
26407
26457
  source = this.audioContext.createBufferSource();
@@ -27057,6 +27107,34 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
27057
27107
  value: function _isHardwarePlaybackRate(rate) {
27058
27108
  return typeof rate === 'number' && rate >= 44100;
27059
27109
  }
27110
+
27111
+ /**
27112
+ * HTML-hop mismatch guard. The MediaStreamDestination → <audio> hop is only
27113
+ * reliable when the context runs at a hardware rate; if Chrome still gave a
27114
+ * low-rate context (e.g. Bluetooth hands-free output), resample the TTS audio
27115
+ * to the context rate ourselves so the stream honestly runs at
27116
+ * context.sampleRate. Destination playback is untouched — Web Audio resamples
27117
+ * correctly on that path.
27118
+ */
27119
+ }, {
27120
+ key: "_honestRateSamples",
27121
+ value: function _honestRateSamples(float32Array, audioDataSampleRate) {
27122
+ var contextRate = this.audioContext.sampleRate;
27123
+ if (this._htmlHopNeedsHardwareRate() && !this._isHardwarePlaybackRate(contextRate) && audioDataSampleRate !== contextRate) {
27124
+ if (!this._loggedHopResample) {
27125
+ this._loggedHopResample = true;
27126
+ console.warn("\u26A0\uFE0F AudioPlayer: HTML hop on a ".concat(contextRate, "Hz context \u2014 resampling TTS ").concat(audioDataSampleRate, "Hz \u2192 ").concat(contextRate, "Hz in the player"));
27127
+ }
27128
+ return {
27129
+ samples: resampleFloat32ToRate(float32Array, audioDataSampleRate, contextRate),
27130
+ sampleRate: contextRate
27131
+ };
27132
+ }
27133
+ return {
27134
+ samples: float32Array,
27135
+ sampleRate: audioDataSampleRate
27136
+ };
27137
+ }
27060
27138
  }, {
27061
27139
  key: "getHtmlAudioPlaybackInfo",
27062
27140
  value: function getHtmlAudioPlaybackInfo() {
@@ -27179,14 +27257,43 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
27179
27257
  value: (function () {
27180
27258
  var _initializeAudioContext = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee7() {
27181
27259
  var _this8 = this;
27182
- var ttsSampleRate, useHardwareRate, desiredSampleRate, contextFits, canReuseShared, setupAfterResume, ctxOpts, _t4;
27183
27260
  return _regenerator().w(function (_context8) {
27184
- while (1) switch (_context8.p = _context8.n) {
27261
+ while (1) switch (_context8.n) {
27262
+ case 0:
27263
+ if (!this._audioContextInitPromise) {
27264
+ _context8.n = 1;
27265
+ break;
27266
+ }
27267
+ return _context8.a(2, this._audioContextInitPromise);
27268
+ case 1:
27269
+ this._audioContextInitPromise = this._initializeAudioContextImpl().finally(function () {
27270
+ _this8._audioContextInitPromise = null;
27271
+ });
27272
+ return _context8.a(2, this._audioContextInitPromise);
27273
+ }
27274
+ }, _callee7, this);
27275
+ }));
27276
+ function initializeAudioContext() {
27277
+ return _initializeAudioContext.apply(this, arguments);
27278
+ }
27279
+ return initializeAudioContext;
27280
+ }())
27281
+ }, {
27282
+ key: "_initializeAudioContextImpl",
27283
+ value: function () {
27284
+ var _initializeAudioContextImpl2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee8() {
27285
+ var _this9 = this;
27286
+ var ttsSampleRate, useHardwareRate, desiredSampleRate, contextFits, canReuseShared, setupAfterResume, ctxOpts, _t4;
27287
+ return _regenerator().w(function (_context9) {
27288
+ while (1) switch (_context9.p = _context9.n) {
27185
27289
  case 0:
27186
27290
  ttsSampleRate = this._ttsSampleRate();
27187
- useHardwareRate = this._htmlHopNeedsHardwareRate(); // Destination path: match TTS (24 kHz). HTML last-hop: omit so the
27188
- // context (and MediaStream) run at the device rate usually 48 kHz.
27189
- desiredSampleRate = useHardwareRate ? null : ttsSampleRate;
27291
+ useHardwareRate = this._htmlHopNeedsHardwareRate(); // Destination path: match TTS (24 kHz). HTML last-hop: request the standard
27292
+ // hardware rate explicitly. Omitting it lets Chrome inherit whatever rate is
27293
+ // already active on the page (the widget opens the 16 kHz mic context before
27294
+ // the player), and the MediaStream → <audio> hop then mis-clocks — heard as
27295
+ // chipmunk-fast or half-speed speech.
27296
+ desiredSampleRate = useHardwareRate ? 48000 : ttsSampleRate;
27190
27297
  if (!useHardwareRate && ![24000, 44100, 48000].includes(desiredSampleRate)) {
27191
27298
  console.log("\u2139\uFE0F AudioPlayer: Backend requested ".concat(desiredSampleRate, "Hz, but browser may resample"));
27192
27299
  console.log(" Consider requesting 24000Hz, 44100Hz, or 48000Hz from backend to reduce resampling");
@@ -27196,27 +27303,27 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
27196
27303
  _sharedPlayerSampleRate = null;
27197
27304
  }
27198
27305
  contextFits = function contextFits(rate) {
27199
- if (useHardwareRate) return _this8._isHardwarePlaybackRate(rate);
27306
+ if (useHardwareRate) return _this9._isHardwarePlaybackRate(rate);
27200
27307
  return Math.abs(rate - desiredSampleRate) <= 100;
27201
27308
  }; // Check if current instance AudioContext exists and matches
27202
27309
  if (!this.audioContext) {
27203
- _context8.n = 3;
27310
+ _context9.n = 3;
27204
27311
  break;
27205
27312
  }
27206
27313
  if (!(this.audioContext.state === 'closed')) {
27207
- _context8.n = 1;
27314
+ _context9.n = 1;
27208
27315
  break;
27209
27316
  }
27210
27317
  this._invalidateClosedAudioContext();
27211
- _context8.n = 3;
27318
+ _context9.n = 3;
27212
27319
  break;
27213
27320
  case 1:
27214
27321
  if (!contextFits(this.audioContext.sampleRate)) {
27215
- _context8.n = 2;
27322
+ _context9.n = 2;
27216
27323
  break;
27217
27324
  }
27218
27325
  this._ensureHtmlAudioPlaying();
27219
- return _context8.a(2);
27326
+ return _context9.a(2);
27220
27327
  case 2:
27221
27328
  console.warn("\u26A0\uFE0F AudioPlayer: AudioContext sample rate (".concat(this.audioContext.sampleRate, "Hz) doesn't match playback hop, recreating..."));
27222
27329
  this.stopImmediate();
@@ -27227,46 +27334,46 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
27227
27334
  // causing newly created AudioContexts to fail silently.
27228
27335
  canReuseShared = _sharedPlayerContext && _sharedPlayerContext.state !== 'closed' && contextFits(_sharedPlayerContext.sampleRate);
27229
27336
  if (!canReuseShared) {
27230
- _context8.n = 8;
27337
+ _context9.n = 8;
27231
27338
  break;
27232
27339
  }
27233
27340
  console.log("\u267B\uFE0F AudioPlayer: Reusing shared AudioContext at ".concat(_sharedPlayerContext.sampleRate, "Hz (iOS-safe)"));
27234
27341
  this.audioContext = _sharedPlayerContext;
27235
27342
  setupAfterResume = function setupAfterResume() {
27236
- _this8.setupAudioContextStateMonitoring();
27237
- if (_this8.gainNode) {
27343
+ _this9.setupAudioContextStateMonitoring();
27344
+ if (_this9.gainNode) {
27238
27345
  try {
27239
- _this8.gainNode.disconnect();
27346
+ _this9.gainNode.disconnect();
27240
27347
  } catch (e) {
27241
27348
  console.warn('⚠️ AudioPlayer: Error disconnecting old GainNode:', e);
27242
27349
  }
27243
27350
  }
27244
- _this8.gainNode = _this8.audioContext.createGain();
27245
- _this8.gainNode.gain.value = 1.0;
27246
- _this8._connectGainToOutput();
27247
- if (!_this8._audioContextPrimed) {
27248
- _this8._primeAudioContext();
27351
+ _this9.gainNode = _this9.audioContext.createGain();
27352
+ _this9.gainNode.gain.value = 1.0;
27353
+ _this9._connectGainToOutput();
27354
+ if (!_this9._audioContextPrimed) {
27355
+ _this9._primeAudioContext();
27249
27356
  }
27250
27357
  };
27251
27358
  if (!(this.audioContext.state === 'suspended')) {
27252
- _context8.n = 7;
27359
+ _context9.n = 7;
27253
27360
  break;
27254
27361
  }
27255
- _context8.p = 4;
27256
- _context8.n = 5;
27362
+ _context9.p = 4;
27363
+ _context9.n = 5;
27257
27364
  return this.audioContext.resume();
27258
27365
  case 5:
27259
- _context8.n = 7;
27366
+ _context9.n = 7;
27260
27367
  break;
27261
27368
  case 6:
27262
- _context8.p = 6;
27263
- _t4 = _context8.v;
27369
+ _context9.p = 6;
27370
+ _t4 = _context9.v;
27264
27371
  console.warn('⚠️ AudioPlayer: Error resuming shared context:', _t4);
27265
27372
  case 7:
27266
27373
  setupAfterResume();
27267
- return _context8.a(2);
27374
+ return _context9.a(2);
27268
27375
  case 8:
27269
- console.log("\uD83C\uDFB5 AudioPlayer: Creating AudioContext (tts=".concat(ttsSampleRate, "Hz, htmlHop=").concat(useHardwareRate, ", requested=").concat(desiredSampleRate || 'hardware default', ")"));
27376
+ console.log("\uD83C\uDFB5 AudioPlayer: Creating AudioContext (tts=".concat(ttsSampleRate, "Hz, htmlHop=").concat(useHardwareRate, ", requested=").concat(desiredSampleRate, "Hz)"));
27270
27377
 
27271
27378
  // Close old shared context if sample rate changed
27272
27379
  if (_sharedPlayerContext && _sharedPlayerContext.state !== 'closed') {
@@ -27291,7 +27398,9 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
27291
27398
  _sharedPlayerSampleRate = this.audioContext.sampleRate;
27292
27399
  console.log("\u2705 AudioContext created at ".concat(this.audioContext.sampleRate, "Hz (tts=").concat(ttsSampleRate, "Hz, htmlHop=").concat(useHardwareRate, ")"));
27293
27400
  if (useHardwareRate && !this._isHardwarePlaybackRate(this.audioContext.sampleRate)) {
27294
- console.warn("\u26A0\uFE0F AudioPlayer: HTML hop expected \u226544.1 kHz context, got ".concat(this.audioContext.sampleRate, "Hz"));
27401
+ // The hop stays on; _honestRateSamples resamples TTS to the context rate
27402
+ // per chunk so the MediaStream honestly runs at context.sampleRate.
27403
+ console.warn("\u26A0\uFE0F AudioPlayer: HTML hop got ".concat(this.audioContext.sampleRate, "Hz (<44.1 kHz) \u2014 resampling TTS to the context rate in the player"));
27295
27404
  } else if (!useHardwareRate && Math.abs(this.audioContext.sampleRate - desiredSampleRate) > 100) {
27296
27405
  console.warn("\u26A0\uFE0F AudioPlayer: Browser sample rate ".concat(this.audioContext.sampleRate, "Hz \u2260 requested ").concat(desiredSampleRate, "Hz; Web Audio will resample"));
27297
27406
  }
@@ -27315,34 +27424,33 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
27315
27424
  this._primeAudioContext();
27316
27425
  }
27317
27426
  case 9:
27318
- return _context8.a(2);
27427
+ return _context9.a(2);
27319
27428
  }
27320
- }, _callee7, this, [[4, 6]]);
27429
+ }, _callee8, this, [[4, 6]]);
27321
27430
  }));
27322
- function initializeAudioContext() {
27323
- return _initializeAudioContext.apply(this, arguments);
27431
+ function _initializeAudioContextImpl() {
27432
+ return _initializeAudioContextImpl2.apply(this, arguments);
27324
27433
  }
27325
- return initializeAudioContext;
27434
+ return _initializeAudioContextImpl;
27326
27435
  }()
27327
27436
  /**
27328
27437
  * Prime AudioContext with silent buffer to initialize Android hardware
27329
27438
  * This prevents the first audio frame from being cut off on Android devices
27330
27439
  */
27331
- )
27332
27440
  }, {
27333
27441
  key: "_primeAudioContext",
27334
27442
  value: (function () {
27335
- var _primeAudioContext2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee8() {
27443
+ var _primeAudioContext2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee9() {
27336
27444
  var sampleRate, silentBuffer, source, _t5;
27337
- return _regenerator().w(function (_context9) {
27338
- while (1) switch (_context9.p = _context9.n) {
27445
+ return _regenerator().w(function (_context0) {
27446
+ while (1) switch (_context0.p = _context0.n) {
27339
27447
  case 0:
27340
- _context9.p = 0;
27448
+ _context0.p = 0;
27341
27449
  if (!(!this.audioContext || this._audioContextPrimed)) {
27342
- _context9.n = 1;
27450
+ _context0.n = 1;
27343
27451
  break;
27344
27452
  }
27345
- return _context9.a(2);
27453
+ return _context0.a(2);
27346
27454
  case 1:
27347
27455
  sampleRate = this.audioContext.sampleRate;
27348
27456
  silentBuffer = this.audioContext.createBuffer(1, sampleRate * 0.15, sampleRate);
@@ -27353,23 +27461,23 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
27353
27461
  source.connect(this.gainNode || this.audioContext.destination);
27354
27462
  source.start();
27355
27463
  this._ensureHtmlAudioPlaying();
27356
- _context9.n = 2;
27464
+ _context0.n = 2;
27357
27465
  return new Promise(function (resolve) {
27358
27466
  return setTimeout(resolve, 150);
27359
27467
  });
27360
27468
  case 2:
27361
27469
  this._audioContextPrimed = true;
27362
27470
  console.log('✅ AudioPlayer: Audio hardware primed with silent buffer');
27363
- _context9.n = 4;
27471
+ _context0.n = 4;
27364
27472
  break;
27365
27473
  case 3:
27366
- _context9.p = 3;
27367
- _t5 = _context9.v;
27474
+ _context0.p = 3;
27475
+ _t5 = _context0.v;
27368
27476
  console.error('❌ AudioPlayer: Audio priming failed:', _t5);
27369
27477
  case 4:
27370
- return _context9.a(2);
27478
+ return _context0.a(2);
27371
27479
  }
27372
- }, _callee8, this, [[0, 3]]);
27480
+ }, _callee9, this, [[0, 3]]);
27373
27481
  }));
27374
27482
  function _primeAudioContext() {
27375
27483
  return _primeAudioContext2.apply(this, arguments);
@@ -27436,7 +27544,7 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
27436
27544
  * Handles mic permission grants, tab switching, browser suspension, etc.
27437
27545
  */
27438
27546
  function setupAudioContextStateMonitoring() {
27439
- var _this9 = this;
27547
+ var _this0 = this;
27440
27548
  if (!this.audioContext) {
27441
27549
  return;
27442
27550
  }
@@ -27449,38 +27557,38 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
27449
27557
  // Create handler that references this.audioContext dynamically
27450
27558
  this._audioContextStateChangeHandler = function () {
27451
27559
  // Null check required because audioContext may be cleaned up while handler is queued
27452
- if (!_this9.audioContext) {
27560
+ if (!_this0.audioContext) {
27453
27561
  console.warn('⚠️ AudioPlayer: State change handler fired but AudioContext is null');
27454
27562
  return;
27455
27563
  }
27456
- console.log("\uD83C\uDFB5 AudioPlayer: AudioContext state changed to: ".concat(_this9.audioContext.state));
27457
- if (_this9.audioContext.state === 'running') {
27458
- _this9._ensureHtmlAudioPlaying();
27564
+ console.log("\uD83C\uDFB5 AudioPlayer: AudioContext state changed to: ".concat(_this0.audioContext.state));
27565
+ if (_this0.audioContext.state === 'running') {
27566
+ _this0._ensureHtmlAudioPlaying();
27459
27567
  }
27460
- if (_this9.audioContext.state === 'suspended' && _this9.isPlaying) {
27568
+ if (_this0.audioContext.state === 'suspended' && _this0.isPlaying) {
27461
27569
  // AudioContext was suspended during playback (tab switch, mic permission, etc.)
27462
27570
  console.warn('⚠️ AudioPlayer: AudioContext suspended during playback');
27463
27571
  // Note: Playback will pause automatically, but we should handle queue processing
27464
27572
  // The state change will be handled when we try to process next frame
27465
- } else if (_this9.audioContext.state === 'running' && !_this9.isPlaying && (_this9.audioQueue.length > 0 || _this9.pcmChunkQueue.length > 0 || _this9.preparedBuffer.length > 0)) {
27573
+ } else if (_this0.audioContext.state === 'running' && !_this0.isPlaying && (_this0.audioQueue.length > 0 || _this0.pcmChunkQueue.length > 0 || _this0.preparedBuffer.length > 0)) {
27466
27574
  // AudioContext resumed and we have queued frames
27467
27575
  // This handles: mic permission grant, tab switching back, browser resume, etc.
27468
27576
  console.log('✅ AudioPlayer: AudioContext resumed - resuming queue processing');
27469
27577
 
27470
27578
  // Resume queue processing if we have frames
27471
- if (_this9.audioQueue.length > 0 && !_this9.isProcessingQueue) {
27579
+ if (_this0.audioQueue.length > 0 && !_this0.isProcessingQueue) {
27472
27580
  setTimeout(function () {
27473
- return _this9.processQueue();
27581
+ return _this0.processQueue();
27474
27582
  }, 50);
27475
27583
  }
27476
- if (_this9.pcmChunkQueue.length > 0 && !_this9.isProcessingPcmQueue) {
27584
+ if (_this0.pcmChunkQueue.length > 0 && !_this0.isProcessingPcmQueue) {
27477
27585
  setTimeout(function () {
27478
- return _this9.processPcmQueue();
27586
+ return _this0.processPcmQueue();
27479
27587
  }, 50);
27480
27588
  }
27481
- if (_this9.preparedBuffer.length > 0 && !_this9.isSchedulingFrames) {
27589
+ if (_this0.preparedBuffer.length > 0 && !_this0.isSchedulingFrames) {
27482
27590
  setTimeout(function () {
27483
- return _this9.scheduleFrames();
27591
+ return _this0.scheduleFrames();
27484
27592
  }, 50);
27485
27593
  }
27486
27594
  }
@@ -27498,49 +27606,49 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
27498
27606
  }, {
27499
27607
  key: "processQueue",
27500
27608
  value: (function () {
27501
- var _processQueue = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee9() {
27502
- var _this0 = this;
27609
+ var _processQueue = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee0() {
27610
+ var _this1 = this;
27503
27611
  var audioBlob, wasFirstPlay, audioContext, arrayBuffer, audioBuffer, shouldEmitStart, source, _t6;
27504
- return _regenerator().w(function (_context0) {
27505
- while (1) switch (_context0.p = _context0.n) {
27612
+ return _regenerator().w(function (_context1) {
27613
+ while (1) switch (_context1.p = _context1.n) {
27506
27614
  case 0:
27507
27615
  if (!this._isStopped) {
27508
- _context0.n = 1;
27616
+ _context1.n = 1;
27509
27617
  break;
27510
27618
  }
27511
27619
  console.log('🛑 AudioPlayer: Not processing queue - playback was stopped (barge-in)');
27512
- return _context0.a(2);
27620
+ return _context1.a(2);
27513
27621
  case 1:
27514
27622
  if (!(this.isProcessingQueue || this.audioQueue.length === 0)) {
27515
- _context0.n = 2;
27623
+ _context1.n = 2;
27516
27624
  break;
27517
27625
  }
27518
- return _context0.a(2);
27626
+ return _context1.a(2);
27519
27627
  case 2:
27520
27628
  this.isProcessingQueue = true;
27521
27629
  this._ensureHtmlAudioPlaying();
27522
27630
  audioBlob = this.audioQueue.shift();
27523
27631
  if (audioBlob) {
27524
- _context0.n = 3;
27632
+ _context1.n = 3;
27525
27633
  break;
27526
27634
  }
27527
27635
  this.isProcessingQueue = false;
27528
- return _context0.a(2);
27636
+ return _context1.a(2);
27529
27637
  case 3:
27530
- _context0.p = 3;
27638
+ _context1.p = 3;
27531
27639
  wasFirstPlay = !this.isPlaying && this.currentSource === null; // Ensure context exists and is running (handles lazy init + suspended shared context)
27532
- _context0.n = 4;
27640
+ _context1.n = 4;
27533
27641
  return this.waitForAudioContextReady();
27534
27642
  case 4:
27535
27643
  audioContext = this.audioContext; // Decode audio
27536
- _context0.n = 5;
27644
+ _context1.n = 5;
27537
27645
  return audioBlob.arrayBuffer();
27538
27646
  case 5:
27539
- arrayBuffer = _context0.v;
27540
- _context0.n = 6;
27647
+ arrayBuffer = _context1.v;
27648
+ _context1.n = 6;
27541
27649
  return audioContext.decodeAudioData(arrayBuffer);
27542
27650
  case 6:
27543
- audioBuffer = _context0.v;
27651
+ audioBuffer = _context1.v;
27544
27652
  shouldEmitStart = wasFirstPlay && !this.isPlaying && this.currentSource === null; // Create source
27545
27653
  source = audioContext.createBufferSource();
27546
27654
  source.buffer = audioBuffer;
@@ -27559,22 +27667,22 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
27559
27667
  // Handle end
27560
27668
 
27561
27669
  source.onended = function () {
27562
- _this0.currentSource = null;
27563
- _this0.isProcessingQueue = false;
27670
+ _this1.currentSource = null;
27671
+ _this1.isProcessingQueue = false;
27564
27672
 
27565
27673
  // Process next chunk
27566
27674
 
27567
- if (_this0.audioQueue.length > 0) {
27675
+ if (_this1.audioQueue.length > 0) {
27568
27676
  setTimeout(function () {
27569
- return _this0.processQueue();
27677
+ return _this1.processQueue();
27570
27678
  }, 50);
27571
27679
  } else {
27572
27680
  // No more chunks - stop after delay
27573
27681
 
27574
27682
  setTimeout(function () {
27575
- if (_this0.audioQueue.length === 0 && !_this0.currentSource) {
27576
- _this0.isPlaying = false;
27577
- _this0.emit('playbackStopped');
27683
+ if (_this1.audioQueue.length === 0 && !_this1.currentSource) {
27684
+ _this1.isPlaying = false;
27685
+ _this1.emit('playbackStopped');
27578
27686
  }
27579
27687
  }, 100);
27580
27688
  }
@@ -27583,11 +27691,11 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
27583
27691
  // Start playback - AudioContext should now be fully ready
27584
27692
 
27585
27693
  source.start();
27586
- _context0.n = 8;
27694
+ _context1.n = 8;
27587
27695
  break;
27588
27696
  case 7:
27589
- _context0.p = 7;
27590
- _t6 = _context0.v;
27697
+ _context1.p = 7;
27698
+ _t6 = _context1.v;
27591
27699
  console.error('❌ AudioPlayer v2: Error processing queue:', _t6);
27592
27700
  this.currentSource = null;
27593
27701
  this.emit('playbackError', _t6);
@@ -27597,7 +27705,7 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
27597
27705
  if (this.audioQueue.length > 0) {
27598
27706
  this.isProcessingQueue = false;
27599
27707
  setTimeout(function () {
27600
- return _this0.processQueue();
27708
+ return _this1.processQueue();
27601
27709
  }, 100);
27602
27710
  } else {
27603
27711
  this.isPlaying = false;
@@ -27605,9 +27713,9 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
27605
27713
  this.emit('playbackStopped');
27606
27714
  }
27607
27715
  case 8:
27608
- return _context0.a(2);
27716
+ return _context1.a(2);
27609
27717
  }
27610
- }, _callee9, this, [[3, 7]]);
27718
+ }, _callee0, this, [[3, 7]]);
27611
27719
  }));
27612
27720
  function processQueue() {
27613
27721
  return _processQueue.apply(this, arguments);
@@ -27820,7 +27928,7 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
27820
27928
  }, {
27821
27929
  key: "markNewSentence",
27822
27930
  value: function markNewSentence(text, synced, segmentId) {
27823
- var _this1 = this;
27931
+ var _this10 = this;
27824
27932
  var wasStopped = this._isStopped;
27825
27933
  var isCurrentlyPlaying = this.isPlaying || this.scheduledSources.size > 0;
27826
27934
 
@@ -27879,34 +27987,34 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
27879
27987
  var sentenceText = text; // Capture for timeout callback
27880
27988
  this._emptySentenceTimeout = setTimeout(function () {
27881
27989
  // Check if this sentence still has no chunks after timeout
27882
- if (_this1.pendingSentenceText === sentenceText && _this1.scheduledBuffers === 0 && _this1.preparedBuffer.length === 0 && _this1.pcmChunkQueue.length === 0 && !_this1._isStopped) {
27990
+ if (_this10.pendingSentenceText === sentenceText && _this10.scheduledBuffers === 0 && _this10.preparedBuffer.length === 0 && _this10.pcmChunkQueue.length === 0 && !_this10._isStopped) {
27883
27991
  console.warn("\u26A0\uFE0F AudioPlayer: Empty sentence detected after 5s timeout - no chunks received for: \"".concat(sentenceText.substring(0, 40), "...\""));
27884
27992
  // If this empty sentence carried a segment id, report it done (nothing was heard) and
27885
27993
  // adopt it as current so the coarse stop below matches the backend's last-sent id.
27886
- if (_this1.pendingSegmentId != null) {
27887
- var emptySegId = _this1.pendingSegmentId;
27888
- _this1.currentSegmentId = emptySegId;
27889
- _this1.pendingSegmentId = null;
27890
- _this1.emit('segmentDone', {
27994
+ if (_this10.pendingSegmentId != null) {
27995
+ var emptySegId = _this10.pendingSegmentId;
27996
+ _this10.currentSegmentId = emptySegId;
27997
+ _this10.pendingSegmentId = null;
27998
+ _this10.emit('segmentDone', {
27891
27999
  segmentId: emptySegId,
27892
28000
  status: 'finished',
27893
28001
  playedMs: 0
27894
28002
  });
27895
28003
  }
27896
28004
  // Clear pending sentence to unblock next sentence
27897
- if (_this1.pendingSentenceText === sentenceText) {
27898
- _this1.pendingSentenceText = null;
28005
+ if (_this10.pendingSentenceText === sentenceText) {
28006
+ _this10.pendingSentenceText = null;
27899
28007
  }
27900
28008
  // Emit playbackStopped to allow next sentence to start
27901
28009
  // Only if we're not currently playing (to avoid interrupting real playback)
27902
- if (!_this1.isPlaying && _this1.scheduledSources.size === 0) {
28010
+ if (!_this10.isPlaying && _this10.scheduledSources.size === 0) {
27903
28011
  console.log('🛑 AudioPlayer: Emitting playbackStopped for empty sentence timeout');
27904
- _this1.emit('playbackStopped', {
27905
- segmentId: _this1.currentSegmentId
28012
+ _this10.emit('playbackStopped', {
28013
+ segmentId: _this10.currentSegmentId
27906
28014
  });
27907
28015
  }
27908
28016
  }
27909
- _this1._emptySentenceTimeout = null;
28017
+ _this10._emptySentenceTimeout = null;
27910
28018
  }, 5000); // 5 second timeout - adjust based on expected chunk arrival rate
27911
28019
  }
27912
28020
 
@@ -27916,14 +28024,14 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
27916
28024
  }, {
27917
28025
  key: "startTranscriptChecker",
27918
28026
  value: function startTranscriptChecker() {
27919
- var _this10 = this;
28027
+ var _this11 = this;
27920
28028
  if (this.isCheckingTranscripts) return;
27921
28029
  this.isCheckingTranscripts = true;
27922
28030
  console.log('📝 AudioPlayer: Transcript checker started');
27923
28031
  var _checkLoop = function checkLoop() {
27924
- if (!_this10.isCheckingTranscripts || !_this10.audioContext) return;
27925
- var currentTime = _this10.audioContext.currentTime;
27926
- var _iterator2 = _createForOfIteratorHelper(_this10.sentenceTimings),
28032
+ if (!_this11.isCheckingTranscripts || !_this11.audioContext) return;
28033
+ var currentTime = _this11.audioContext.currentTime;
28034
+ var _iterator2 = _createForOfIteratorHelper(_this11.sentenceTimings),
27927
28035
  _step2;
27928
28036
  try {
27929
28037
  for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
@@ -27937,13 +28045,13 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
27937
28045
  eventData.synced = _timing.synced;
27938
28046
  }
27939
28047
  console.log("\uD83D\uDCDD AudioPlayer: Display transcript at ".concat(currentTime.toFixed(3), "s: \"").concat(_timing.text.substring(0, 40), "...\" (synced: ").concat(_timing.synced ? _timing.synced.length : 0, ")"));
27940
- _this10.emit('transcriptDisplay', eventData);
28048
+ _this11.emit('transcriptDisplay', eventData);
27941
28049
  }
27942
28050
  // Per-segment natural finish: this segment's audio window has fully elapsed.
27943
28051
  if (!_timing.doneReported && _timing.endTime != null && currentTime >= _timing.endTime) {
27944
28052
  _timing.doneReported = true;
27945
28053
  var _playedMs = Math.round((_timing.endTime - _timing.startTime) * 1000);
27946
- _this10.emit('segmentDone', {
28054
+ _this11.emit('segmentDone', {
27947
28055
  segmentId: _timing.segmentId,
27948
28056
  status: 'finished',
27949
28057
  playedMs: _playedMs
@@ -27955,12 +28063,12 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
27955
28063
  } finally {
27956
28064
  _iterator2.f();
27957
28065
  }
27958
- if (_this10.isPlaying || _this10.scheduledBuffers > 0) {
28066
+ if (_this11.isPlaying || _this11.scheduledBuffers > 0) {
27959
28067
  requestAnimationFrame(_checkLoop);
27960
28068
  } else {
27961
28069
  // Playback drained naturally — flush any segment whose finish tick we may have missed
27962
28070
  // (the last buffer's onended can flip isPlaying=false before this loop's next tick).
27963
- var _iterator3 = _createForOfIteratorHelper(_this10.sentenceTimings),
28071
+ var _iterator3 = _createForOfIteratorHelper(_this11.sentenceTimings),
27964
28072
  _step3;
27965
28073
  try {
27966
28074
  for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
@@ -27969,7 +28077,7 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
27969
28077
  timing.doneReported = true;
27970
28078
  var end = timing.endTime != null ? timing.endTime : timing.startTime;
27971
28079
  var playedMs = Math.round((end - timing.startTime) * 1000);
27972
- _this10.emit('segmentDone', {
28080
+ _this11.emit('segmentDone', {
27973
28081
  segmentId: timing.segmentId,
27974
28082
  status: 'finished',
27975
28083
  playedMs: playedMs
@@ -27981,7 +28089,7 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
27981
28089
  } finally {
27982
28090
  _iterator3.f();
27983
28091
  }
27984
- _this10.isCheckingTranscripts = false;
28092
+ _this11.isCheckingTranscripts = false;
27985
28093
  console.log('📝 AudioPlayer: Transcript checker stopped');
27986
28094
  }
27987
28095
  };
@@ -28012,43 +28120,43 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
28012
28120
  }, {
28013
28121
  key: "resumeAudioContext",
28014
28122
  value: (function () {
28015
- var _resumeAudioContext = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee0() {
28123
+ var _resumeAudioContext = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee1() {
28016
28124
  var _t7;
28017
- return _regenerator().w(function (_context1) {
28018
- while (1) switch (_context1.p = _context1.n) {
28125
+ return _regenerator().w(function (_context10) {
28126
+ while (1) switch (_context10.p = _context10.n) {
28019
28127
  case 0:
28020
28128
  if (!(!this.audioContext || this.audioContext.state === 'closed')) {
28021
- _context1.n = 2;
28129
+ _context10.n = 2;
28022
28130
  break;
28023
28131
  }
28024
- _context1.n = 1;
28132
+ _context10.n = 1;
28025
28133
  return this.initializeAudioContext();
28026
28134
  case 1:
28027
- _context1.n = 6;
28135
+ _context10.n = 6;
28028
28136
  break;
28029
28137
  case 2:
28030
28138
  if (!(this.audioContext.state === 'suspended')) {
28031
- _context1.n = 6;
28139
+ _context10.n = 6;
28032
28140
  break;
28033
28141
  }
28034
- _context1.p = 3;
28035
- _context1.n = 4;
28142
+ _context10.p = 3;
28143
+ _context10.n = 4;
28036
28144
  return this.audioContext.resume();
28037
28145
  case 4:
28038
28146
  console.log('✅ AudioPlayer v2: AudioContext resumed after mic permission');
28039
- _context1.n = 6;
28147
+ _context10.n = 6;
28040
28148
  break;
28041
28149
  case 5:
28042
- _context1.p = 5;
28043
- _t7 = _context1.v;
28150
+ _context10.p = 5;
28151
+ _t7 = _context10.v;
28044
28152
  console.warn('⚠️ AudioPlayer v2: Failed to resume AudioContext:', _t7);
28045
28153
  case 6:
28046
- _context1.n = 7;
28154
+ _context10.n = 7;
28047
28155
  return this.waitForAudioContextReady();
28048
28156
  case 7:
28049
- return _context1.a(2);
28157
+ return _context10.a(2);
28050
28158
  }
28051
- }, _callee0, this, [[3, 5]]);
28159
+ }, _callee1, this, [[3, 5]]);
28052
28160
  }));
28053
28161
  function resumeAudioContext() {
28054
28162
  return _resumeAudioContext.apply(this, arguments);
@@ -29141,7 +29249,7 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
29141
29249
  // iOS in-app webviews lack "Safari" in the UA (real Safari always has it).
29142
29250
  var webview = isAndroid && (/\bwv\b/.test(ua) || /Version\/[\d.]+.*Chrome/.test(ua)) || isIos && !/Safari/i.test(ua) || false;
29143
29251
  var env = {
29144
- sdkVersion: true ? "2.48.2" : 0,
29252
+ sdkVersion: true ? "2.48.7" : 0,
29145
29253
  ua: ua,
29146
29254
  platform: (uaData === null || uaData === void 0 ? void 0 : uaData.platform) || navigator.platform || '',
29147
29255
  mobile: (_uaData$mobile = uaData === null || uaData === void 0 ? void 0 : uaData.mobile) !== null && _uaData$mobile !== void 0 ? _uaData$mobile : isAndroid || isIos,
@@ -29156,7 +29264,7 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
29156
29264
  } catch (e) {
29157
29265
  console.warn('⚠️ VoiceSDK v2: Failed to build client env:', e);
29158
29266
  return {
29159
- sdkVersion: true ? "2.48.2" : 0
29267
+ sdkVersion: true ? "2.48.7" : 0
29160
29268
  };
29161
29269
  }
29162
29270
  }
@@ -29298,7 +29406,7 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
29298
29406
 
29299
29407
  // Include SDK build time for debugging
29300
29408
  if (true) {
29301
- helloMessage.lastBuildTime = "2026-08-20T14:41:57.957Z";
29409
+ helloMessage.lastBuildTime = "2026-08-20T21:16:40.754Z";
29302
29410
  }
29303
29411
 
29304
29412
  // Client environment (device/browser/webview) for backend logs + Langfuse metadata
@@ -35348,7 +35456,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
35348
35456
  return;
35349
35457
  }
35350
35458
  this._ensureAboutStyles();
35351
- var version = true ? "2.48.2" : 0;
35459
+ var version = true ? "2.48.7" : 0;
35352
35460
  var convId = this._getLastConversationId();
35353
35461
  var t = function t(k, fb) {
35354
35462
  try {