@hivegpt/hiveai-angular 0.0.586 → 0.0.587

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.
@@ -1477,6 +1477,29 @@
1477
1477
  /** Emits true once when first remote audio frame starts playing. */
1478
1478
  this.firstRemoteAudioFrame$ = this.firstRemoteAudioFrameSubject.asObservable();
1479
1479
  }
1480
+ /**
1481
+ * Prompt for microphone access up front so callers can handle permission
1482
+ * denial before creating backend room/session resources.
1483
+ */
1484
+ DailyVoiceClientService.prototype.ensureMicrophoneAccess = function () {
1485
+ var _a;
1486
+ return __awaiter(this, void 0, void 0, function () {
1487
+ var stream;
1488
+ return __generator(this, function (_e) {
1489
+ switch (_e.label) {
1490
+ case 0:
1491
+ if (!((_a = navigator === null || navigator === void 0 ? void 0 : navigator.mediaDevices) === null || _a === void 0 ? void 0 : _a.getUserMedia)) {
1492
+ throw new Error('Microphone API unavailable');
1493
+ }
1494
+ return [4 /*yield*/, navigator.mediaDevices.getUserMedia({ audio: true })];
1495
+ case 1:
1496
+ stream = _e.sent();
1497
+ stream.getTracks().forEach(function (t) { return t.stop(); });
1498
+ return [2 /*return*/];
1499
+ }
1500
+ });
1501
+ });
1502
+ };
1480
1503
  /**
1481
1504
  * Connect to Daily room. Acquires mic first for waveform, then joins with audio.
1482
1505
  * @param roomUrl Daily room URL (from room_created)
@@ -1848,29 +1871,34 @@
1848
1871
  }
1849
1872
  _a.label = 1;
1850
1873
  case 1:
1851
- _a.trys.push([1, 8, , 10]);
1874
+ _a.trys.push([1, 9, , 13]);
1852
1875
  this.callStateSubject.next('connecting');
1853
1876
  this.statusTextSubject.next('Connecting...');
1854
- accessToken = token;
1855
- if (!(usersApiUrl && common.isPlatformBrowser(this.platformId))) return [3 /*break*/, 5];
1856
- _a.label = 2;
1877
+ // Request mic permission before provisioning backend room flow.
1878
+ return [4 /*yield*/, this.dailyClient.ensureMicrophoneAccess()];
1857
1879
  case 2:
1858
- _a.trys.push([2, 4, , 5]);
1880
+ // Request mic permission before provisioning backend room flow.
1881
+ _a.sent();
1882
+ accessToken = token;
1883
+ if (!(usersApiUrl && common.isPlatformBrowser(this.platformId))) return [3 /*break*/, 6];
1884
+ _a.label = 3;
1885
+ case 3:
1886
+ _a.trys.push([3, 5, , 6]);
1859
1887
  return [4 /*yield*/, this.platformTokenRefresh
1860
1888
  .ensureValidAccessToken(token, usersApiUrl)
1861
1889
  .pipe(operators.take(1))
1862
1890
  .toPromise()];
1863
- case 3:
1891
+ case 4:
1864
1892
  ensured = _a.sent();
1865
1893
  if (ensured === null || ensured === void 0 ? void 0 : ensured.accessToken) {
1866
1894
  accessToken = ensured.accessToken;
1867
1895
  }
1868
- return [3 /*break*/, 5];
1869
- case 4:
1896
+ return [3 /*break*/, 6];
1897
+ case 5:
1870
1898
  e_1 = _a.sent();
1871
1899
  console.warn('[HiveGpt Voice] Token refresh before connect failed', e_1);
1872
- return [3 /*break*/, 5];
1873
- case 5:
1900
+ return [3 /*break*/, 6];
1901
+ case 6:
1874
1902
  baseUrl = apiUrl.replace(/\/$/, '');
1875
1903
  postUrl = baseUrl + "/ai/ask-voice";
1876
1904
  headers = {
@@ -1893,13 +1921,13 @@
1893
1921
  voice: 'alloy',
1894
1922
  }),
1895
1923
  })];
1896
- case 6:
1924
+ case 7:
1897
1925
  res = _a.sent();
1898
1926
  if (!res.ok) {
1899
1927
  throw new Error("HTTP " + res.status);
1900
1928
  }
1901
1929
  return [4 /*yield*/, res.json()];
1902
- case 7:
1930
+ case 8:
1903
1931
  json = _a.sent();
1904
1932
  wsUrl = json === null || json === void 0 ? void 0 : json.rn_ws_url;
1905
1933
  if (!wsUrl || typeof wsUrl !== 'string') {
@@ -1913,21 +1941,30 @@
1913
1941
  return __generator(this, function (_a) {
1914
1942
  switch (_a.label) {
1915
1943
  case 0:
1916
- _a.trys.push([0, 2, , 4]);
1944
+ _a.trys.push([0, 2, , 6]);
1917
1945
  return [4 /*yield*/, this.onRoomCreated(roomUrl)];
1918
1946
  case 1:
1919
1947
  _a.sent();
1920
- return [3 /*break*/, 4];
1948
+ return [3 /*break*/, 6];
1921
1949
  case 2:
1922
1950
  err_1 = _a.sent();
1923
1951
  console.error('Daily join failed:', err_1);
1952
+ if (!this.isMicPermissionError(err_1)) return [3 /*break*/, 4];
1953
+ return [4 /*yield*/, this.cleanupMediaAndSignal()];
1954
+ case 3:
1955
+ _a.sent();
1956
+ this.callStateSubject.next('idle');
1957
+ this.durationSubject.next('0:00');
1958
+ this.statusTextSubject.next('Microphone permission is required');
1959
+ return [2 /*return*/];
1960
+ case 4:
1924
1961
  this.callStateSubject.next('ended');
1925
1962
  this.statusTextSubject.next('Connection failed');
1926
1963
  return [4 /*yield*/, this.disconnect()];
1927
- case 3:
1964
+ case 5:
1928
1965
  _a.sent();
1929
- throw err_1;
1930
- case 4: return [2 /*return*/];
1966
+ return [3 /*break*/, 6];
1967
+ case 6: return [2 /*return*/];
1931
1968
  }
1932
1969
  });
1933
1970
  }); });
@@ -1940,17 +1977,26 @@
1940
1977
  .subscribe(function (t) { return _this.botTranscriptSubject.next(t); }));
1941
1978
  // Connect signaling WebSocket (no audio over WS)
1942
1979
  this.wsClient.connect(wsUrl);
1943
- return [3 /*break*/, 10];
1944
- case 8:
1980
+ return [3 /*break*/, 13];
1981
+ case 9:
1945
1982
  error_1 = _a.sent();
1946
1983
  console.error('Error connecting voice agent:', error_1);
1984
+ if (!this.isMicPermissionError(error_1)) return [3 /*break*/, 11];
1985
+ return [4 /*yield*/, this.cleanupMediaAndSignal()];
1986
+ case 10:
1987
+ _a.sent();
1988
+ this.callStateSubject.next('idle');
1989
+ this.durationSubject.next('0:00');
1990
+ this.statusTextSubject.next('Microphone permission is required');
1991
+ return [2 /*return*/];
1992
+ case 11:
1947
1993
  this.callStateSubject.next('ended');
1948
1994
  return [4 /*yield*/, this.disconnect()];
1949
- case 9:
1995
+ case 12:
1950
1996
  _a.sent();
1951
1997
  this.statusTextSubject.next('Connection failed');
1952
1998
  throw error_1;
1953
- case 10: return [2 /*return*/];
1999
+ case 13: return [2 /*return*/];
1954
2000
  }
1955
2001
  });
1956
2002
  });
@@ -2062,6 +2108,31 @@
2062
2108
  this.durationInterval = null;
2063
2109
  }
2064
2110
  };
2111
+ VoiceAgentService.prototype.isMicPermissionError = function (error) {
2112
+ if (!error || typeof error !== 'object')
2113
+ return false;
2114
+ var maybe = error;
2115
+ return (maybe.name === 'NotAllowedError' ||
2116
+ maybe.name === 'PermissionDeniedError' ||
2117
+ maybe.name === 'SecurityError');
2118
+ };
2119
+ VoiceAgentService.prototype.cleanupMediaAndSignal = function () {
2120
+ return __awaiter(this, void 0, void 0, function () {
2121
+ return __generator(this, function (_a) {
2122
+ switch (_a.label) {
2123
+ case 0:
2124
+ this.stopDurationTimer();
2125
+ this.audioAnalyzer.stop();
2126
+ return [4 /*yield*/, this.dailyClient.disconnect()];
2127
+ case 1:
2128
+ _a.sent();
2129
+ this.wsClient.disconnect();
2130
+ this.hasAutoUnmutedAfterFirstAudio = false;
2131
+ return [2 /*return*/];
2132
+ }
2133
+ });
2134
+ });
2135
+ };
2065
2136
  return VoiceAgentService;
2066
2137
  }());
2067
2138
  VoiceAgentService.ɵprov = i0__namespace.ɵɵdefineInjectable({ factory: function VoiceAgentService_Factory() { return new VoiceAgentService(i0__namespace.ɵɵinject(AudioAnalyzerService), i0__namespace.ɵɵinject(WebSocketVoiceClientService), i0__namespace.ɵɵinject(DailyVoiceClientService), i0__namespace.ɵɵinject(PlatformTokenRefreshService), i0__namespace.ɵɵinject(i0__namespace.PLATFORM_ID)); }, token: VoiceAgentService, providedIn: "root" });