@hivegpt/hiveai-angular 0.0.569 → 0.0.570

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.
@@ -1437,67 +1437,43 @@
1437
1437
  },] }
1438
1438
  ];
1439
1439
 
1440
- /**
1441
- * Daily.js WebRTC client for voice agent audio.
1442
- * Responsibilities:
1443
- * - Create and manage Daily CallObject
1444
- * - Join Daily room using room_url
1445
- * - Handle mic capture + speaker playback
1446
- * - Bot speaking detection via AnalyserNode on remote track (instant)
1447
- * - User speaking detection via active-speaker-change
1448
- * - Expose speaking$ (bot speaking), userSpeaking$ (user speaking), micMuted$
1449
- * - Expose localStream$ for waveform visualization (AudioAnalyzerService)
1450
- */
1451
1440
  var DailyVoiceClientService = /** @class */ (function () {
1452
1441
  function DailyVoiceClientService(ngZone) {
1453
1442
  this.ngZone = ngZone;
1454
1443
  this.callObject = null;
1455
1444
  this.localStream = null;
1456
1445
  this.localSessionId = null;
1457
- /** Explicit playback of remote (bot) audio; required in some browsers. */
1458
1446
  this.remoteAudioElement = null;
1459
- /** AnalyserNode-based remote audio monitor for instant bot speaking detection. */
1460
1447
  this.remoteAudioContext = null;
1461
1448
  this.remoteSpeakingRAF = null;
1462
1449
  this.speakingSubject = new rxjs.BehaviorSubject(false);
1463
1450
  this.userSpeakingSubject = new rxjs.BehaviorSubject(false);
1464
- this.micMutedSubject = new rxjs.BehaviorSubject(false);
1451
+ this.micMutedSubject = new rxjs.BehaviorSubject(true); // 🔴 default muted
1465
1452
  this.localStreamSubject = new rxjs.BehaviorSubject(null);
1466
- /** True when bot (remote participant) is the active speaker. */
1467
1453
  this.speaking$ = this.speakingSubject.asObservable();
1468
- /** True when user (local participant) is the active speaker. */
1469
1454
  this.userSpeaking$ = this.userSpeakingSubject.asObservable();
1470
- /** True when mic is muted. */
1471
1455
  this.micMuted$ = this.micMutedSubject.asObservable();
1472
- /** Emits local mic stream for waveform visualization. */
1473
1456
  this.localStream$ = this.localStreamSubject.asObservable();
1474
1457
  }
1475
- /**
1476
- * Connect to Daily room. Acquires mic first for waveform, then joins with audio.
1477
- * @param roomUrl Daily room URL (from room_created)
1478
- * @param token Optional meeting token
1479
- */
1480
1458
  DailyVoiceClientService.prototype.connect = function (roomUrl, token) {
1481
1459
  return __awaiter(this, void 0, void 0, function () {
1482
1460
  var stream, audioTrack, callObject, joinOptions, participants, err_1;
1483
- return __generator(this, function (_e) {
1484
- switch (_e.label) {
1461
+ return __generator(this, function (_f) {
1462
+ switch (_f.label) {
1485
1463
  case 0:
1486
1464
  if (!this.callObject) return [3 /*break*/, 2];
1487
1465
  return [4 /*yield*/, this.disconnect()];
1488
1466
  case 1:
1489
- _e.sent();
1490
- _e.label = 2;
1467
+ _f.sent();
1468
+ _f.label = 2;
1491
1469
  case 2:
1492
- _e.trys.push([2, 5, , 6]);
1470
+ _f.trys.push([2, 5, , 6]);
1493
1471
  return [4 /*yield*/, navigator.mediaDevices.getUserMedia({ audio: true })];
1494
1472
  case 3:
1495
- stream = _e.sent();
1473
+ stream = _f.sent();
1496
1474
  audioTrack = stream.getAudioTracks()[0];
1497
- if (!audioTrack) {
1498
- stream.getTracks().forEach(function (t) { return t.stop(); });
1475
+ if (!audioTrack)
1499
1476
  throw new Error('No audio track');
1500
- }
1501
1477
  this.localStream = stream;
1502
1478
  this.localStreamSubject.next(stream);
1503
1479
  callObject = Daily__default["default"].createCallObject({
@@ -1506,23 +1482,27 @@
1506
1482
  });
1507
1483
  this.callObject = callObject;
1508
1484
  this.setupEventHandlers(callObject);
1485
+ // 🔴 Ensure mic is OFF before join
1486
+ callObject.setLocalAudio(false);
1487
+ this.micMutedSubject.next(true);
1509
1488
  joinOptions = { url: roomUrl };
1510
- if (typeof token === 'string' && token.trim() !== '') {
1489
+ if (typeof token === 'string' && token.trim()) {
1511
1490
  joinOptions.token = token;
1512
1491
  }
1513
1492
  return [4 /*yield*/, callObject.join(joinOptions)];
1514
1493
  case 4:
1515
- _e.sent();
1516
- console.log("[VoiceDebug] Room connected (Daily join complete) \u2014 " + new Date().toISOString());
1494
+ _f.sent();
1495
+ console.log("[VoiceDebug] Joined room \u2014 " + new Date().toISOString());
1517
1496
  participants = callObject.participants();
1518
1497
  if (participants === null || participants === void 0 ? void 0 : participants.local) {
1519
1498
  this.localSessionId = participants.local.session_id;
1520
1499
  }
1521
- // Initial mute state: Daily starts with audio on
1522
- this.micMutedSubject.next(!callObject.localAudio());
1500
+ // 🔴 Force sync again (Daily sometimes overrides)
1501
+ callObject.setLocalAudio(false);
1502
+ this.micMutedSubject.next(true);
1523
1503
  return [3 /*break*/, 6];
1524
1504
  case 5:
1525
- err_1 = _e.sent();
1505
+ err_1 = _f.sent();
1526
1506
  this.cleanup();
1527
1507
  throw err_1;
1528
1508
  case 6: return [2 /*return*/];
@@ -1532,8 +1512,6 @@
1532
1512
  };
1533
1513
  DailyVoiceClientService.prototype.setupEventHandlers = function (call) {
1534
1514
  var _this = this;
1535
- // active-speaker-change: used ONLY for user speaking detection.
1536
- // Bot speaking is detected by our own AnalyserNode (instant, no debounce).
1537
1515
  call.on('active-speaker-change', function (event) {
1538
1516
  _this.ngZone.run(function () {
1539
1517
  var _a;
@@ -1542,23 +1520,20 @@
1542
1520
  _this.userSpeakingSubject.next(false);
1543
1521
  return;
1544
1522
  }
1545
- var isLocal = peerId === _this.localSessionId;
1546
- _this.userSpeakingSubject.next(isLocal);
1523
+ _this.userSpeakingSubject.next(peerId === _this.localSessionId);
1547
1524
  });
1548
1525
  });
1549
- // track-started / track-stopped: set up remote audio playback + AnalyserNode monitor.
1550
1526
  call.on('track-started', function (event) {
1551
1527
  _this.ngZone.run(function () {
1552
- var _a, _b, _c, _d;
1528
+ var _a, _b, _c, _d, _e;
1553
1529
  var p = event === null || event === void 0 ? void 0 : event.participant;
1554
1530
  var type = (_a = event === null || event === void 0 ? void 0 : event.type) !== null && _a !== void 0 ? _a : (_b = event === null || event === void 0 ? void 0 : event.track) === null || _b === void 0 ? void 0 : _b.kind;
1555
- var track = event === null || event === void 0 ? void 0 : event.track;
1556
1531
  if (p && !p.local && type === 'audio') {
1557
- console.log("[VoiceDebug] Got audio track from backend (track-started) \u2014 readyState=" + (track === null || track === void 0 ? void 0 : track.readyState) + ", muted=" + (track === null || track === void 0 ? void 0 : track.muted) + " \u2014 " + new Date().toISOString());
1558
- var audioTrack = track !== null && track !== void 0 ? track : (_d = (_c = p.tracks) === null || _c === void 0 ? void 0 : _c.audio) === null || _d === void 0 ? void 0 : _d.track;
1559
- if (audioTrack && typeof audioTrack === 'object') {
1560
- _this.playRemoteTrack(audioTrack);
1561
- _this.monitorRemoteAudio(audioTrack);
1532
+ var track = (_c = event.track) !== null && _c !== void 0 ? _c : (_e = (_d = p === null || p === void 0 ? void 0 : p.tracks) === null || _d === void 0 ? void 0 : _d.audio) === null || _e === void 0 ? void 0 : _e.track;
1533
+ if (track) {
1534
+ console.log('[VoiceDebug] Remote audio track received');
1535
+ _this.playRemoteTrack(track);
1536
+ _this.monitorRemoteAudio(track);
1562
1537
  }
1563
1538
  }
1564
1539
  });
@@ -1577,57 +1552,27 @@
1577
1552
  call.on('left-meeting', function () {
1578
1553
  _this.ngZone.run(function () { return _this.cleanup(); });
1579
1554
  });
1580
- call.on('error', function (event) {
1581
- _this.ngZone.run(function () {
1582
- var _a;
1583
- console.error('DailyVoiceClient: Daily error', (_a = event === null || event === void 0 ? void 0 : event.errorMsg) !== null && _a !== void 0 ? _a : event);
1584
- _this.cleanup();
1585
- });
1555
+ call.on('error', function (e) {
1556
+ console.error('Daily error:', e);
1557
+ _this.cleanup();
1586
1558
  });
1587
1559
  };
1588
- /**
1589
- * Play remote (bot) audio track via a dedicated audio element.
1590
- * Required in many browsers where Daily's internal playback does not output to speakers.
1591
- */
1592
1560
  DailyVoiceClientService.prototype.playRemoteTrack = function (track) {
1593
1561
  this.stopRemoteAudio();
1594
1562
  try {
1595
- console.log("[VoiceDebug] playRemoteTrack called \u2014 track.readyState=" + track.readyState + ", track.muted=" + track.muted + " \u2014 " + new Date().toISOString());
1596
- track.onunmute = function () {
1597
- console.log("[VoiceDebug] Remote audio track UNMUTED (audio data arriving) \u2014 " + new Date().toISOString());
1598
- };
1599
1563
  var stream = new MediaStream([track]);
1600
1564
  var audio = new Audio();
1601
1565
  audio.autoplay = true;
1602
1566
  audio.srcObject = stream;
1603
1567
  this.remoteAudioElement = audio;
1604
- audio.onplaying = function () {
1605
- console.log("[VoiceDebug] Audio element PLAYING (browser started playback) \u2014 " + new Date().toISOString());
1606
- };
1607
- var firstTimeUpdate_1 = true;
1608
- audio.ontimeupdate = function () {
1609
- if (firstTimeUpdate_1) {
1610
- firstTimeUpdate_1 = false;
1611
- console.log("[VoiceDebug] Audio element first TIMEUPDATE (actual audio output) \u2014 " + new Date().toISOString());
1612
- }
1613
- };
1614
- var p = audio.play();
1615
- if (p && typeof p.then === 'function') {
1616
- p.then(function () {
1617
- console.log("[VoiceDebug] audio.play() resolved \u2014 " + new Date().toISOString());
1618
- }).catch(function (err) {
1619
- console.warn('DailyVoiceClient: remote audio play failed (may need user gesture)', err);
1620
- });
1621
- }
1568
+ audio.play().catch(function () {
1569
+ console.warn('Autoplay blocked');
1570
+ });
1622
1571
  }
1623
1572
  catch (err) {
1624
- console.warn('DailyVoiceClient: failed to create remote audio element', err);
1573
+ console.warn('Audio playback error', err);
1625
1574
  }
1626
1575
  };
1627
- /**
1628
- * Monitor remote audio track energy via AnalyserNode.
1629
- * Polls at ~60fps and flips speakingSubject based on actual audio energy.
1630
- */
1631
1576
  DailyVoiceClientService.prototype.monitorRemoteAudio = function (track) {
1632
1577
  var _this = this;
1633
1578
  this.stopRemoteAudioMonitor();
@@ -1638,92 +1583,75 @@
1638
1583
  analyser_1.fftSize = 256;
1639
1584
  source.connect(analyser_1);
1640
1585
  this.remoteAudioContext = ctx;
1641
- var dataArray_1 = new Uint8Array(analyser_1.frequencyBinCount);
1642
- var THRESHOLD_1 = 5;
1643
- var SILENCE_MS_1 = 1500;
1644
- var lastSoundTime_1 = 0;
1645
- var isSpeaking_1 = false;
1646
- var poll_1 = function () {
1586
+ var data_1 = new Uint8Array(analyser_1.frequencyBinCount);
1587
+ var speaking_1 = false;
1588
+ var lastSound_1 = 0;
1589
+ var loop_1 = function () {
1647
1590
  if (!_this.remoteAudioContext)
1648
1591
  return;
1649
- analyser_1.getByteFrequencyData(dataArray_1);
1650
- var sum = 0;
1651
- for (var i = 0; i < dataArray_1.length; i++) {
1652
- sum += dataArray_1[i];
1653
- }
1654
- var avg = sum / dataArray_1.length;
1592
+ analyser_1.getByteFrequencyData(data_1);
1593
+ var avg = data_1.reduce(function (a, b) { return a + b; }, 0) / data_1.length;
1655
1594
  var now = Date.now();
1656
- if (avg > THRESHOLD_1) {
1657
- lastSoundTime_1 = now;
1658
- if (!isSpeaking_1) {
1659
- isSpeaking_1 = true;
1660
- console.log("[VoiceDebug] Bot audio energy detected (speaking=true) \u2014 avg=" + avg.toFixed(1) + " \u2014 " + new Date().toISOString());
1595
+ if (avg > 5) {
1596
+ lastSound_1 = now;
1597
+ if (!speaking_1) {
1598
+ speaking_1 = true;
1661
1599
  _this.ngZone.run(function () {
1662
1600
  _this.userSpeakingSubject.next(false);
1663
1601
  _this.speakingSubject.next(true);
1664
1602
  });
1665
1603
  }
1666
1604
  }
1667
- else if (isSpeaking_1 && now - lastSoundTime_1 > SILENCE_MS_1) {
1668
- isSpeaking_1 = false;
1669
- console.log("[VoiceDebug] Bot audio silence detected (speaking=false) \u2014 " + new Date().toISOString());
1605
+ else if (speaking_1 && now - lastSound_1 > 1500) {
1606
+ speaking_1 = false;
1670
1607
  _this.ngZone.run(function () { return _this.speakingSubject.next(false); });
1671
1608
  }
1672
- _this.remoteSpeakingRAF = requestAnimationFrame(poll_1);
1609
+ _this.remoteSpeakingRAF = requestAnimationFrame(loop_1);
1673
1610
  };
1674
- this.remoteSpeakingRAF = requestAnimationFrame(poll_1);
1675
- }
1676
- catch (err) {
1677
- console.warn('DailyVoiceClient: failed to create remote audio monitor', err);
1611
+ this.remoteSpeakingRAF = requestAnimationFrame(loop_1);
1678
1612
  }
1613
+ catch (_a) { }
1679
1614
  };
1680
1615
  DailyVoiceClientService.prototype.stopRemoteAudioMonitor = function () {
1616
+ var _a;
1681
1617
  if (this.remoteSpeakingRAF) {
1682
1618
  cancelAnimationFrame(this.remoteSpeakingRAF);
1683
1619
  this.remoteSpeakingRAF = null;
1684
1620
  }
1685
- if (this.remoteAudioContext) {
1686
- this.remoteAudioContext.close().catch(function () { });
1687
- this.remoteAudioContext = null;
1688
- }
1621
+ (_a = this.remoteAudioContext) === null || _a === void 0 ? void 0 : _a.close().catch(function () { });
1622
+ this.remoteAudioContext = null;
1689
1623
  };
1690
1624
  DailyVoiceClientService.prototype.stopRemoteAudio = function () {
1691
1625
  if (this.remoteAudioElement) {
1692
- try {
1693
- this.remoteAudioElement.pause();
1694
- this.remoteAudioElement.srcObject = null;
1695
- }
1696
- catch (_) { }
1626
+ this.remoteAudioElement.pause();
1627
+ this.remoteAudioElement.srcObject = null;
1697
1628
  this.remoteAudioElement = null;
1698
1629
  }
1699
1630
  };
1700
- /** Set mic muted state. */
1701
1631
  DailyVoiceClientService.prototype.setMuted = function (muted) {
1702
1632
  if (!this.callObject)
1703
1633
  return;
1704
1634
  this.callObject.setLocalAudio(!muted);
1705
1635
  this.micMutedSubject.next(muted);
1636
+ console.log("[VoiceDebug] Mic " + (muted ? 'MUTED' : 'UNMUTED'));
1706
1637
  };
1707
- /** Disconnect and cleanup. */
1708
1638
  DailyVoiceClientService.prototype.disconnect = function () {
1709
1639
  return __awaiter(this, void 0, void 0, function () {
1710
- var e_1;
1711
- return __generator(this, function (_e) {
1712
- switch (_e.label) {
1640
+ var _a_1;
1641
+ return __generator(this, function (_f) {
1642
+ switch (_f.label) {
1713
1643
  case 0:
1714
- if (!this.callObject) {
1715
- this.cleanup();
1716
- return [2 /*return*/];
1717
- }
1718
- _e.label = 1;
1644
+ if (!this.callObject)
1645
+ return [2 /*return*/, this.cleanup()];
1646
+ _f.label = 1;
1719
1647
  case 1:
1720
- _e.trys.push([1, 3, , 4]);
1648
+ _f.trys.push([1, 3, , 4]);
1721
1649
  return [4 /*yield*/, this.callObject.leave()];
1722
1650
  case 2:
1723
- _e.sent();
1651
+ _f.sent();
1724
1652
  return [3 /*break*/, 4];
1725
1653
  case 3:
1726
- e_1 = _e.sent();
1654
+ _a_1 = _f.sent();
1727
1655
  return [3 /*break*/, 4];
1728
1656
  case 4:
1729
1657
  this.cleanup();
@@ -1733,21 +1661,17 @@
1733
1661
  });
1734
1662
  };
1735
1663
  DailyVoiceClientService.prototype.cleanup = function () {
1664
+ var _a, _b;
1736
1665
  this.stopRemoteAudioMonitor();
1737
1666
  this.stopRemoteAudio();
1738
- if (this.callObject) {
1739
- this.callObject.destroy().catch(function () { });
1740
- this.callObject = null;
1741
- }
1742
- if (this.localStream) {
1743
- this.localStream.getTracks().forEach(function (t) { return t.stop(); });
1744
- this.localStream = null;
1745
- }
1667
+ (_a = this.callObject) === null || _a === void 0 ? void 0 : _a.destroy().catch(function () { });
1668
+ this.callObject = null;
1669
+ (_b = this.localStream) === null || _b === void 0 ? void 0 : _b.getTracks().forEach(function (t) { return t.stop(); });
1670
+ this.localStream = null;
1746
1671
  this.localSessionId = null;
1747
1672
  this.speakingSubject.next(false);
1748
1673
  this.userSpeakingSubject.next(false);
1749
1674
  this.localStreamSubject.next(null);
1750
- // Keep last micMuted state; will reset on next connect
1751
1675
  };
1752
1676
  return DailyVoiceClientService;
1753
1677
  }());
@@ -1761,21 +1685,8 @@
1761
1685
  { type: i0.NgZone }
1762
1686
  ]; };
1763
1687
 
1764
- /**
1765
- * Voice agent orchestrator. Coordinates WebSocket (signaling) and Daily.js (WebRTC audio).
1766
- *
1767
- * CRITICAL: This service must NEVER use Socket.IO or ngx-socket-io. Voice flow uses only:
1768
- * - Native WebSocket (WebSocketVoiceClientService) for signaling (room_created, transcripts)
1769
- * - Daily.js (DailyVoiceClientService) for WebRTC audio. Audio does NOT flow over WebSocket.
1770
- *
1771
- * - Maintains callState, statusText, duration, isMicMuted, isUserSpeaking, audioLevels
1772
- * - Uses WebSocket for room_created and transcripts only (no audio)
1773
- * - Uses Daily.js for all audio, mic, and real-time speaking detection
1774
- */
1775
1688
  var VoiceAgentService = /** @class */ (function () {
1776
- function VoiceAgentService(audioAnalyzer, wsClient, dailyClient, platformTokenRefresh,
1777
- /** `Object` not `object` — ngc metadata collection rejects the `object` type in DI params. */
1778
- platformId) {
1689
+ function VoiceAgentService(audioAnalyzer, wsClient, dailyClient, platformTokenRefresh, platformId) {
1779
1690
  var _this = this;
1780
1691
  this.audioAnalyzer = audioAnalyzer;
1781
1692
  this.wsClient = wsClient;
@@ -1785,7 +1696,7 @@
1785
1696
  this.callStateSubject = new rxjs.BehaviorSubject('idle');
1786
1697
  this.statusTextSubject = new rxjs.BehaviorSubject('');
1787
1698
  this.durationSubject = new rxjs.BehaviorSubject('00:00');
1788
- this.isMicMutedSubject = new rxjs.BehaviorSubject(false);
1699
+ this.isMicMutedSubject = new rxjs.BehaviorSubject(true);
1789
1700
  this.isUserSpeakingSubject = new rxjs.BehaviorSubject(false);
1790
1701
  this.audioLevelsSubject = new rxjs.BehaviorSubject([]);
1791
1702
  this.userTranscriptSubject = new rxjs.Subject();
@@ -1802,7 +1713,6 @@
1802
1713
  this.audioLevels$ = this.audioLevelsSubject.asObservable();
1803
1714
  this.userTranscript$ = this.userTranscriptSubject.asObservable();
1804
1715
  this.botTranscript$ = this.botTranscriptSubject.asObservable();
1805
- // Waveform visualization only - do NOT use for speaking state
1806
1716
  this.subscriptions.add(this.audioAnalyzer.audioLevels$.subscribe(function (levels) { return _this.audioLevelsSubject.next(levels); }));
1807
1717
  }
1808
1718
  VoiceAgentService.prototype.ngOnDestroy = function () {
@@ -1810,70 +1720,67 @@
1810
1720
  this.subscriptions.unsubscribe();
1811
1721
  this.disconnect();
1812
1722
  };
1813
- /** Reset to idle state (e.g. when modal opens so user can click Start Call). */
1723
+ /**
1724
+ * Tear down transports and reset UI state so a new `connect()` can run.
1725
+ * `connect()` only proceeds from `idle`; use this after `ended` or when reopening the modal.
1726
+ */
1814
1727
  VoiceAgentService.prototype.resetToIdle = function () {
1815
- if (this.callStateSubject.value === 'idle')
1816
- return;
1817
1728
  this.stopDurationTimer();
1818
1729
  this.audioAnalyzer.stop();
1819
1730
  this.wsClient.disconnect();
1820
- // Fire-and-forget: Daily disconnect is async; connect() will await if needed
1821
1731
  void this.dailyClient.disconnect();
1822
1732
  this.callStateSubject.next('idle');
1823
1733
  this.statusTextSubject.next('');
1824
- this.durationSubject.next('0:00');
1734
+ this.durationSubject.next('00:00');
1735
+ this.isMicMutedSubject.next(true);
1736
+ this.isUserSpeakingSubject.next(false);
1737
+ this.audioLevelsSubject.next([]);
1825
1738
  };
1826
1739
  VoiceAgentService.prototype.connect = function (apiUrl, token, botId, conversationId, apiKey, eventToken, eventUrl, domainAuthority, usersApiUrl) {
1827
1740
  return __awaiter(this, void 0, void 0, function () {
1828
- var accessToken, ensured, e_1, baseUrl, postUrl, headers, res, json, wsUrl, error_1;
1741
+ var accessToken, ensured, _a_1, postUrl, res, json, wsUrl, e_1;
1829
1742
  var _this = this;
1830
- return __generator(this, function (_a) {
1831
- switch (_a.label) {
1743
+ return __generator(this, function (_b) {
1744
+ switch (_b.label) {
1832
1745
  case 0:
1833
- if (this.callStateSubject.value !== 'idle') {
1834
- console.warn('Call already in progress');
1746
+ if (this.callStateSubject.value !== 'idle')
1835
1747
  return [2 /*return*/];
1836
- }
1837
- _a.label = 1;
1748
+ _b.label = 1;
1838
1749
  case 1:
1839
- _a.trys.push([1, 8, , 10]);
1750
+ _b.trys.push([1, 8, , 9]);
1840
1751
  this.callStateSubject.next('connecting');
1841
- this.statusTextSubject.next('Connecting...');
1752
+ this.statusTextSubject.next('Connecting to agent...');
1842
1753
  accessToken = token;
1843
1754
  if (!(usersApiUrl && common.isPlatformBrowser(this.platformId))) return [3 /*break*/, 5];
1844
- _a.label = 2;
1755
+ _b.label = 2;
1845
1756
  case 2:
1846
- _a.trys.push([2, 4, , 5]);
1757
+ _b.trys.push([2, 4, , 5]);
1847
1758
  return [4 /*yield*/, this.platformTokenRefresh
1848
1759
  .ensureValidAccessToken(token, usersApiUrl)
1849
1760
  .pipe(operators.take(1))
1850
1761
  .toPromise()];
1851
1762
  case 3:
1852
- ensured = _a.sent();
1763
+ ensured = _b.sent();
1853
1764
  if (ensured === null || ensured === void 0 ? void 0 : ensured.accessToken) {
1854
1765
  accessToken = ensured.accessToken;
1855
1766
  }
1856
1767
  return [3 /*break*/, 5];
1857
1768
  case 4:
1858
- e_1 = _a.sent();
1859
- console.warn('[HiveGpt Voice] Token refresh before connect failed', e_1);
1769
+ _a_1 = _b.sent();
1860
1770
  return [3 /*break*/, 5];
1861
1771
  case 5:
1862
- baseUrl = apiUrl.replace(/\/$/, '');
1863
1772
  postUrl = "https://1356-103-210-33-236.ngrok-free.app/ai/ask-voice";
1864
- headers = {
1865
- 'Content-Type': 'application/json',
1866
- Authorization: "Bearer " + accessToken,
1867
- 'domain-authority': domainAuthority,
1868
- 'eventtoken': eventToken,
1869
- 'eventurl': eventUrl,
1870
- 'hive-bot-id': botId,
1871
- 'x-api-key': apiKey,
1872
- 'ngrok-skip-browser-warning': 'true',
1873
- };
1874
1773
  return [4 /*yield*/, fetch(postUrl, {
1875
1774
  method: 'POST',
1876
- headers: headers,
1775
+ headers: {
1776
+ 'Content-Type': 'application/json',
1777
+ Authorization: "Bearer " + accessToken,
1778
+ 'domain-authority': domainAuthority,
1779
+ eventtoken: eventToken,
1780
+ eventurl: eventUrl,
1781
+ 'hive-bot-id': botId,
1782
+ 'x-api-key': apiKey,
1783
+ },
1877
1784
  body: JSON.stringify({
1878
1785
  bot_id: botId,
1879
1786
  conversation_id: conversationId,
@@ -1881,94 +1788,73 @@
1881
1788
  }),
1882
1789
  })];
1883
1790
  case 6:
1884
- res = _a.sent();
1885
- if (!res.ok) {
1886
- throw new Error("HTTP " + res.status);
1887
- }
1791
+ res = _b.sent();
1888
1792
  return [4 /*yield*/, res.json()];
1889
1793
  case 7:
1890
- json = _a.sent();
1794
+ json = _b.sent();
1891
1795
  wsUrl = json === null || json === void 0 ? void 0 : json.rn_ws_url;
1892
- if (!wsUrl || typeof wsUrl !== 'string') {
1893
- throw new Error('No ws_url in response');
1894
- }
1895
- // Subscribe to room_created BEFORE connecting to avoid race
1896
1796
  this.wsClient.roomCreated$
1897
1797
  .pipe(operators.take(1), operators.takeUntil(this.destroy$))
1898
1798
  .subscribe(function (roomUrl) { return __awaiter(_this, void 0, void 0, function () {
1899
- var err_1;
1900
- return __generator(this, function (_a) {
1901
- switch (_a.label) {
1902
- case 0:
1903
- _a.trys.push([0, 2, , 4]);
1904
- return [4 /*yield*/, this.onRoomCreated(roomUrl)];
1799
+ return __generator(this, function (_b) {
1800
+ switch (_b.label) {
1801
+ case 0: return [4 /*yield*/, this.onRoomCreated(roomUrl)];
1905
1802
  case 1:
1906
- _a.sent();
1907
- return [3 /*break*/, 4];
1908
- case 2:
1909
- err_1 = _a.sent();
1910
- console.error('Daily join failed:', err_1);
1911
- this.callStateSubject.next('ended');
1912
- this.statusTextSubject.next('Connection failed');
1913
- return [4 /*yield*/, this.disconnect()];
1914
- case 3:
1915
- _a.sent();
1916
- throw err_1;
1917
- case 4: return [2 /*return*/];
1803
+ _b.sent();
1804
+ return [2 /*return*/];
1918
1805
  }
1919
1806
  });
1920
1807
  }); });
1921
- // Forward transcripts from WebSocket
1922
- this.subscriptions.add(this.wsClient.userTranscript$
1923
- .pipe(operators.takeUntil(this.destroy$))
1924
- .subscribe(function (t) { return _this.userTranscriptSubject.next(t); }));
1925
- this.subscriptions.add(this.wsClient.botTranscript$
1926
- .pipe(operators.takeUntil(this.destroy$))
1927
- .subscribe(function (t) { return _this.botTranscriptSubject.next(t); }));
1928
- // Connect signaling WebSocket (no audio over WS)
1808
+ this.subscriptions.add(this.wsClient.userTranscript$.subscribe(function (t) { return _this.userTranscriptSubject.next(t); }));
1809
+ this.subscriptions.add(this.wsClient.botTranscript$.subscribe(function (t) { return _this.botTranscriptSubject.next(t); }));
1929
1810
  this.wsClient.connect(wsUrl);
1930
- return [3 /*break*/, 10];
1811
+ return [3 /*break*/, 9];
1931
1812
  case 8:
1932
- error_1 = _a.sent();
1933
- console.error('Error connecting voice agent:', error_1);
1813
+ e_1 = _b.sent();
1934
1814
  this.callStateSubject.next('ended');
1935
- return [4 /*yield*/, this.disconnect()];
1936
- case 9:
1937
- _a.sent();
1938
- this.statusTextSubject.next('Connection failed');
1939
- throw error_1;
1940
- case 10: return [2 /*return*/];
1815
+ return [3 /*break*/, 9];
1816
+ case 9: return [2 /*return*/];
1941
1817
  }
1942
1818
  });
1943
1819
  });
1944
1820
  };
1945
1821
  VoiceAgentService.prototype.onRoomCreated = function (roomUrl) {
1946
1822
  return __awaiter(this, void 0, void 0, function () {
1823
+ var handled;
1947
1824
  var _this = this;
1948
- return __generator(this, function (_a) {
1949
- switch (_a.label) {
1950
- case 0:
1951
- // Connect Daily.js for WebRTC audio
1952
- return [4 /*yield*/, this.dailyClient.connect(roomUrl)];
1825
+ return __generator(this, function (_b) {
1826
+ switch (_b.label) {
1827
+ case 0: return [4 /*yield*/, this.dailyClient.connect(roomUrl)];
1953
1828
  case 1:
1954
- // Connect Daily.js for WebRTC audio
1955
- _a.sent();
1956
- // Waveform: use local mic stream from Daily client
1957
- this.dailyClient.localStream$
1958
- .pipe(operators.filter(function (s) { return s != null; }), operators.take(1))
1959
- .subscribe(function (stream) {
1960
- _this.audioAnalyzer.start(stream);
1829
+ _b.sent();
1830
+ // 🔴 Start MUTED
1831
+ this.dailyClient.setMuted(true);
1832
+ this.isMicMutedSubject.next(true);
1833
+ this.statusTextSubject.next('Listening to agent...');
1834
+ handled = false;
1835
+ this.dailyClient.speaking$.pipe(operators.filter(Boolean), operators.take(1)).subscribe(function () {
1836
+ if (handled)
1837
+ return;
1838
+ handled = true;
1839
+ console.log('[VoiceFlow] First bot response → enabling mic');
1840
+ _this.dailyClient.setMuted(false);
1841
+ _this.statusTextSubject.next('You can speak now');
1961
1842
  });
1962
- this.subscriptions.add(this.dailyClient.userSpeaking$.subscribe(function (s) { return _this.isUserSpeakingSubject.next(s); }));
1843
+ // ⛑️ Fallback (if bot fails)
1844
+ setTimeout(function () {
1845
+ if (!handled) {
1846
+ console.warn('[VoiceFlow] Fallback → enabling mic');
1847
+ _this.dailyClient.setMuted(false);
1848
+ _this.statusTextSubject.next('You can speak now');
1849
+ }
1850
+ }, 8000);
1851
+ // rest same
1963
1852
  this.subscriptions.add(rxjs.combineLatest([
1964
1853
  this.dailyClient.speaking$,
1965
1854
  this.dailyClient.userSpeaking$,
1966
- ]).subscribe(function (_a) {
1967
- var _b = __read(_a, 2), bot = _b[0], user = _b[1];
1855
+ ]).subscribe(function (_b) {
1856
+ var _c = __read(_b, 2), bot = _c[0], user = _c[1];
1968
1857
  var current = _this.callStateSubject.value;
1969
- if (current === 'connecting' && !bot) {
1970
- return;
1971
- }
1972
1858
  if (current === 'connecting' && bot) {
1973
1859
  _this.callStartTime = Date.now();
1974
1860
  _this.startDurationTimer();
@@ -1981,12 +1867,10 @@
1981
1867
  else if (bot) {
1982
1868
  _this.callStateSubject.next('talking');
1983
1869
  }
1984
- else if (current === 'talking' || current === 'listening') {
1870
+ else {
1985
1871
  _this.callStateSubject.next('connected');
1986
1872
  }
1987
1873
  }));
1988
- this.subscriptions.add(this.dailyClient.micMuted$.subscribe(function (muted) { return _this.isMicMutedSubject.next(muted); }));
1989
- this.statusTextSubject.next('Connecting...');
1990
1874
  return [2 /*return*/];
1991
1875
  }
1992
1876
  });
@@ -1994,16 +1878,14 @@
1994
1878
  };
1995
1879
  VoiceAgentService.prototype.disconnect = function () {
1996
1880
  return __awaiter(this, void 0, void 0, function () {
1997
- return __generator(this, function (_a) {
1998
- switch (_a.label) {
1881
+ return __generator(this, function (_b) {
1882
+ switch (_b.label) {
1999
1883
  case 0:
2000
1884
  this.stopDurationTimer();
2001
1885
  this.audioAnalyzer.stop();
2002
- // Daily first, then WebSocket
2003
1886
  return [4 /*yield*/, this.dailyClient.disconnect()];
2004
1887
  case 1:
2005
- // Daily first, then WebSocket
2006
- _a.sent();
1888
+ _b.sent();
2007
1889
  this.wsClient.disconnect();
2008
1890
  this.callStateSubject.next('ended');
2009
1891
  this.statusTextSubject.next('Call Ended');
@@ -2018,22 +1900,16 @@
2018
1900
  };
2019
1901
  VoiceAgentService.prototype.startDurationTimer = function () {
2020
1902
  var _this = this;
2021
- var updateDuration = function () {
2022
- if (_this.callStartTime > 0) {
2023
- var elapsed = Math.floor((Date.now() - _this.callStartTime) / 1000);
2024
- var minutes = Math.floor(elapsed / 60);
2025
- var seconds = elapsed % 60;
2026
- _this.durationSubject.next(minutes + ":" + String(seconds).padStart(2, '0'));
2027
- }
2028
- };
2029
- updateDuration();
2030
- this.durationInterval = setInterval(updateDuration, 1000);
1903
+ this.durationInterval = setInterval(function () {
1904
+ var elapsed = Math.floor((Date.now() - _this.callStartTime) / 1000);
1905
+ var m = Math.floor(elapsed / 60);
1906
+ var s = elapsed % 60;
1907
+ _this.durationSubject.next(m + ":" + String(s).padStart(2, '0'));
1908
+ }, 1000);
2031
1909
  };
2032
1910
  VoiceAgentService.prototype.stopDurationTimer = function () {
2033
- if (this.durationInterval) {
1911
+ if (this.durationInterval)
2034
1912
  clearInterval(this.durationInterval);
2035
- this.durationInterval = null;
2036
- }
2037
1913
  };
2038
1914
  return VoiceAgentService;
2039
1915
  }());