ttp-agent-sdk 2.48.18 → 2.48.21
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/agent-widget.dev.js +748 -165
- package/dist/agent-widget.esm.js +1 -1
- package/dist/agent-widget.js +1 -1
- package/package.json +2 -1
- package/dist/examples/pet-store.html +0 -494
- package/dist/examples/seabreeze-hotel.html +0 -403
- package/examples/pet-store.html +0 -494
- package/examples/seabreeze-hotel.html +0 -403
package/dist/agent-widget.dev.js
CHANGED
|
@@ -12129,7 +12129,7 @@ var TextChatSDK = /*#__PURE__*/function (_EventEmitter) {
|
|
|
12129
12129
|
|
|
12130
12130
|
// SDK build time for debugging
|
|
12131
12131
|
if (true) {
|
|
12132
|
-
helloMessage.lastBuildTime = "2026-08-
|
|
12132
|
+
helloMessage.lastBuildTime = "2026-08-27T17:29:05.172Z";
|
|
12133
12133
|
}
|
|
12134
12134
|
try {
|
|
12135
12135
|
this.ws.send(JSON.stringify(helloMessage));
|
|
@@ -21439,8 +21439,8 @@ var VoiceSDK = _v2_VoiceSDK_js__WEBPACK_IMPORTED_MODULE_0__["default"];
|
|
|
21439
21439
|
|
|
21440
21440
|
|
|
21441
21441
|
// Version - injected at build time from package.json via webpack DefinePlugin
|
|
21442
|
-
var VERSION = "2.48.
|
|
21443
|
-
var BUILD_TIME = "2026-08-
|
|
21442
|
+
var VERSION = "2.48.21";
|
|
21443
|
+
var BUILD_TIME = "2026-08-27T17:29:05.172Z";
|
|
21444
21444
|
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;');
|
|
21445
21445
|
|
|
21446
21446
|
// Named exports
|
|
@@ -25616,6 +25616,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
25616
25616
|
/* harmony import */ var _codecs_PCMUCodec_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./codecs/PCMUCodec.js */ "./src/v2/codecs/PCMUCodec.js");
|
|
25617
25617
|
/* harmony import */ var _codecs_PCMACodec_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./codecs/PCMACodec.js */ "./src/v2/codecs/PCMACodec.js");
|
|
25618
25618
|
/* harmony import */ var _hopPlatform_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./hopPlatform.js */ "./src/v2/hopPlatform.js");
|
|
25619
|
+
/* harmony import */ var _loopbackAec_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./loopbackAec.js */ "./src/v2/loopbackAec.js");
|
|
25619
25620
|
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
|
25620
25621
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
25621
25622
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
@@ -25648,6 +25649,7 @@ function _setPrototypeOf(t, e) { return _setPrototypeOf = Object.setPrototypeOf
|
|
|
25648
25649
|
|
|
25649
25650
|
|
|
25650
25651
|
|
|
25652
|
+
|
|
25651
25653
|
// iOS FIX: Shared AudioContext for playback that persists across AudioPlayer instances.
|
|
25652
25654
|
// iOS WebKit doesn't release audio hardware synchronously when AudioContext.close() is called,
|
|
25653
25655
|
// so creating a new AudioContext immediately after closing the old one can fail silently.
|
|
@@ -25749,6 +25751,18 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
|
|
|
25749
25751
|
_this._htmlAudioPlayOk = false;
|
|
25750
25752
|
_this._htmlAudioPlayWatchdog = null;
|
|
25751
25753
|
_this._loggedHopResample = false;
|
|
25754
|
+
// Loopback AEC route (opt-in): the same MediaStream, but pushed through a
|
|
25755
|
+
// pair of local RTCPeerConnections first, because Chrome's echo canceller
|
|
25756
|
+
// only cancels peer-connection audio — a hidden <audio> is invisible to it.
|
|
25757
|
+
// See loopbackAec.js. Off unless asked for; the hop above is unchanged.
|
|
25758
|
+
_this._loopbackDest = null;
|
|
25759
|
+
_this._loopbackEl = null;
|
|
25760
|
+
_this._loopbackClose = null;
|
|
25761
|
+
_this._loopbackReady = false;
|
|
25762
|
+
_this._loopbackPending = false;
|
|
25763
|
+
_this._loopbackFailed = false;
|
|
25764
|
+
_this._loopbackPlayOk = false;
|
|
25765
|
+
_this._loopbackWanted = undefined; // memoized by wantsLoopbackAec()
|
|
25752
25766
|
// Greeting (and other bursts) fire many playChunk()s without await.
|
|
25753
25767
|
// Serialize context creation so they cannot open two AudioContexts
|
|
25754
25768
|
// at different rates in the middle of a sentence.
|
|
@@ -27022,6 +27036,7 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
|
|
|
27022
27036
|
this.gainNode = null;
|
|
27023
27037
|
}
|
|
27024
27038
|
this._teardownHtmlAudioRoute();
|
|
27039
|
+
this._teardownLoopbackRoute();
|
|
27025
27040
|
if (this.audioContext === _sharedPlayerContext) {
|
|
27026
27041
|
_sharedPlayerContext = null;
|
|
27027
27042
|
_sharedPlayerSampleRate = null;
|
|
@@ -27221,7 +27236,10 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
|
|
|
27221
27236
|
}, {
|
|
27222
27237
|
key: "_htmlHopNeedsHardwareRate",
|
|
27223
27238
|
value: function _htmlHopNeedsHardwareRate() {
|
|
27224
|
-
|
|
27239
|
+
// The loopback ends in the same live-MediaStream <audio> the hop does, so
|
|
27240
|
+
// it inherits the same device-rate requirement: a 24 kHz context makes
|
|
27241
|
+
// Chrome clock that stream wrong and play speech ~2x.
|
|
27242
|
+
return this.wantsHtmlAudioPlayback() || this.wantsLoopbackAec();
|
|
27225
27243
|
}
|
|
27226
27244
|
}, {
|
|
27227
27245
|
key: "_isHardwarePlaybackRate",
|
|
@@ -27256,13 +27274,76 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
|
|
|
27256
27274
|
sampleRate: audioDataSampleRate
|
|
27257
27275
|
};
|
|
27258
27276
|
}
|
|
27277
|
+
|
|
27278
|
+
/**
|
|
27279
|
+
* Read-only playback-route telemetry for hello (`client`) and client_audio_info.
|
|
27280
|
+
* Does not influence route selection — mirrors flags set by _connectGainToOutput.
|
|
27281
|
+
*/
|
|
27282
|
+
}, {
|
|
27283
|
+
key: "getPlaybackRouteReport",
|
|
27284
|
+
value: function getPlaybackRouteReport() {
|
|
27285
|
+
var htmlAudioPlayback = this.wantsHtmlAudioPlayback();
|
|
27286
|
+
var loopbackWanted = this.wantsLoopbackAec();
|
|
27287
|
+
var playbackRoute = this._reportEffectivePlaybackRoute();
|
|
27288
|
+
return {
|
|
27289
|
+
htmlAudioPlayback: htmlAudioPlayback,
|
|
27290
|
+
playbackRoute: playbackRoute,
|
|
27291
|
+
loopbackAttach: this._reportLoopbackAttach(loopbackWanted, playbackRoute),
|
|
27292
|
+
// Legacy booleans — kept for downstream consumers that predated tri-state.
|
|
27293
|
+
htmlAudioRouteActive: this._htmlAudioRouteActive,
|
|
27294
|
+
htmlAudioPlayOk: this._htmlAudioPlayOk,
|
|
27295
|
+
loopbackAec: loopbackWanted,
|
|
27296
|
+
loopbackRouteActive: this._loopbackReady,
|
|
27297
|
+
loopbackPlayOk: this._loopbackPlayOk
|
|
27298
|
+
};
|
|
27299
|
+
}
|
|
27259
27300
|
}, {
|
|
27260
27301
|
key: "getHtmlAudioPlaybackInfo",
|
|
27261
27302
|
value: function getHtmlAudioPlaybackInfo() {
|
|
27303
|
+
return this.getPlaybackRouteReport();
|
|
27304
|
+
}
|
|
27305
|
+
|
|
27306
|
+
/** Effective last-hop route from established player state (not config intent). */
|
|
27307
|
+
}, {
|
|
27308
|
+
key: "_reportEffectivePlaybackRoute",
|
|
27309
|
+
value: function _reportEffectivePlaybackRoute() {
|
|
27310
|
+
if (this._loopbackReady && !this._loopbackFailed) {
|
|
27311
|
+
return 'loopback';
|
|
27312
|
+
}
|
|
27313
|
+
if (this._htmlAudioRouteActive) {
|
|
27314
|
+
return 'htmlHop';
|
|
27315
|
+
}
|
|
27316
|
+
return 'destination';
|
|
27317
|
+
}
|
|
27318
|
+
}, {
|
|
27319
|
+
key: "_reportLoopbackAttach",
|
|
27320
|
+
value: function _reportLoopbackAttach(loopbackWanted, playbackRoute) {
|
|
27321
|
+
if (!loopbackWanted) {
|
|
27322
|
+
return {
|
|
27323
|
+
outcome: 'not_attempted'
|
|
27324
|
+
};
|
|
27325
|
+
}
|
|
27326
|
+
if (this._loopbackFailed) {
|
|
27327
|
+
return {
|
|
27328
|
+
outcome: 'failed',
|
|
27329
|
+
fallbackTo: playbackRoute
|
|
27330
|
+
};
|
|
27331
|
+
}
|
|
27332
|
+
if (this._loopbackReady && this._loopbackPlayOk) {
|
|
27333
|
+
return {
|
|
27334
|
+
outcome: 'success'
|
|
27335
|
+
};
|
|
27336
|
+
}
|
|
27337
|
+
if (this._loopbackReady && !this._loopbackPlayOk) {
|
|
27338
|
+
// Peer path is up; element play() not yet confirmed.
|
|
27339
|
+
return {
|
|
27340
|
+
outcome: 'pending'
|
|
27341
|
+
};
|
|
27342
|
+
}
|
|
27343
|
+
// Negotiation in flight — audio may be on an interim hop/destination route.
|
|
27262
27344
|
return {
|
|
27263
|
-
|
|
27264
|
-
|
|
27265
|
-
htmlAudioPlayOk: this._htmlAudioPlayOk
|
|
27345
|
+
outcome: 'pending',
|
|
27346
|
+
fallbackTo: playbackRoute
|
|
27266
27347
|
};
|
|
27267
27348
|
}
|
|
27268
27349
|
|
|
@@ -27279,6 +27360,18 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
|
|
|
27279
27360
|
try {
|
|
27280
27361
|
this.gainNode.disconnect();
|
|
27281
27362
|
} catch (_) {/* ignore */}
|
|
27363
|
+
|
|
27364
|
+
// Loopback first when asked for. It returns null until the peer connections
|
|
27365
|
+
// are up (negotiation is async), and we deliberately fall through to a
|
|
27366
|
+
// normal audible route in the meantime rather than holding audio: the
|
|
27367
|
+
// establishment is re-entrant and calls back here when it completes.
|
|
27368
|
+
if (this.wantsLoopbackAec()) {
|
|
27369
|
+
var loopbackDest = this._ensureLoopbackRoute();
|
|
27370
|
+
if (loopbackDest) {
|
|
27371
|
+
this.gainNode.connect(loopbackDest);
|
|
27372
|
+
return;
|
|
27373
|
+
}
|
|
27374
|
+
}
|
|
27282
27375
|
if (this.wantsHtmlAudioPlayback() && this._ensureHtmlAudioRoute()) {
|
|
27283
27376
|
this.gainNode.connect(this._mediaStreamDest);
|
|
27284
27377
|
return;
|
|
@@ -27303,16 +27396,7 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
|
|
|
27303
27396
|
}
|
|
27304
27397
|
try {
|
|
27305
27398
|
this._mediaStreamDest = this.audioContext.createMediaStreamDestination();
|
|
27306
|
-
var el =
|
|
27307
|
-
el.setAttribute('playsinline', '');
|
|
27308
|
-
el.setAttribute('webkit-playsinline', '');
|
|
27309
|
-
el.autoplay = true;
|
|
27310
|
-
el.controls = false;
|
|
27311
|
-
el.preload = 'auto';
|
|
27312
|
-
el.playbackRate = 1;
|
|
27313
|
-
el.style.display = 'none';
|
|
27314
|
-
el.srcObject = this._mediaStreamDest.stream;
|
|
27315
|
-
document.body.appendChild(el);
|
|
27399
|
+
var el = this._createHiddenAudioEl(this._mediaStreamDest.stream);
|
|
27316
27400
|
this._htmlAudioEl = el;
|
|
27317
27401
|
this._htmlAudioRouteActive = true;
|
|
27318
27402
|
this._ensureHtmlAudioPlaying();
|
|
@@ -27393,6 +27477,7 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
|
|
|
27393
27477
|
this.gainNode.disconnect();
|
|
27394
27478
|
} catch (_) {/* ignore */}
|
|
27395
27479
|
this._teardownHtmlAudioRoute();
|
|
27480
|
+
this._teardownLoopbackRoute();
|
|
27396
27481
|
this.gainNode.connect(this.audioContext.destination);
|
|
27397
27482
|
console.warn("\u26A0\uFE0F AudioPlayer: Fell back to AudioContext.destination (".concat(reason, ")"));
|
|
27398
27483
|
this.emit('htmlAudioRoute', {
|
|
@@ -27420,29 +27505,216 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
|
|
|
27420
27505
|
this._htmlAudioRouteActive = false;
|
|
27421
27506
|
}
|
|
27422
27507
|
|
|
27508
|
+
/**
|
|
27509
|
+
* Shared factory for the hidden playback element. Both last-hop routes need
|
|
27510
|
+
* exactly this: autoplay, inline on iOS, invisible, rate pinned to 1 so a
|
|
27511
|
+
* page-level playbackRate can't stretch TTS under us.
|
|
27512
|
+
*/
|
|
27513
|
+
}, {
|
|
27514
|
+
key: "_createHiddenAudioEl",
|
|
27515
|
+
value: function _createHiddenAudioEl(stream) {
|
|
27516
|
+
var el = document.createElement('audio');
|
|
27517
|
+
el.setAttribute('playsinline', '');
|
|
27518
|
+
el.setAttribute('webkit-playsinline', '');
|
|
27519
|
+
el.autoplay = true;
|
|
27520
|
+
el.controls = false;
|
|
27521
|
+
el.preload = 'auto';
|
|
27522
|
+
el.playbackRate = 1;
|
|
27523
|
+
el.style.display = 'none';
|
|
27524
|
+
el.srcObject = stream;
|
|
27525
|
+
document.body.appendChild(el);
|
|
27526
|
+
return el;
|
|
27527
|
+
}
|
|
27528
|
+
|
|
27529
|
+
/**
|
|
27530
|
+
* Opt-in loopback route. Default OFF: this is an unproven replacement for the
|
|
27531
|
+
* hop running on live customer sites, so it ships dark and is turned on per
|
|
27532
|
+
* machine (?ttp_loopback=1 / localStorage) or per integration (config).
|
|
27533
|
+
*/
|
|
27534
|
+
}, {
|
|
27535
|
+
key: "wantsLoopbackAec",
|
|
27536
|
+
value: function wantsLoopbackAec() {
|
|
27537
|
+
// Memoized per player: _htmlHopNeedsHardwareRate() consults this from
|
|
27538
|
+
// _honestRateSamples, i.e. once per audio chunk, and reading it live would
|
|
27539
|
+
// put a synchronous storage hit on the hot path for every machine where
|
|
27540
|
+
// the hop is off (there the || cannot short-circuit). Changing the flag
|
|
27541
|
+
// requires a reload anyway — that is how it is documented and tested.
|
|
27542
|
+
if (this._loopbackWanted === undefined) {
|
|
27543
|
+
var override = (0,_loopbackAec_js__WEBPACK_IMPORTED_MODULE_5__.readTtpLoopbackOverride)(typeof window !== 'undefined' ? window : null);
|
|
27544
|
+
this._loopbackWanted = override !== null ? override : typeof this.config.loopbackAec === 'boolean' ? this.config.loopbackAec : false;
|
|
27545
|
+
if (this._loopbackWanted) {
|
|
27546
|
+
console.log('🔊 AudioPlayer: loopback AEC requested — TTS will play via a local peer connection');
|
|
27547
|
+
}
|
|
27548
|
+
}
|
|
27549
|
+
return this._loopbackWanted;
|
|
27550
|
+
}
|
|
27551
|
+
|
|
27552
|
+
/**
|
|
27553
|
+
* Returns the MediaStreamDestination to play into once the loopback is up,
|
|
27554
|
+
* or null while it is not. Never blocks: the caller routes audio somewhere
|
|
27555
|
+
* audible in the meantime and we re-route from _establishLoopback.
|
|
27556
|
+
*/
|
|
27557
|
+
}, {
|
|
27558
|
+
key: "_ensureLoopbackRoute",
|
|
27559
|
+
value: function _ensureLoopbackRoute() {
|
|
27560
|
+
var _this9 = this;
|
|
27561
|
+
if (this._loopbackReady && this._loopbackDest) {
|
|
27562
|
+
this._ensureLoopbackPlaying();
|
|
27563
|
+
return this._loopbackDest;
|
|
27564
|
+
}
|
|
27565
|
+
if (this._loopbackFailed || this._loopbackPending) return null;
|
|
27566
|
+
if (!this.audioContext || typeof this.audioContext.createMediaStreamDestination !== 'function') {
|
|
27567
|
+
this._failLoopback('no_media_stream_destination');
|
|
27568
|
+
return null;
|
|
27569
|
+
}
|
|
27570
|
+
if (!(0,_loopbackAec_js__WEBPACK_IMPORTED_MODULE_5__.isLoopbackAecSupported)(typeof window !== 'undefined' ? window : null)) {
|
|
27571
|
+
this._failLoopback('no_peer_connection');
|
|
27572
|
+
return null;
|
|
27573
|
+
}
|
|
27574
|
+
this._loopbackPending = true;
|
|
27575
|
+
this._establishLoopback().catch(function (e) {
|
|
27576
|
+
console.warn('⚠️ AudioPlayer: loopback AEC route unavailable, keeping existing playback route:', e && e.message);
|
|
27577
|
+
_this9._failLoopback('negotiation_failed');
|
|
27578
|
+
});
|
|
27579
|
+
return null;
|
|
27580
|
+
}
|
|
27581
|
+
}, {
|
|
27582
|
+
key: "_establishLoopback",
|
|
27583
|
+
value: function () {
|
|
27584
|
+
var _establishLoopback2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee7() {
|
|
27585
|
+
var gen, dest, _yield$createAecLoopb, remoteStream, close;
|
|
27586
|
+
return _regenerator().w(function (_context8) {
|
|
27587
|
+
while (1) switch (_context8.n) {
|
|
27588
|
+
case 0:
|
|
27589
|
+
// Generation token: a teardown (call end, context rebuild) while we are
|
|
27590
|
+
// negotiating must not resurrect a route into a dead AudioContext.
|
|
27591
|
+
gen = this._loopbackGen = (this._loopbackGen || 0) + 1;
|
|
27592
|
+
dest = this.audioContext.createMediaStreamDestination();
|
|
27593
|
+
_context8.n = 1;
|
|
27594
|
+
return (0,_loopbackAec_js__WEBPACK_IMPORTED_MODULE_5__.createAecLoopback)({
|
|
27595
|
+
stream: dest.stream
|
|
27596
|
+
});
|
|
27597
|
+
case 1:
|
|
27598
|
+
_yield$createAecLoopb = _context8.v;
|
|
27599
|
+
remoteStream = _yield$createAecLoopb.remoteStream;
|
|
27600
|
+
close = _yield$createAecLoopb.close;
|
|
27601
|
+
if (!(gen !== this._loopbackGen || !this.audioContext)) {
|
|
27602
|
+
_context8.n = 2;
|
|
27603
|
+
break;
|
|
27604
|
+
}
|
|
27605
|
+
try {
|
|
27606
|
+
close();
|
|
27607
|
+
} catch (_) {/* ignore */}
|
|
27608
|
+
return _context8.a(2);
|
|
27609
|
+
case 2:
|
|
27610
|
+
// Drop the transitional hop element if one was built while we negotiated,
|
|
27611
|
+
// or it keeps playing a destination nothing is connected to any more.
|
|
27612
|
+
this._teardownHtmlAudioRoute();
|
|
27613
|
+
this._loopbackDest = dest;
|
|
27614
|
+
this._loopbackClose = close;
|
|
27615
|
+
this._loopbackEl = this._createHiddenAudioEl(remoteStream);
|
|
27616
|
+
this._loopbackReady = true;
|
|
27617
|
+
this._loopbackPending = false;
|
|
27618
|
+
this._ensureLoopbackPlaying();
|
|
27619
|
+
this._connectGainToOutput();
|
|
27620
|
+
console.log('🔊 AudioPlayer: Playback last-hop is a local WebRTC loopback (Chrome-cancellable AEC far-end)');
|
|
27621
|
+
this.emit('htmlAudioRoute', {
|
|
27622
|
+
state: 'loopback_established'
|
|
27623
|
+
});
|
|
27624
|
+
case 3:
|
|
27625
|
+
return _context8.a(2);
|
|
27626
|
+
}
|
|
27627
|
+
}, _callee7, this);
|
|
27628
|
+
}));
|
|
27629
|
+
function _establishLoopback() {
|
|
27630
|
+
return _establishLoopback2.apply(this, arguments);
|
|
27631
|
+
}
|
|
27632
|
+
return _establishLoopback;
|
|
27633
|
+
}()
|
|
27634
|
+
}, {
|
|
27635
|
+
key: "_ensureLoopbackPlaying",
|
|
27636
|
+
value: function _ensureLoopbackPlaying() {
|
|
27637
|
+
var _this0 = this;
|
|
27638
|
+
var el = this._loopbackEl;
|
|
27639
|
+
if (!el) return;
|
|
27640
|
+
if (!el.paused && this._loopbackPlayOk) return;
|
|
27641
|
+
var playResult = el.play();
|
|
27642
|
+
if (playResult && typeof playResult.then === 'function') {
|
|
27643
|
+
playResult.then(function () {
|
|
27644
|
+
_this0._loopbackPlayOk = true;
|
|
27645
|
+
}).catch(function (err) {
|
|
27646
|
+
if (_this0._loopbackPlayOk || !el.paused) return;
|
|
27647
|
+
console.warn('⚠️ AudioPlayer: loopback element play() rejected — reverting to the previous route:', err);
|
|
27648
|
+
_this0._failLoopback('play_rejected');
|
|
27649
|
+
_this0._connectGainToOutput();
|
|
27650
|
+
});
|
|
27651
|
+
}
|
|
27652
|
+
}
|
|
27653
|
+
|
|
27654
|
+
/** One-way latch: once the loopback is off for this player it stays off,
|
|
27655
|
+
* rather than retrying every reconnect and stuttering the route. */
|
|
27656
|
+
}, {
|
|
27657
|
+
key: "_failLoopback",
|
|
27658
|
+
value: function _failLoopback(reason) {
|
|
27659
|
+
this._loopbackFailed = true;
|
|
27660
|
+
this._loopbackPending = false;
|
|
27661
|
+
this._teardownLoopbackRoute();
|
|
27662
|
+
this.emit('htmlAudioRoute', {
|
|
27663
|
+
state: 'loopback_fallback',
|
|
27664
|
+
reason: reason
|
|
27665
|
+
});
|
|
27666
|
+
}
|
|
27667
|
+
}, {
|
|
27668
|
+
key: "_teardownLoopbackRoute",
|
|
27669
|
+
value: function _teardownLoopbackRoute() {
|
|
27670
|
+
this._loopbackGen = (this._loopbackGen || 0) + 1;
|
|
27671
|
+
if (this._loopbackEl) {
|
|
27672
|
+
try {
|
|
27673
|
+
this._loopbackEl.pause();
|
|
27674
|
+
} catch (_) {/* ignore */}
|
|
27675
|
+
try {
|
|
27676
|
+
this._loopbackEl.srcObject = null;
|
|
27677
|
+
} catch (_) {/* ignore */}
|
|
27678
|
+
if (this._loopbackEl.parentNode) {
|
|
27679
|
+
this._loopbackEl.parentNode.removeChild(this._loopbackEl);
|
|
27680
|
+
}
|
|
27681
|
+
this._loopbackEl = null;
|
|
27682
|
+
}
|
|
27683
|
+
if (this._loopbackClose) {
|
|
27684
|
+
try {
|
|
27685
|
+
this._loopbackClose();
|
|
27686
|
+
} catch (_) {/* ignore */}
|
|
27687
|
+
this._loopbackClose = null;
|
|
27688
|
+
}
|
|
27689
|
+
this._loopbackDest = null;
|
|
27690
|
+
this._loopbackReady = false;
|
|
27691
|
+
this._loopbackPending = false;
|
|
27692
|
+
this._loopbackPlayOk = false;
|
|
27693
|
+
}
|
|
27694
|
+
|
|
27423
27695
|
/**
|
|
27424
27696
|
* Initialize audio context with correct sample rate
|
|
27425
27697
|
*/
|
|
27426
27698
|
}, {
|
|
27427
27699
|
key: "initializeAudioContext",
|
|
27428
27700
|
value: (function () {
|
|
27429
|
-
var _initializeAudioContext = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function
|
|
27430
|
-
var
|
|
27431
|
-
return _regenerator().w(function (
|
|
27432
|
-
while (1) switch (
|
|
27701
|
+
var _initializeAudioContext = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee8() {
|
|
27702
|
+
var _this1 = this;
|
|
27703
|
+
return _regenerator().w(function (_context9) {
|
|
27704
|
+
while (1) switch (_context9.n) {
|
|
27433
27705
|
case 0:
|
|
27434
27706
|
if (!this._audioContextInitPromise) {
|
|
27435
|
-
|
|
27707
|
+
_context9.n = 1;
|
|
27436
27708
|
break;
|
|
27437
27709
|
}
|
|
27438
|
-
return
|
|
27710
|
+
return _context9.a(2, this._audioContextInitPromise);
|
|
27439
27711
|
case 1:
|
|
27440
27712
|
this._audioContextInitPromise = this._initializeAudioContextImpl().finally(function () {
|
|
27441
|
-
|
|
27713
|
+
_this1._audioContextInitPromise = null;
|
|
27442
27714
|
});
|
|
27443
|
-
return
|
|
27715
|
+
return _context9.a(2, this._audioContextInitPromise);
|
|
27444
27716
|
}
|
|
27445
|
-
},
|
|
27717
|
+
}, _callee8, this);
|
|
27446
27718
|
}));
|
|
27447
27719
|
function initializeAudioContext() {
|
|
27448
27720
|
return _initializeAudioContext.apply(this, arguments);
|
|
@@ -27452,11 +27724,11 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
|
|
|
27452
27724
|
}, {
|
|
27453
27725
|
key: "_initializeAudioContextImpl",
|
|
27454
27726
|
value: function () {
|
|
27455
|
-
var _initializeAudioContextImpl2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function
|
|
27456
|
-
var
|
|
27727
|
+
var _initializeAudioContextImpl2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee9() {
|
|
27728
|
+
var _this10 = this;
|
|
27457
27729
|
var ttsSampleRate, useHardwareRate, desiredSampleRate, contextFits, canReuseShared, setupAfterResume, ctxOpts, _t4;
|
|
27458
|
-
return _regenerator().w(function (
|
|
27459
|
-
while (1) switch (
|
|
27730
|
+
return _regenerator().w(function (_context0) {
|
|
27731
|
+
while (1) switch (_context0.p = _context0.n) {
|
|
27460
27732
|
case 0:
|
|
27461
27733
|
ttsSampleRate = this._ttsSampleRate();
|
|
27462
27734
|
useHardwareRate = this._htmlHopNeedsHardwareRate(); // Destination path: match TTS (24 kHz). HTML last-hop: request the standard
|
|
@@ -27474,27 +27746,27 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
|
|
|
27474
27746
|
_sharedPlayerSampleRate = null;
|
|
27475
27747
|
}
|
|
27476
27748
|
contextFits = function contextFits(rate) {
|
|
27477
|
-
if (useHardwareRate) return
|
|
27749
|
+
if (useHardwareRate) return _this10._isHardwarePlaybackRate(rate);
|
|
27478
27750
|
return Math.abs(rate - desiredSampleRate) <= 100;
|
|
27479
27751
|
}; // Check if current instance AudioContext exists and matches
|
|
27480
27752
|
if (!this.audioContext) {
|
|
27481
|
-
|
|
27753
|
+
_context0.n = 3;
|
|
27482
27754
|
break;
|
|
27483
27755
|
}
|
|
27484
27756
|
if (!(this.audioContext.state === 'closed')) {
|
|
27485
|
-
|
|
27757
|
+
_context0.n = 1;
|
|
27486
27758
|
break;
|
|
27487
27759
|
}
|
|
27488
27760
|
this._invalidateClosedAudioContext();
|
|
27489
|
-
|
|
27761
|
+
_context0.n = 3;
|
|
27490
27762
|
break;
|
|
27491
27763
|
case 1:
|
|
27492
27764
|
if (!contextFits(this.audioContext.sampleRate)) {
|
|
27493
|
-
|
|
27765
|
+
_context0.n = 2;
|
|
27494
27766
|
break;
|
|
27495
27767
|
}
|
|
27496
27768
|
this._ensureHtmlAudioPlaying();
|
|
27497
|
-
return
|
|
27769
|
+
return _context0.a(2);
|
|
27498
27770
|
case 2:
|
|
27499
27771
|
console.warn("\u26A0\uFE0F AudioPlayer: AudioContext sample rate (".concat(this.audioContext.sampleRate, "Hz) doesn't match playback hop, recreating..."));
|
|
27500
27772
|
this.stopImmediate();
|
|
@@ -27505,44 +27777,44 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
|
|
|
27505
27777
|
// causing newly created AudioContexts to fail silently.
|
|
27506
27778
|
canReuseShared = _sharedPlayerContext && _sharedPlayerContext.state !== 'closed' && contextFits(_sharedPlayerContext.sampleRate);
|
|
27507
27779
|
if (!canReuseShared) {
|
|
27508
|
-
|
|
27780
|
+
_context0.n = 8;
|
|
27509
27781
|
break;
|
|
27510
27782
|
}
|
|
27511
27783
|
console.log("\u267B\uFE0F AudioPlayer: Reusing shared AudioContext at ".concat(_sharedPlayerContext.sampleRate, "Hz (iOS-safe)"));
|
|
27512
27784
|
this.audioContext = _sharedPlayerContext;
|
|
27513
27785
|
setupAfterResume = function setupAfterResume() {
|
|
27514
|
-
|
|
27515
|
-
if (
|
|
27786
|
+
_this10.setupAudioContextStateMonitoring();
|
|
27787
|
+
if (_this10.gainNode) {
|
|
27516
27788
|
try {
|
|
27517
|
-
|
|
27789
|
+
_this10.gainNode.disconnect();
|
|
27518
27790
|
} catch (e) {
|
|
27519
27791
|
console.warn('⚠️ AudioPlayer: Error disconnecting old GainNode:', e);
|
|
27520
27792
|
}
|
|
27521
27793
|
}
|
|
27522
|
-
|
|
27523
|
-
|
|
27524
|
-
|
|
27525
|
-
if (!
|
|
27526
|
-
|
|
27794
|
+
_this10.gainNode = _this10.audioContext.createGain();
|
|
27795
|
+
_this10.gainNode.gain.value = 1.0;
|
|
27796
|
+
_this10._connectGainToOutput();
|
|
27797
|
+
if (!_this10._audioContextPrimed) {
|
|
27798
|
+
_this10._primeAudioContext();
|
|
27527
27799
|
}
|
|
27528
27800
|
};
|
|
27529
27801
|
if (!(this.audioContext.state === 'suspended')) {
|
|
27530
|
-
|
|
27802
|
+
_context0.n = 7;
|
|
27531
27803
|
break;
|
|
27532
27804
|
}
|
|
27533
|
-
|
|
27534
|
-
|
|
27805
|
+
_context0.p = 4;
|
|
27806
|
+
_context0.n = 5;
|
|
27535
27807
|
return this.audioContext.resume();
|
|
27536
27808
|
case 5:
|
|
27537
|
-
|
|
27809
|
+
_context0.n = 7;
|
|
27538
27810
|
break;
|
|
27539
27811
|
case 6:
|
|
27540
|
-
|
|
27541
|
-
_t4 =
|
|
27812
|
+
_context0.p = 6;
|
|
27813
|
+
_t4 = _context0.v;
|
|
27542
27814
|
console.warn('⚠️ AudioPlayer: Error resuming shared context:', _t4);
|
|
27543
27815
|
case 7:
|
|
27544
27816
|
setupAfterResume();
|
|
27545
|
-
return
|
|
27817
|
+
return _context0.a(2);
|
|
27546
27818
|
case 8:
|
|
27547
27819
|
console.log("\uD83C\uDFB5 AudioPlayer: Creating AudioContext (tts=".concat(ttsSampleRate, "Hz, htmlHop=").concat(useHardwareRate, ", requested=").concat(desiredSampleRate, "Hz)"));
|
|
27548
27820
|
|
|
@@ -27595,9 +27867,9 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
|
|
|
27595
27867
|
this._primeAudioContext();
|
|
27596
27868
|
}
|
|
27597
27869
|
case 9:
|
|
27598
|
-
return
|
|
27870
|
+
return _context0.a(2);
|
|
27599
27871
|
}
|
|
27600
|
-
},
|
|
27872
|
+
}, _callee9, this, [[4, 6]]);
|
|
27601
27873
|
}));
|
|
27602
27874
|
function _initializeAudioContextImpl() {
|
|
27603
27875
|
return _initializeAudioContextImpl2.apply(this, arguments);
|
|
@@ -27611,17 +27883,17 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
|
|
|
27611
27883
|
}, {
|
|
27612
27884
|
key: "_primeAudioContext",
|
|
27613
27885
|
value: (function () {
|
|
27614
|
-
var _primeAudioContext2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function
|
|
27886
|
+
var _primeAudioContext2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee0() {
|
|
27615
27887
|
var sampleRate, silentBuffer, source, _t5;
|
|
27616
|
-
return _regenerator().w(function (
|
|
27617
|
-
while (1) switch (
|
|
27888
|
+
return _regenerator().w(function (_context1) {
|
|
27889
|
+
while (1) switch (_context1.p = _context1.n) {
|
|
27618
27890
|
case 0:
|
|
27619
|
-
|
|
27891
|
+
_context1.p = 0;
|
|
27620
27892
|
if (!(!this.audioContext || this._audioContextPrimed)) {
|
|
27621
|
-
|
|
27893
|
+
_context1.n = 1;
|
|
27622
27894
|
break;
|
|
27623
27895
|
}
|
|
27624
|
-
return
|
|
27896
|
+
return _context1.a(2);
|
|
27625
27897
|
case 1:
|
|
27626
27898
|
sampleRate = this.audioContext.sampleRate;
|
|
27627
27899
|
silentBuffer = this.audioContext.createBuffer(1, sampleRate * 0.15, sampleRate);
|
|
@@ -27632,23 +27904,23 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
|
|
|
27632
27904
|
source.connect(this.gainNode || this.audioContext.destination);
|
|
27633
27905
|
source.start();
|
|
27634
27906
|
this._ensureHtmlAudioPlaying();
|
|
27635
|
-
|
|
27907
|
+
_context1.n = 2;
|
|
27636
27908
|
return new Promise(function (resolve) {
|
|
27637
27909
|
return setTimeout(resolve, 150);
|
|
27638
27910
|
});
|
|
27639
27911
|
case 2:
|
|
27640
27912
|
this._audioContextPrimed = true;
|
|
27641
27913
|
console.log('✅ AudioPlayer: Audio hardware primed with silent buffer');
|
|
27642
|
-
|
|
27914
|
+
_context1.n = 4;
|
|
27643
27915
|
break;
|
|
27644
27916
|
case 3:
|
|
27645
|
-
|
|
27646
|
-
_t5 =
|
|
27917
|
+
_context1.p = 3;
|
|
27918
|
+
_t5 = _context1.v;
|
|
27647
27919
|
console.error('❌ AudioPlayer: Audio priming failed:', _t5);
|
|
27648
27920
|
case 4:
|
|
27649
|
-
return
|
|
27921
|
+
return _context1.a(2);
|
|
27650
27922
|
}
|
|
27651
|
-
},
|
|
27923
|
+
}, _callee0, this, [[0, 3]]);
|
|
27652
27924
|
}));
|
|
27653
27925
|
function _primeAudioContext() {
|
|
27654
27926
|
return _primeAudioContext2.apply(this, arguments);
|
|
@@ -27675,6 +27947,7 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
|
|
|
27675
27947
|
this.gainNode = null;
|
|
27676
27948
|
}
|
|
27677
27949
|
this._teardownHtmlAudioRoute();
|
|
27950
|
+
this._teardownLoopbackRoute();
|
|
27678
27951
|
|
|
27679
27952
|
// Remove state change listener first
|
|
27680
27953
|
if (this._audioContextStateChangeHandler && this.audioContext) {
|
|
@@ -27715,7 +27988,7 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
|
|
|
27715
27988
|
* Handles mic permission grants, tab switching, browser suspension, etc.
|
|
27716
27989
|
*/
|
|
27717
27990
|
function setupAudioContextStateMonitoring() {
|
|
27718
|
-
var
|
|
27991
|
+
var _this11 = this;
|
|
27719
27992
|
if (!this.audioContext) {
|
|
27720
27993
|
return;
|
|
27721
27994
|
}
|
|
@@ -27728,38 +28001,38 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
|
|
|
27728
28001
|
// Create handler that references this.audioContext dynamically
|
|
27729
28002
|
this._audioContextStateChangeHandler = function () {
|
|
27730
28003
|
// Null check required because audioContext may be cleaned up while handler is queued
|
|
27731
|
-
if (!
|
|
28004
|
+
if (!_this11.audioContext) {
|
|
27732
28005
|
console.warn('⚠️ AudioPlayer: State change handler fired but AudioContext is null');
|
|
27733
28006
|
return;
|
|
27734
28007
|
}
|
|
27735
|
-
console.log("\uD83C\uDFB5 AudioPlayer: AudioContext state changed to: ".concat(
|
|
27736
|
-
if (
|
|
27737
|
-
|
|
28008
|
+
console.log("\uD83C\uDFB5 AudioPlayer: AudioContext state changed to: ".concat(_this11.audioContext.state));
|
|
28009
|
+
if (_this11.audioContext.state === 'running') {
|
|
28010
|
+
_this11._ensureHtmlAudioPlaying();
|
|
27738
28011
|
}
|
|
27739
|
-
if (
|
|
28012
|
+
if (_this11.audioContext.state === 'suspended' && _this11.isPlaying) {
|
|
27740
28013
|
// AudioContext was suspended during playback (tab switch, mic permission, etc.)
|
|
27741
28014
|
console.warn('⚠️ AudioPlayer: AudioContext suspended during playback');
|
|
27742
28015
|
// Note: Playback will pause automatically, but we should handle queue processing
|
|
27743
28016
|
// The state change will be handled when we try to process next frame
|
|
27744
|
-
} else if (
|
|
28017
|
+
} else if (_this11.audioContext.state === 'running' && !_this11.isPlaying && (_this11.audioQueue.length > 0 || _this11.pcmChunkQueue.length > 0 || _this11.preparedBuffer.length > 0)) {
|
|
27745
28018
|
// AudioContext resumed and we have queued frames
|
|
27746
28019
|
// This handles: mic permission grant, tab switching back, browser resume, etc.
|
|
27747
28020
|
console.log('✅ AudioPlayer: AudioContext resumed - resuming queue processing');
|
|
27748
28021
|
|
|
27749
28022
|
// Resume queue processing if we have frames
|
|
27750
|
-
if (
|
|
28023
|
+
if (_this11.audioQueue.length > 0 && !_this11.isProcessingQueue) {
|
|
27751
28024
|
setTimeout(function () {
|
|
27752
|
-
return
|
|
28025
|
+
return _this11.processQueue();
|
|
27753
28026
|
}, 50);
|
|
27754
28027
|
}
|
|
27755
|
-
if (
|
|
28028
|
+
if (_this11.pcmChunkQueue.length > 0 && !_this11.isProcessingPcmQueue) {
|
|
27756
28029
|
setTimeout(function () {
|
|
27757
|
-
return
|
|
28030
|
+
return _this11.processPcmQueue();
|
|
27758
28031
|
}, 50);
|
|
27759
28032
|
}
|
|
27760
|
-
if (
|
|
28033
|
+
if (_this11.preparedBuffer.length > 0 && !_this11.isSchedulingFrames) {
|
|
27761
28034
|
setTimeout(function () {
|
|
27762
|
-
return
|
|
28035
|
+
return _this11.scheduleFrames();
|
|
27763
28036
|
}, 50);
|
|
27764
28037
|
}
|
|
27765
28038
|
}
|
|
@@ -27777,49 +28050,49 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
|
|
|
27777
28050
|
}, {
|
|
27778
28051
|
key: "processQueue",
|
|
27779
28052
|
value: (function () {
|
|
27780
|
-
var _processQueue = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function
|
|
27781
|
-
var
|
|
28053
|
+
var _processQueue = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee1() {
|
|
28054
|
+
var _this12 = this;
|
|
27782
28055
|
var audioBlob, wasFirstPlay, audioContext, arrayBuffer, audioBuffer, shouldEmitStart, source, _t6;
|
|
27783
|
-
return _regenerator().w(function (
|
|
27784
|
-
while (1) switch (
|
|
28056
|
+
return _regenerator().w(function (_context10) {
|
|
28057
|
+
while (1) switch (_context10.p = _context10.n) {
|
|
27785
28058
|
case 0:
|
|
27786
28059
|
if (!this._isStopped) {
|
|
27787
|
-
|
|
28060
|
+
_context10.n = 1;
|
|
27788
28061
|
break;
|
|
27789
28062
|
}
|
|
27790
28063
|
console.log('🛑 AudioPlayer: Not processing queue - playback was stopped (barge-in)');
|
|
27791
|
-
return
|
|
28064
|
+
return _context10.a(2);
|
|
27792
28065
|
case 1:
|
|
27793
28066
|
if (!(this.isProcessingQueue || this.audioQueue.length === 0)) {
|
|
27794
|
-
|
|
28067
|
+
_context10.n = 2;
|
|
27795
28068
|
break;
|
|
27796
28069
|
}
|
|
27797
|
-
return
|
|
28070
|
+
return _context10.a(2);
|
|
27798
28071
|
case 2:
|
|
27799
28072
|
this.isProcessingQueue = true;
|
|
27800
28073
|
this._ensureHtmlAudioPlaying();
|
|
27801
28074
|
audioBlob = this.audioQueue.shift();
|
|
27802
28075
|
if (audioBlob) {
|
|
27803
|
-
|
|
28076
|
+
_context10.n = 3;
|
|
27804
28077
|
break;
|
|
27805
28078
|
}
|
|
27806
28079
|
this.isProcessingQueue = false;
|
|
27807
|
-
return
|
|
28080
|
+
return _context10.a(2);
|
|
27808
28081
|
case 3:
|
|
27809
|
-
|
|
28082
|
+
_context10.p = 3;
|
|
27810
28083
|
wasFirstPlay = !this.isPlaying && this.currentSource === null; // Ensure context exists and is running (handles lazy init + suspended shared context)
|
|
27811
|
-
|
|
28084
|
+
_context10.n = 4;
|
|
27812
28085
|
return this.waitForAudioContextReady();
|
|
27813
28086
|
case 4:
|
|
27814
28087
|
audioContext = this.audioContext; // Decode audio
|
|
27815
|
-
|
|
28088
|
+
_context10.n = 5;
|
|
27816
28089
|
return audioBlob.arrayBuffer();
|
|
27817
28090
|
case 5:
|
|
27818
|
-
arrayBuffer =
|
|
27819
|
-
|
|
28091
|
+
arrayBuffer = _context10.v;
|
|
28092
|
+
_context10.n = 6;
|
|
27820
28093
|
return audioContext.decodeAudioData(arrayBuffer);
|
|
27821
28094
|
case 6:
|
|
27822
|
-
audioBuffer =
|
|
28095
|
+
audioBuffer = _context10.v;
|
|
27823
28096
|
shouldEmitStart = wasFirstPlay && !this.isPlaying && this.currentSource === null; // Create source
|
|
27824
28097
|
source = audioContext.createBufferSource();
|
|
27825
28098
|
source.buffer = audioBuffer;
|
|
@@ -27838,22 +28111,22 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
|
|
|
27838
28111
|
// Handle end
|
|
27839
28112
|
|
|
27840
28113
|
source.onended = function () {
|
|
27841
|
-
|
|
27842
|
-
|
|
28114
|
+
_this12.currentSource = null;
|
|
28115
|
+
_this12.isProcessingQueue = false;
|
|
27843
28116
|
|
|
27844
28117
|
// Process next chunk
|
|
27845
28118
|
|
|
27846
|
-
if (
|
|
28119
|
+
if (_this12.audioQueue.length > 0) {
|
|
27847
28120
|
setTimeout(function () {
|
|
27848
|
-
return
|
|
28121
|
+
return _this12.processQueue();
|
|
27849
28122
|
}, 50);
|
|
27850
28123
|
} else {
|
|
27851
28124
|
// No more chunks - stop after delay
|
|
27852
28125
|
|
|
27853
28126
|
setTimeout(function () {
|
|
27854
|
-
if (
|
|
27855
|
-
|
|
27856
|
-
|
|
28127
|
+
if (_this12.audioQueue.length === 0 && !_this12.currentSource) {
|
|
28128
|
+
_this12.isPlaying = false;
|
|
28129
|
+
_this12.emit('playbackStopped');
|
|
27857
28130
|
}
|
|
27858
28131
|
}, 100);
|
|
27859
28132
|
}
|
|
@@ -27862,11 +28135,11 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
|
|
|
27862
28135
|
// Start playback - AudioContext should now be fully ready
|
|
27863
28136
|
|
|
27864
28137
|
source.start();
|
|
27865
|
-
|
|
28138
|
+
_context10.n = 8;
|
|
27866
28139
|
break;
|
|
27867
28140
|
case 7:
|
|
27868
|
-
|
|
27869
|
-
_t6 =
|
|
28141
|
+
_context10.p = 7;
|
|
28142
|
+
_t6 = _context10.v;
|
|
27870
28143
|
console.error('❌ AudioPlayer v2: Error processing queue:', _t6);
|
|
27871
28144
|
this.currentSource = null;
|
|
27872
28145
|
this.emit('playbackError', _t6);
|
|
@@ -27876,7 +28149,7 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
|
|
|
27876
28149
|
if (this.audioQueue.length > 0) {
|
|
27877
28150
|
this.isProcessingQueue = false;
|
|
27878
28151
|
setTimeout(function () {
|
|
27879
|
-
return
|
|
28152
|
+
return _this12.processQueue();
|
|
27880
28153
|
}, 100);
|
|
27881
28154
|
} else {
|
|
27882
28155
|
this.isPlaying = false;
|
|
@@ -27884,9 +28157,9 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
|
|
|
27884
28157
|
this.emit('playbackStopped');
|
|
27885
28158
|
}
|
|
27886
28159
|
case 8:
|
|
27887
|
-
return
|
|
28160
|
+
return _context10.a(2);
|
|
27888
28161
|
}
|
|
27889
|
-
},
|
|
28162
|
+
}, _callee1, this, [[3, 7]]);
|
|
27890
28163
|
}));
|
|
27891
28164
|
function processQueue() {
|
|
27892
28165
|
return _processQueue.apply(this, arguments);
|
|
@@ -28099,7 +28372,7 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
|
|
|
28099
28372
|
}, {
|
|
28100
28373
|
key: "markNewSentence",
|
|
28101
28374
|
value: function markNewSentence(text, synced, segmentId) {
|
|
28102
|
-
var
|
|
28375
|
+
var _this13 = this;
|
|
28103
28376
|
var wasStopped = this._isStopped;
|
|
28104
28377
|
var isCurrentlyPlaying = this.isPlaying || this.scheduledSources.size > 0;
|
|
28105
28378
|
|
|
@@ -28158,34 +28431,34 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
|
|
|
28158
28431
|
var sentenceText = text; // Capture for timeout callback
|
|
28159
28432
|
this._emptySentenceTimeout = setTimeout(function () {
|
|
28160
28433
|
// Check if this sentence still has no chunks after timeout
|
|
28161
|
-
if (
|
|
28434
|
+
if (_this13.pendingSentenceText === sentenceText && _this13.scheduledBuffers === 0 && _this13.preparedBuffer.length === 0 && _this13.pcmChunkQueue.length === 0 && !_this13._isStopped) {
|
|
28162
28435
|
console.warn("\u26A0\uFE0F AudioPlayer: Empty sentence detected after 5s timeout - no chunks received for: \"".concat(sentenceText.substring(0, 40), "...\""));
|
|
28163
28436
|
// If this empty sentence carried a segment id, report it done (nothing was heard) and
|
|
28164
28437
|
// adopt it as current so the coarse stop below matches the backend's last-sent id.
|
|
28165
|
-
if (
|
|
28166
|
-
var emptySegId =
|
|
28167
|
-
|
|
28168
|
-
|
|
28169
|
-
|
|
28438
|
+
if (_this13.pendingSegmentId != null) {
|
|
28439
|
+
var emptySegId = _this13.pendingSegmentId;
|
|
28440
|
+
_this13.currentSegmentId = emptySegId;
|
|
28441
|
+
_this13.pendingSegmentId = null;
|
|
28442
|
+
_this13.emit('segmentDone', {
|
|
28170
28443
|
segmentId: emptySegId,
|
|
28171
28444
|
status: 'finished',
|
|
28172
28445
|
playedMs: 0
|
|
28173
28446
|
});
|
|
28174
28447
|
}
|
|
28175
28448
|
// Clear pending sentence to unblock next sentence
|
|
28176
|
-
if (
|
|
28177
|
-
|
|
28449
|
+
if (_this13.pendingSentenceText === sentenceText) {
|
|
28450
|
+
_this13.pendingSentenceText = null;
|
|
28178
28451
|
}
|
|
28179
28452
|
// Emit playbackStopped to allow next sentence to start
|
|
28180
28453
|
// Only if we're not currently playing (to avoid interrupting real playback)
|
|
28181
|
-
if (!
|
|
28454
|
+
if (!_this13.isPlaying && _this13.scheduledSources.size === 0) {
|
|
28182
28455
|
console.log('🛑 AudioPlayer: Emitting playbackStopped for empty sentence timeout');
|
|
28183
|
-
|
|
28184
|
-
segmentId:
|
|
28456
|
+
_this13.emit('playbackStopped', {
|
|
28457
|
+
segmentId: _this13.currentSegmentId
|
|
28185
28458
|
});
|
|
28186
28459
|
}
|
|
28187
28460
|
}
|
|
28188
|
-
|
|
28461
|
+
_this13._emptySentenceTimeout = null;
|
|
28189
28462
|
}, 5000); // 5 second timeout - adjust based on expected chunk arrival rate
|
|
28190
28463
|
}
|
|
28191
28464
|
|
|
@@ -28195,14 +28468,14 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
|
|
|
28195
28468
|
}, {
|
|
28196
28469
|
key: "startTranscriptChecker",
|
|
28197
28470
|
value: function startTranscriptChecker() {
|
|
28198
|
-
var
|
|
28471
|
+
var _this14 = this;
|
|
28199
28472
|
if (this.isCheckingTranscripts) return;
|
|
28200
28473
|
this.isCheckingTranscripts = true;
|
|
28201
28474
|
console.log('📝 AudioPlayer: Transcript checker started');
|
|
28202
28475
|
var _checkLoop = function checkLoop() {
|
|
28203
|
-
if (!
|
|
28204
|
-
var currentTime =
|
|
28205
|
-
var _iterator2 = _createForOfIteratorHelper(
|
|
28476
|
+
if (!_this14.isCheckingTranscripts || !_this14.audioContext) return;
|
|
28477
|
+
var currentTime = _this14.audioContext.currentTime;
|
|
28478
|
+
var _iterator2 = _createForOfIteratorHelper(_this14.sentenceTimings),
|
|
28206
28479
|
_step2;
|
|
28207
28480
|
try {
|
|
28208
28481
|
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
@@ -28216,13 +28489,13 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
|
|
|
28216
28489
|
eventData.synced = _timing.synced;
|
|
28217
28490
|
}
|
|
28218
28491
|
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, ")"));
|
|
28219
|
-
|
|
28492
|
+
_this14.emit('transcriptDisplay', eventData);
|
|
28220
28493
|
}
|
|
28221
28494
|
// Per-segment natural finish: this segment's audio window has fully elapsed.
|
|
28222
28495
|
if (!_timing.doneReported && _timing.endTime != null && currentTime >= _timing.endTime) {
|
|
28223
28496
|
_timing.doneReported = true;
|
|
28224
28497
|
var _playedMs = Math.round((_timing.endTime - _timing.startTime) * 1000);
|
|
28225
|
-
|
|
28498
|
+
_this14.emit('segmentDone', {
|
|
28226
28499
|
segmentId: _timing.segmentId,
|
|
28227
28500
|
status: 'finished',
|
|
28228
28501
|
playedMs: _playedMs
|
|
@@ -28234,12 +28507,12 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
|
|
|
28234
28507
|
} finally {
|
|
28235
28508
|
_iterator2.f();
|
|
28236
28509
|
}
|
|
28237
|
-
if (
|
|
28510
|
+
if (_this14.isPlaying || _this14.scheduledBuffers > 0) {
|
|
28238
28511
|
requestAnimationFrame(_checkLoop);
|
|
28239
28512
|
} else {
|
|
28240
28513
|
// Playback drained naturally — flush any segment whose finish tick we may have missed
|
|
28241
28514
|
// (the last buffer's onended can flip isPlaying=false before this loop's next tick).
|
|
28242
|
-
var _iterator3 = _createForOfIteratorHelper(
|
|
28515
|
+
var _iterator3 = _createForOfIteratorHelper(_this14.sentenceTimings),
|
|
28243
28516
|
_step3;
|
|
28244
28517
|
try {
|
|
28245
28518
|
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
@@ -28248,7 +28521,7 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
|
|
|
28248
28521
|
timing.doneReported = true;
|
|
28249
28522
|
var end = timing.endTime != null ? timing.endTime : timing.startTime;
|
|
28250
28523
|
var playedMs = Math.round((end - timing.startTime) * 1000);
|
|
28251
|
-
|
|
28524
|
+
_this14.emit('segmentDone', {
|
|
28252
28525
|
segmentId: timing.segmentId,
|
|
28253
28526
|
status: 'finished',
|
|
28254
28527
|
playedMs: playedMs
|
|
@@ -28260,7 +28533,7 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
|
|
|
28260
28533
|
} finally {
|
|
28261
28534
|
_iterator3.f();
|
|
28262
28535
|
}
|
|
28263
|
-
|
|
28536
|
+
_this14.isCheckingTranscripts = false;
|
|
28264
28537
|
console.log('📝 AudioPlayer: Transcript checker stopped');
|
|
28265
28538
|
}
|
|
28266
28539
|
};
|
|
@@ -28291,43 +28564,43 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
|
|
|
28291
28564
|
}, {
|
|
28292
28565
|
key: "resumeAudioContext",
|
|
28293
28566
|
value: (function () {
|
|
28294
|
-
var _resumeAudioContext = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function
|
|
28567
|
+
var _resumeAudioContext = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee10() {
|
|
28295
28568
|
var _t7;
|
|
28296
|
-
return _regenerator().w(function (
|
|
28297
|
-
while (1) switch (
|
|
28569
|
+
return _regenerator().w(function (_context11) {
|
|
28570
|
+
while (1) switch (_context11.p = _context11.n) {
|
|
28298
28571
|
case 0:
|
|
28299
28572
|
if (!(!this.audioContext || this.audioContext.state === 'closed')) {
|
|
28300
|
-
|
|
28573
|
+
_context11.n = 2;
|
|
28301
28574
|
break;
|
|
28302
28575
|
}
|
|
28303
|
-
|
|
28576
|
+
_context11.n = 1;
|
|
28304
28577
|
return this.initializeAudioContext();
|
|
28305
28578
|
case 1:
|
|
28306
|
-
|
|
28579
|
+
_context11.n = 6;
|
|
28307
28580
|
break;
|
|
28308
28581
|
case 2:
|
|
28309
28582
|
if (!(this.audioContext.state === 'suspended')) {
|
|
28310
|
-
|
|
28583
|
+
_context11.n = 6;
|
|
28311
28584
|
break;
|
|
28312
28585
|
}
|
|
28313
|
-
|
|
28314
|
-
|
|
28586
|
+
_context11.p = 3;
|
|
28587
|
+
_context11.n = 4;
|
|
28315
28588
|
return this.audioContext.resume();
|
|
28316
28589
|
case 4:
|
|
28317
28590
|
console.log('✅ AudioPlayer v2: AudioContext resumed after mic permission');
|
|
28318
|
-
|
|
28591
|
+
_context11.n = 6;
|
|
28319
28592
|
break;
|
|
28320
28593
|
case 5:
|
|
28321
|
-
|
|
28322
|
-
_t7 =
|
|
28594
|
+
_context11.p = 5;
|
|
28595
|
+
_t7 = _context11.v;
|
|
28323
28596
|
console.warn('⚠️ AudioPlayer v2: Failed to resume AudioContext:', _t7);
|
|
28324
28597
|
case 6:
|
|
28325
|
-
|
|
28598
|
+
_context11.n = 7;
|
|
28326
28599
|
return this.waitForAudioContextReady();
|
|
28327
28600
|
case 7:
|
|
28328
|
-
return
|
|
28601
|
+
return _context11.a(2);
|
|
28329
28602
|
}
|
|
28330
|
-
},
|
|
28603
|
+
}, _callee10, this, [[3, 5]]);
|
|
28331
28604
|
}));
|
|
28332
28605
|
function resumeAudioContext() {
|
|
28333
28606
|
return _resumeAudioContext.apply(this, arguments);
|
|
@@ -28578,6 +28851,11 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
28578
28851
|
// Pass through undefined so AudioPlayer applies the platform default
|
|
28579
28852
|
return config.htmlAudioPlayback;
|
|
28580
28853
|
}(),
|
|
28854
|
+
// Opt-in: play TTS through a pair of local RTCPeerConnections so Chrome's
|
|
28855
|
+
// echo canceller can actually see it as a far-end reference (it ignores
|
|
28856
|
+
// <audio> elements). Default off — AudioPlayer also honours
|
|
28857
|
+
// ?ttp_loopback=1 / localStorage 'ttp_loopback' on its own.
|
|
28858
|
+
loopbackAec: config.loopbackAec,
|
|
28581
28859
|
// Protocol version
|
|
28582
28860
|
|
|
28583
28861
|
protocolVersion: config.protocolVersion || 2,
|
|
@@ -28650,6 +28928,9 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
28650
28928
|
_this.pendingInjections = new Map(); // Maps correlationId to { resolve, reject, timeout }
|
|
28651
28929
|
_this.injectionCounter = 0; // Counter for generating unique correlation IDs
|
|
28652
28930
|
|
|
28931
|
+
// One settled playback-route report per call (first segment audible).
|
|
28932
|
+
_this._playbackRouteSettledSent = false;
|
|
28933
|
+
|
|
28653
28934
|
// Barge-in detection is handled by the backend, not the frontend
|
|
28654
28935
|
// The backend analyzes the audio stream and sends 'barge_in' message when user interrupts
|
|
28655
28936
|
// Frontend only responds to backend barge-in messages
|
|
@@ -29062,6 +29343,18 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
29062
29343
|
}
|
|
29063
29344
|
_this3.emit('playbackStarted');
|
|
29064
29345
|
|
|
29346
|
+
// Unconditional settled playback-route report on first audible segment —
|
|
29347
|
+
// even when the route matches hello-time telemetry and no htmlAudioRoute
|
|
29348
|
+
// event fired afterward (e.g. loopback succeeded quietly).
|
|
29349
|
+
if (!_this3._playbackRouteSettledSent) {
|
|
29350
|
+
var _info$segmentId;
|
|
29351
|
+
_this3._playbackRouteSettledSent = true;
|
|
29352
|
+
_this3._sendClientAudioInfo(null, {
|
|
29353
|
+
settled: true,
|
|
29354
|
+
segmentId: (_info$segmentId = info === null || info === void 0 ? void 0 : info.segmentId) !== null && _info$segmentId !== void 0 ? _info$segmentId : null
|
|
29355
|
+
});
|
|
29356
|
+
}
|
|
29357
|
+
|
|
29065
29358
|
// Transcripts are displayed when they arrive (between sentences)
|
|
29066
29359
|
// No need to handle transcript display here - it's handled in handleTranscript()
|
|
29067
29360
|
|
|
@@ -29351,6 +29644,7 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
29351
29644
|
_this5.isConnected = false;
|
|
29352
29645
|
_this5.helloAckReceived = false;
|
|
29353
29646
|
_this5.disclaimersPending = false;
|
|
29647
|
+
_this5._playbackRouteSettledSent = false;
|
|
29354
29648
|
|
|
29355
29649
|
// Discard any audio still held by the first-playback gate
|
|
29356
29650
|
_this5._dropPlaybackGate();
|
|
@@ -29468,7 +29762,7 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
29468
29762
|
key: "_buildClientEnv",
|
|
29469
29763
|
value: function _buildClientEnv() {
|
|
29470
29764
|
try {
|
|
29471
|
-
var _uaData$mobile, _window$screen, _window$screen2;
|
|
29765
|
+
var _uaData$mobile, _window$screen, _window$screen2, _this$audioPlayer, _this$audioPlayer$get;
|
|
29472
29766
|
var ua = navigator.userAgent || '';
|
|
29473
29767
|
var uaData = navigator.userAgentData;
|
|
29474
29768
|
var conn = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
|
|
@@ -29477,8 +29771,8 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
29477
29771
|
// Webview heuristic: Android WebView marks itself with "; wv)" or "Version/x.x Chrome";
|
|
29478
29772
|
// iOS in-app webviews lack "Safari" in the UA (real Safari always has it).
|
|
29479
29773
|
var webview = isAndroid && (/\bwv\b/.test(ua) || /Version\/[\d.]+.*Chrome/.test(ua)) || isIos && !/Safari/i.test(ua) || false;
|
|
29480
|
-
var env = {
|
|
29481
|
-
sdkVersion: true ? "2.48.
|
|
29774
|
+
var env = _objectSpread({
|
|
29775
|
+
sdkVersion: true ? "2.48.21" : 0,
|
|
29482
29776
|
ua: ua,
|
|
29483
29777
|
platform: (uaData === null || uaData === void 0 ? void 0 : uaData.platform) || navigator.platform || '',
|
|
29484
29778
|
mobile: (_uaData$mobile = uaData === null || uaData === void 0 ? void 0 : uaData.mobile) !== null && _uaData$mobile !== void 0 ? _uaData$mobile : isAndroid || isIos,
|
|
@@ -29488,34 +29782,43 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
29488
29782
|
cores: navigator.hardwareConcurrency || null,
|
|
29489
29783
|
memoryGb: navigator.deviceMemory || null,
|
|
29490
29784
|
connection: (conn === null || conn === void 0 ? void 0 : conn.effectiveType) || null
|
|
29491
|
-
}
|
|
29785
|
+
}, ((_this$audioPlayer = this.audioPlayer) === null || _this$audioPlayer === void 0 || (_this$audioPlayer$get = _this$audioPlayer.getPlaybackRouteReport) === null || _this$audioPlayer$get === void 0 ? void 0 : _this$audioPlayer$get.call(_this$audioPlayer)) || {
|
|
29786
|
+
htmlAudioPlayback: null,
|
|
29787
|
+
playbackRoute: 'destination',
|
|
29788
|
+
loopbackAttach: {
|
|
29789
|
+
outcome: 'not_attempted'
|
|
29790
|
+
}
|
|
29791
|
+
});
|
|
29492
29792
|
return env;
|
|
29493
29793
|
} catch (e) {
|
|
29494
29794
|
console.warn('⚠️ VoiceSDK v2: Failed to build client env:', e);
|
|
29495
29795
|
return {
|
|
29496
|
-
sdkVersion: true ? "2.48.
|
|
29796
|
+
sdkVersion: true ? "2.48.21" : 0
|
|
29497
29797
|
};
|
|
29498
29798
|
}
|
|
29499
29799
|
}
|
|
29500
29800
|
|
|
29501
29801
|
/**
|
|
29502
|
-
*
|
|
29503
|
-
*
|
|
29504
|
-
*
|
|
29505
|
-
* requested), which is the ground truth for diagnosing speakerphone echo barge-in —
|
|
29506
|
-
* plus mic label, AudioContext rates, and whether the minimal-constraints fallback fired.
|
|
29802
|
+
* Telemetry sent as t:'client_audio_info'. Interim snapshots (capture start,
|
|
29803
|
+
* htmlAudioRoute transitions) use routeReportKind:'interim'. The first audible
|
|
29804
|
+
* segment emits routeReportKind:'settled' exactly once per connection.
|
|
29507
29805
|
*/
|
|
29508
29806
|
}, {
|
|
29509
29807
|
key: "_sendClientAudioInfo",
|
|
29510
29808
|
value: function _sendClientAudioInfo(routeUpdate) {
|
|
29809
|
+
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
29511
29810
|
try {
|
|
29512
|
-
var _this$audioRecorder, _this$audioRecorder$g, _s$echoCancellation, _s$noiseSuppression, _s$autoGainControl, _s$voiceIsolation, _s$sampleRate, _s$channelCount, _this$audioRecorder2, _this$
|
|
29811
|
+
var _this$audioRecorder, _this$audioRecorder$g, _s$echoCancellation, _s$noiseSuppression, _s$autoGainControl, _s$voiceIsolation, _s$sampleRate, _s$channelCount, _this$audioRecorder2, _this$audioPlayer2, _this$audioRecorder3, _this$audioPlayer3, _this$audioPlayer3$ge;
|
|
29812
|
+
var settled = options.settled === true;
|
|
29513
29813
|
var track = (_this$audioRecorder = this.audioRecorder) === null || _this$audioRecorder === void 0 || (_this$audioRecorder = _this$audioRecorder.mediaStream) === null || _this$audioRecorder === void 0 || (_this$audioRecorder$g = _this$audioRecorder.getAudioTracks) === null || _this$audioRecorder$g === void 0 ? void 0 : _this$audioRecorder$g.call(_this$audioRecorder)[0];
|
|
29514
29814
|
// Route updates must go out even before the mic track exists — the hop
|
|
29515
|
-
// state is the whole point of the follow-up.
|
|
29516
|
-
if (
|
|
29815
|
+
// state is the whole point of the follow-up. Settled reports go out even
|
|
29816
|
+
// if capture never started (monitor / playback-only paths).
|
|
29817
|
+
if (!track && !routeUpdate && !settled) return;
|
|
29517
29818
|
var s = track && track.getSettings ? track.getSettings() : {};
|
|
29518
29819
|
var audio = _objectSpread({
|
|
29820
|
+
sdkVersion: true ? "2.48.21" : 0,
|
|
29821
|
+
routeReportKind: settled ? 'settled' : 'interim',
|
|
29519
29822
|
aec: (_s$echoCancellation = s.echoCancellation) !== null && _s$echoCancellation !== void 0 ? _s$echoCancellation : null,
|
|
29520
29823
|
ns: (_s$noiseSuppression = s.noiseSuppression) !== null && _s$noiseSuppression !== void 0 ? _s$noiseSuppression : null,
|
|
29521
29824
|
agc: (_s$autoGainControl = s.autoGainControl) !== null && _s$autoGainControl !== void 0 ? _s$autoGainControl : null,
|
|
@@ -29524,18 +29827,21 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
29524
29827
|
channels: (_s$channelCount = s.channelCount) !== null && _s$channelCount !== void 0 ? _s$channelCount : null,
|
|
29525
29828
|
mic: track ? track.label || null : null,
|
|
29526
29829
|
captureCtxRate: ((_this$audioRecorder2 = this.audioRecorder) === null || _this$audioRecorder2 === void 0 || (_this$audioRecorder2 = _this$audioRecorder2.audioContext) === null || _this$audioRecorder2 === void 0 ? void 0 : _this$audioRecorder2.sampleRate) || null,
|
|
29527
|
-
playbackCtxRate: ((_this$
|
|
29830
|
+
playbackCtxRate: ((_this$audioPlayer2 = this.audioPlayer) === null || _this$audioPlayer2 === void 0 || (_this$audioPlayer2 = _this$audioPlayer2.audioContext) === null || _this$audioPlayer2 === void 0 ? void 0 : _this$audioPlayer2.sampleRate) || null,
|
|
29528
29831
|
constraintsFallback: ((_this$audioRecorder3 = this.audioRecorder) === null || _this$audioRecorder3 === void 0 || (_this$audioRecorder3 = _this$audioRecorder3.mediaStream) === null || _this$audioRecorder3 === void 0 ? void 0 : _this$audioRecorder3._ttpConstraintsFallback) === true
|
|
29529
|
-
}, ((_this$
|
|
29832
|
+
}, ((_this$audioPlayer3 = this.audioPlayer) === null || _this$audioPlayer3 === void 0 || (_this$audioPlayer3$ge = _this$audioPlayer3.getPlaybackRouteReport) === null || _this$audioPlayer3$ge === void 0 ? void 0 : _this$audioPlayer3$ge.call(_this$audioPlayer3)) || {});
|
|
29833
|
+
if (settled && options.segmentId != null) {
|
|
29834
|
+
audio.settledAtSegmentId = options.segmentId;
|
|
29835
|
+
}
|
|
29530
29836
|
if (routeUpdate && routeUpdate.state) {
|
|
29531
|
-
audio.routeUpdate = routeUpdate.state; // 'established' | 'fallback' | 'play_pending'
|
|
29837
|
+
audio.routeUpdate = routeUpdate.state; // 'established' | 'fallback' | 'play_pending' | ...
|
|
29532
29838
|
if (routeUpdate.reason) audio.routeFallbackReason = routeUpdate.reason;
|
|
29533
29839
|
}
|
|
29534
29840
|
this.sendMessage({
|
|
29535
29841
|
t: 'client_audio_info',
|
|
29536
29842
|
audio: audio
|
|
29537
29843
|
});
|
|
29538
|
-
console.log(
|
|
29844
|
+
console.log("\uD83C\uDF9B\uFE0F VoiceSDK v2: Sent client_audio_info (".concat(audio.routeReportKind, "):"), audio);
|
|
29539
29845
|
} catch (e) {
|
|
29540
29846
|
console.warn('⚠️ VoiceSDK v2: Failed to send client_audio_info:', e);
|
|
29541
29847
|
}
|
|
@@ -29641,7 +29947,7 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
29641
29947
|
|
|
29642
29948
|
// Include SDK build time for debugging
|
|
29643
29949
|
if (true) {
|
|
29644
|
-
helloMessage.lastBuildTime = "2026-08-
|
|
29950
|
+
helloMessage.lastBuildTime = "2026-08-27T17:29:05.172Z";
|
|
29645
29951
|
}
|
|
29646
29952
|
|
|
29647
29953
|
// Client environment (device/browser/webview) for backend logs + Langfuse metadata
|
|
@@ -32359,6 +32665,283 @@ function readTtpHopOverride(win) {
|
|
|
32359
32665
|
|
|
32360
32666
|
/***/ }),
|
|
32361
32667
|
|
|
32668
|
+
/***/ "./src/v2/loopbackAec.js":
|
|
32669
|
+
/*!*******************************!*\
|
|
32670
|
+
!*** ./src/v2/loopbackAec.js ***!
|
|
32671
|
+
\*******************************/
|
|
32672
|
+
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
32673
|
+
|
|
32674
|
+
"use strict";
|
|
32675
|
+
__webpack_require__.r(__webpack_exports__);
|
|
32676
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
32677
|
+
/* harmony export */ TTP_LOOPBACK_SESSION_KEY: () => (/* binding */ TTP_LOOPBACK_SESSION_KEY),
|
|
32678
|
+
/* harmony export */ createAecLoopback: () => (/* binding */ createAecLoopback),
|
|
32679
|
+
/* harmony export */ isLoopbackAecSupported: () => (/* binding */ isLoopbackAecSupported),
|
|
32680
|
+
/* harmony export */ preferHighQualityOpus: () => (/* binding */ preferHighQualityOpus),
|
|
32681
|
+
/* harmony export */ readTtpLoopbackOverride: () => (/* binding */ readTtpLoopbackOverride)
|
|
32682
|
+
/* harmony export */ });
|
|
32683
|
+
function _regenerator() { /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/babel/babel/blob/main/packages/babel-helpers/LICENSE */ var e, t, r = "function" == typeof Symbol ? Symbol : {}, n = r.iterator || "@@iterator", o = r.toStringTag || "@@toStringTag"; function i(r, n, o, i) { var c = n && n.prototype instanceof Generator ? n : Generator, u = Object.create(c.prototype); return _regeneratorDefine2(u, "_invoke", function (r, n, o) { var i, c, u, f = 0, p = o || [], y = !1, G = { p: 0, n: 0, v: e, a: d, f: d.bind(e, 4), d: function d(t, r) { return i = t, c = 0, u = e, G.n = r, a; } }; function d(r, n) { for (c = r, u = n, t = 0; !y && f && !o && t < p.length; t++) { var o, i = p[t], d = G.p, l = i[2]; r > 3 ? (o = l === n) && (u = i[(c = i[4]) ? 5 : (c = 3, 3)], i[4] = i[5] = e) : i[0] <= d && ((o = r < 2 && d < i[1]) ? (c = 0, G.v = n, G.n = i[1]) : d < l && (o = r < 3 || i[0] > n || n > l) && (i[4] = r, i[5] = n, G.n = l, c = 0)); } if (o || r > 1) return a; throw y = !0, n; } return function (o, p, l) { if (f > 1) throw TypeError("Generator is already running"); for (y && 1 === p && d(p, l), c = p, u = l; (t = c < 2 ? e : u) || !y;) { i || (c ? c < 3 ? (c > 1 && (G.n = -1), d(c, u)) : G.n = u : G.v = u); try { if (f = 2, i) { if (c || (o = "next"), t = i[o]) { if (!(t = t.call(i, u))) throw TypeError("iterator result is not an object"); if (!t.done) return t; u = t.value, c < 2 && (c = 0); } else 1 === c && (t = i.return) && t.call(i), c < 2 && (u = TypeError("The iterator does not provide a '" + o + "' method"), c = 1); i = e; } else if ((t = (y = G.n < 0) ? u : r.call(n, G)) !== a) break; } catch (t) { i = e, c = 1, u = t; } finally { f = 1; } } return { value: t, done: y }; }; }(r, o, i), !0), u; } var a = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} t = Object.getPrototypeOf; var c = [][n] ? t(t([][n]())) : (_regeneratorDefine2(t = {}, n, function () { return this; }), t), u = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(c); function f(e) { return Object.setPrototypeOf ? Object.setPrototypeOf(e, GeneratorFunctionPrototype) : (e.__proto__ = GeneratorFunctionPrototype, _regeneratorDefine2(e, o, "GeneratorFunction")), e.prototype = Object.create(u), e; } return GeneratorFunction.prototype = GeneratorFunctionPrototype, _regeneratorDefine2(u, "constructor", GeneratorFunctionPrototype), _regeneratorDefine2(GeneratorFunctionPrototype, "constructor", GeneratorFunction), GeneratorFunction.displayName = "GeneratorFunction", _regeneratorDefine2(GeneratorFunctionPrototype, o, "GeneratorFunction"), _regeneratorDefine2(u), _regeneratorDefine2(u, o, "Generator"), _regeneratorDefine2(u, n, function () { return this; }), _regeneratorDefine2(u, "toString", function () { return "[object Generator]"; }), (_regenerator = function _regenerator() { return { w: i, m: f }; })(); }
|
|
32684
|
+
function _regeneratorDefine2(e, r, n, t) { var i = Object.defineProperty; try { i({}, "", {}); } catch (e) { i = 0; } _regeneratorDefine2 = function _regeneratorDefine(e, r, n, t) { function o(r, n) { _regeneratorDefine2(e, r, function (e) { return this._invoke(r, n, e); }); } r ? i ? i(e, r, { value: n, enumerable: !t, configurable: !t, writable: !t }) : e[r] = n : (o("next", 0), o("throw", 1), o("return", 2)); }, _regeneratorDefine2(e, r, n, t); }
|
|
32685
|
+
function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); }
|
|
32686
|
+
function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; }
|
|
32687
|
+
/**
|
|
32688
|
+
* Local WebRTC loopback for echo cancellation.
|
|
32689
|
+
*
|
|
32690
|
+
* WHY THIS EXISTS. Chrome's echo canceller only cancels audio that arrived
|
|
32691
|
+
* through a WebRTC peer connection — not <audio> elements, not Web Audio.
|
|
32692
|
+
* (Firefox/Safari/Edge consider all browser audio; Chrome does not.) That is
|
|
32693
|
+
* why the HTML hop — AudioContext → MediaStreamDestination → hidden <audio> —
|
|
32694
|
+
* never reliably fixed speaker echo on Chrome: where it appeared to work, what
|
|
32695
|
+
* actually helped was Chrome-wide echo cancellation, a separate system-level
|
|
32696
|
+
* feature that is not always available. Two people at the same customer, same
|
|
32697
|
+
* OS class, both on speakers, got opposite results from the same build.
|
|
32698
|
+
*
|
|
32699
|
+
* The fix is to make TTS *actually be* peer-connection audio: wire two
|
|
32700
|
+
* RTCPeerConnections together inside this tab and push playback through them.
|
|
32701
|
+
* The remote track is then far-end reference material Chrome's AEC will
|
|
32702
|
+
* cancel. No server, no SFU, no TURN, no ports — both ends are local and ICE
|
|
32703
|
+
* never leaves the host.
|
|
32704
|
+
*
|
|
32705
|
+
* Cost is one Opus encode/decode (~20-40 ms added latency, and lossy
|
|
32706
|
+
* compression of TTS that was already lossy over the wire). Bitrate is munged
|
|
32707
|
+
* up because the "link" is a memcpy; see preferHighQualityOpus.
|
|
32708
|
+
*
|
|
32709
|
+
* Kept free of AudioPlayer state and injectable so the peer-connection dance
|
|
32710
|
+
* is unit-testable without a browser: see test/loopback-aec.test.mjs.
|
|
32711
|
+
*/
|
|
32712
|
+
|
|
32713
|
+
/** sessionStorage key mirroring an explicit ?ttp_loopback= URL value. */
|
|
32714
|
+
var TTP_LOOPBACK_SESSION_KEY = 'ttp_loopback_pref';
|
|
32715
|
+
|
|
32716
|
+
/**
|
|
32717
|
+
* QA/rollout override for the loopback route. true (force on), false (force
|
|
32718
|
+
* off), or null (no override — apply config, which defaults off).
|
|
32719
|
+
*
|
|
32720
|
+
* Precedence and the sessionStorage mirror match readTtpHopOverride for the
|
|
32721
|
+
* same reason: Borusan's navigate_to_form does window.location.href = '/path',
|
|
32722
|
+
* a same-origin full load that drops the query string mid-call (call
|
|
32723
|
+
* 84b5af7d). Without the mirror the route would silently revert on the very
|
|
32724
|
+
* navigation the tester is exercising.
|
|
32725
|
+
*/
|
|
32726
|
+
function readTtpLoopbackOverride(win) {
|
|
32727
|
+
var w = win || (typeof window !== 'undefined' ? window : null);
|
|
32728
|
+
if (!w) return null;
|
|
32729
|
+
var flag = null;
|
|
32730
|
+
try {
|
|
32731
|
+
flag = new URLSearchParams(w.location.search).get('ttp_loopback');
|
|
32732
|
+
} catch (e) {/* no location in this env */}
|
|
32733
|
+
if (flag === '0' || flag === '1') {
|
|
32734
|
+
try {
|
|
32735
|
+
w.sessionStorage.setItem(TTP_LOOPBACK_SESSION_KEY, flag);
|
|
32736
|
+
} catch (e) {/* storage blocked */}
|
|
32737
|
+
return flag === '1';
|
|
32738
|
+
}
|
|
32739
|
+
var mirrored = null;
|
|
32740
|
+
try {
|
|
32741
|
+
mirrored = w.sessionStorage.getItem(TTP_LOOPBACK_SESSION_KEY);
|
|
32742
|
+
} catch (e) {/* storage blocked */}
|
|
32743
|
+
if (mirrored === '0' || mirrored === '1') return mirrored === '1';
|
|
32744
|
+
var stored = null;
|
|
32745
|
+
try {
|
|
32746
|
+
stored = w.localStorage.getItem('ttp_loopback');
|
|
32747
|
+
} catch (e) {/* storage blocked */}
|
|
32748
|
+
if (stored === '0' || stored === '1') return stored === '1';
|
|
32749
|
+
return null;
|
|
32750
|
+
}
|
|
32751
|
+
function isLoopbackAecSupported(win) {
|
|
32752
|
+
var w = win || (typeof window !== 'undefined' ? window : null);
|
|
32753
|
+
if (!w) return false;
|
|
32754
|
+
return typeof w.RTCPeerConnection === 'function' && typeof w.MediaStream === 'function';
|
|
32755
|
+
}
|
|
32756
|
+
|
|
32757
|
+
/**
|
|
32758
|
+
* Raise Opus quality on a loopback that has no bandwidth cost, and disable the
|
|
32759
|
+
* two features that are wrong for synthesized speech on a local link:
|
|
32760
|
+
*
|
|
32761
|
+
* - usedtx=0: discontinuous transmission replaces "silence" with comfort
|
|
32762
|
+
* noise. TTS leading/trailing silence is real audio the segment ledger
|
|
32763
|
+
* accounts for; letting the codec invent it would desynchronize playedMs.
|
|
32764
|
+
* - maxaveragebitrate: the default ~32 kbps is chosen for real networks. This
|
|
32765
|
+
* link is a memcpy, so spend bits instead of degrading a voice the customer
|
|
32766
|
+
* is paying for.
|
|
32767
|
+
*
|
|
32768
|
+
* Returns the SDP unchanged if there is no Opus line to munge — never throws,
|
|
32769
|
+
* because a failed munge must not cost us the route.
|
|
32770
|
+
*/
|
|
32771
|
+
function preferHighQualityOpus(sdp) {
|
|
32772
|
+
var bitrate = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 128000;
|
|
32773
|
+
if (typeof sdp !== 'string' || !sdp) return sdp;
|
|
32774
|
+
var rtpmap = sdp.match(/^a=rtpmap:(\d+)\s+opus\/48000(?:\/2)?/mi);
|
|
32775
|
+
if (!rtpmap) return sdp;
|
|
32776
|
+
var pt = rtpmap[1];
|
|
32777
|
+
var params = "stereo=0;useinbandfec=1;usedtx=0;maxaveragebitrate=".concat(bitrate);
|
|
32778
|
+
var fmtpRe = new RegExp("^a=fmtp:".concat(pt, " (.*)$"), 'mi');
|
|
32779
|
+
if (fmtpRe.test(sdp)) {
|
|
32780
|
+
return sdp.replace(fmtpRe, function (line, existing) {
|
|
32781
|
+
// Drop any key we are about to set, keep everything else the browser chose.
|
|
32782
|
+
var kept = existing.split(';').filter(function (kv) {
|
|
32783
|
+
return !/^\s*(stereo|useinbandfec|usedtx|maxaveragebitrate)\s*=/i.test(kv);
|
|
32784
|
+
}).filter(function (kv) {
|
|
32785
|
+
return kv.trim().length > 0;
|
|
32786
|
+
});
|
|
32787
|
+
return "a=fmtp:".concat(pt, " ").concat(kept.concat(params.split(';')).join(';'));
|
|
32788
|
+
});
|
|
32789
|
+
}
|
|
32790
|
+
return sdp.replace(rtpmap[0], "".concat(rtpmap[0], "\r\na=fmtp:").concat(pt, " ").concat(params));
|
|
32791
|
+
}
|
|
32792
|
+
|
|
32793
|
+
/**
|
|
32794
|
+
* Wire two peer connections together in this tab and return the remote end of
|
|
32795
|
+
* the given stream.
|
|
32796
|
+
*
|
|
32797
|
+
* Resolves { remoteStream, close } once the receiving side reports connected
|
|
32798
|
+
* AND a track has arrived — both, because either alone has been seen without
|
|
32799
|
+
* audible audio. Rejects on timeout so a stalled negotiation degrades to the
|
|
32800
|
+
* caller's existing route rather than leaving the call silent.
|
|
32801
|
+
*
|
|
32802
|
+
* Dependencies are injected (win) so this runs under node --test.
|
|
32803
|
+
*/
|
|
32804
|
+
function createAecLoopback() {
|
|
32805
|
+
var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
|
|
32806
|
+
stream = _ref.stream,
|
|
32807
|
+
win = _ref.win,
|
|
32808
|
+
_ref$timeoutMs = _ref.timeoutMs,
|
|
32809
|
+
timeoutMs = _ref$timeoutMs === void 0 ? 4000 : _ref$timeoutMs,
|
|
32810
|
+
_ref$bitrate = _ref.bitrate,
|
|
32811
|
+
bitrate = _ref$bitrate === void 0 ? 128000 : _ref$bitrate;
|
|
32812
|
+
var w = win || (typeof window !== 'undefined' ? window : null);
|
|
32813
|
+
if (!w) return Promise.reject(new Error('loopback: no window'));
|
|
32814
|
+
if (!isLoopbackAecSupported(w)) return Promise.reject(new Error('loopback: RTCPeerConnection unavailable'));
|
|
32815
|
+
var tracks = stream && typeof stream.getAudioTracks === 'function' ? stream.getAudioTracks() : [];
|
|
32816
|
+
if (!tracks.length) return Promise.reject(new Error('loopback: source stream has no audio track'));
|
|
32817
|
+
|
|
32818
|
+
// No ICE servers: both ends are in this process, so host candidates are the
|
|
32819
|
+
// only ones that can possibly be useful. Asking for STUN would leak the
|
|
32820
|
+
// user's IP to a third party for a connection that never leaves the tab.
|
|
32821
|
+
var pcSend = new w.RTCPeerConnection({
|
|
32822
|
+
iceServers: []
|
|
32823
|
+
});
|
|
32824
|
+
var pcRecv = new w.RTCPeerConnection({
|
|
32825
|
+
iceServers: []
|
|
32826
|
+
});
|
|
32827
|
+
var settled = false;
|
|
32828
|
+
var timer = null;
|
|
32829
|
+
var remoteStream = new w.MediaStream();
|
|
32830
|
+
var close = function close() {
|
|
32831
|
+
if (timer) {
|
|
32832
|
+
clearTimeout(timer);
|
|
32833
|
+
timer = null;
|
|
32834
|
+
}
|
|
32835
|
+
try {
|
|
32836
|
+
pcSend.close();
|
|
32837
|
+
} catch (e) {/* already closed */}
|
|
32838
|
+
try {
|
|
32839
|
+
pcRecv.close();
|
|
32840
|
+
} catch (e) {/* already closed */}
|
|
32841
|
+
};
|
|
32842
|
+
return new Promise(function (resolve, reject) {
|
|
32843
|
+
var fail = function fail(err) {
|
|
32844
|
+
if (settled) return;
|
|
32845
|
+
settled = true;
|
|
32846
|
+
close();
|
|
32847
|
+
reject(err instanceof Error ? err : new Error(String(err)));
|
|
32848
|
+
};
|
|
32849
|
+
var maybeResolve = function maybeResolve() {
|
|
32850
|
+
if (settled) return;
|
|
32851
|
+
if (!remoteStream.getAudioTracks().length) return;
|
|
32852
|
+
var state = pcRecv.connectionState || pcRecv.iceConnectionState;
|
|
32853
|
+
if (state !== 'connected' && state !== 'completed') return;
|
|
32854
|
+
settled = true;
|
|
32855
|
+
if (timer) {
|
|
32856
|
+
clearTimeout(timer);
|
|
32857
|
+
timer = null;
|
|
32858
|
+
}
|
|
32859
|
+
resolve({
|
|
32860
|
+
remoteStream: remoteStream,
|
|
32861
|
+
close: close,
|
|
32862
|
+
pcSend: pcSend,
|
|
32863
|
+
pcRecv: pcRecv
|
|
32864
|
+
});
|
|
32865
|
+
};
|
|
32866
|
+
timer = setTimeout(function () {
|
|
32867
|
+
return fail(new Error('loopback: negotiation timed out'));
|
|
32868
|
+
}, timeoutMs);
|
|
32869
|
+
pcSend.onicecandidate = function (e) {
|
|
32870
|
+
if (e.candidate) {
|
|
32871
|
+
try {
|
|
32872
|
+
pcRecv.addIceCandidate(e.candidate);
|
|
32873
|
+
} catch (err) {/* late candidate */}
|
|
32874
|
+
}
|
|
32875
|
+
};
|
|
32876
|
+
pcRecv.onicecandidate = function (e) {
|
|
32877
|
+
if (e.candidate) {
|
|
32878
|
+
try {
|
|
32879
|
+
pcSend.addIceCandidate(e.candidate);
|
|
32880
|
+
} catch (err) {/* late candidate */}
|
|
32881
|
+
}
|
|
32882
|
+
};
|
|
32883
|
+
pcRecv.ontrack = function (e) {
|
|
32884
|
+
var track = e.track || e.streams && e.streams[0] && e.streams[0].getAudioTracks()[0];
|
|
32885
|
+
if (track) remoteStream.addTrack(track);
|
|
32886
|
+
maybeResolve();
|
|
32887
|
+
};
|
|
32888
|
+
pcRecv.onconnectionstatechange = function () {
|
|
32889
|
+
var s = pcRecv.connectionState;
|
|
32890
|
+
if (s === 'failed' || s === 'closed') return fail(new Error("loopback: receiver ".concat(s)));
|
|
32891
|
+
maybeResolve();
|
|
32892
|
+
};
|
|
32893
|
+
pcRecv.oniceconnectionstatechange = function () {
|
|
32894
|
+
var s = pcRecv.iceConnectionState;
|
|
32895
|
+
if (s === 'failed') return fail(new Error('loopback: ice failed'));
|
|
32896
|
+
maybeResolve();
|
|
32897
|
+
};
|
|
32898
|
+
_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee() {
|
|
32899
|
+
var offer, tunedOffer, answer, tunedAnswer;
|
|
32900
|
+
return _regenerator().w(function (_context) {
|
|
32901
|
+
while (1) switch (_context.n) {
|
|
32902
|
+
case 0:
|
|
32903
|
+
tracks.forEach(function (t) {
|
|
32904
|
+
return pcSend.addTrack(t, stream);
|
|
32905
|
+
});
|
|
32906
|
+
_context.n = 1;
|
|
32907
|
+
return pcSend.createOffer();
|
|
32908
|
+
case 1:
|
|
32909
|
+
offer = _context.v;
|
|
32910
|
+
tunedOffer = {
|
|
32911
|
+
type: offer.type,
|
|
32912
|
+
sdp: preferHighQualityOpus(offer.sdp, bitrate)
|
|
32913
|
+
};
|
|
32914
|
+
_context.n = 2;
|
|
32915
|
+
return pcSend.setLocalDescription(tunedOffer);
|
|
32916
|
+
case 2:
|
|
32917
|
+
_context.n = 3;
|
|
32918
|
+
return pcRecv.setRemoteDescription(tunedOffer);
|
|
32919
|
+
case 3:
|
|
32920
|
+
_context.n = 4;
|
|
32921
|
+
return pcRecv.createAnswer();
|
|
32922
|
+
case 4:
|
|
32923
|
+
answer = _context.v;
|
|
32924
|
+
tunedAnswer = {
|
|
32925
|
+
type: answer.type,
|
|
32926
|
+
sdp: preferHighQualityOpus(answer.sdp, bitrate)
|
|
32927
|
+
};
|
|
32928
|
+
_context.n = 5;
|
|
32929
|
+
return pcRecv.setLocalDescription(tunedAnswer);
|
|
32930
|
+
case 5:
|
|
32931
|
+
_context.n = 6;
|
|
32932
|
+
return pcSend.setRemoteDescription(tunedAnswer);
|
|
32933
|
+
case 6:
|
|
32934
|
+
maybeResolve();
|
|
32935
|
+
case 7:
|
|
32936
|
+
return _context.a(2);
|
|
32937
|
+
}
|
|
32938
|
+
}, _callee);
|
|
32939
|
+
}))().catch(fail);
|
|
32940
|
+
});
|
|
32941
|
+
}
|
|
32942
|
+
|
|
32943
|
+
/***/ }),
|
|
32944
|
+
|
|
32362
32945
|
/***/ "./src/v2/utils/AudioFormatConverter.js":
|
|
32363
32946
|
/*!**********************************************!*\
|
|
32364
32947
|
!*** ./src/v2/utils/AudioFormatConverter.js ***!
|
|
@@ -35963,7 +36546,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
35963
36546
|
return;
|
|
35964
36547
|
}
|
|
35965
36548
|
this._ensureAboutStyles();
|
|
35966
|
-
var version = true ? "2.48.
|
|
36549
|
+
var version = true ? "2.48.21" : 0;
|
|
35967
36550
|
var convId = this._getLastConversationId();
|
|
35968
36551
|
var t = function t(k, fb) {
|
|
35969
36552
|
try {
|