@hivegpt/hiveai-angular 0.0.608 → 0.0.609

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.
@@ -153,6 +153,11 @@ class AudioAnalyzerService {
153
153
  this.audioLevelsSubject.next([]);
154
154
  this.isUserSpeakingSubject.next(false);
155
155
  }
156
+ resumeContextIfSuspended() {
157
+ if (!this.audioContext || this.audioContext.state !== 'suspended')
158
+ return;
159
+ this.audioContext.resume().catch((err) => console.warn('[HiveGpt Voice] AudioContext resume failed', err));
160
+ }
156
161
  analyze() {
157
162
  if (!this.isRunning || !this.analyserNode || !this.dataArray) {
158
163
  return;
@@ -418,6 +423,8 @@ class VoiceAgentService {
418
423
  this.lifecycleToken = 0;
419
424
  this.subscriptions = new Subscription();
420
425
  this.pcEventCleanup = [];
426
+ this.pageLifecycleCleanup = [];
427
+ this.wasInActiveCallBeforeHide = false;
421
428
  this.callState$ = this.callStateSubject.asObservable();
422
429
  this.statusText$ = this.statusTextSubject.asObservable();
423
430
  this.duration$ = this.durationSubject.asObservable();
@@ -427,6 +434,13 @@ class VoiceAgentService {
427
434
  this.userTranscript$ = this.userTranscriptSubject.asObservable();
428
435
  this.botTranscript$ = this.botTranscriptSubject.asObservable();
429
436
  this.subscriptions.add(this.audioAnalyzer.audioLevels$.pipe(throttleTime(50)).subscribe((levels) => this.ngZone.run(() => this.audioLevelsSubject.next(levels))));
437
+ this.registerPageLifecycleListeners();
438
+ }
439
+ ngOnDestroy() {
440
+ this.pageLifecycleCleanup.forEach((fn) => fn());
441
+ this.pageLifecycleCleanup = [];
442
+ this.subscriptions.unsubscribe();
443
+ void this.cleanupPipecatClient();
430
444
  }
431
445
  /** Reset to idle (e.g. when modal re-opens so user can click Start Call). */
432
446
  resetToIdle() {
@@ -447,6 +461,7 @@ class VoiceAgentService {
447
461
  this.durationSubject.next('00:00');
448
462
  this.statusTextSubject.next('');
449
463
  this.callStateSubject.next('idle');
464
+ this.wasInActiveCallBeforeHide = false;
450
465
  await this.cleanupPipecatClient();
451
466
  }
452
467
  async connect(apiUrl, token, botId, conversationId, apiKey, eventToken, eventId, eventUrl, domainAuthority, usersApiUrl) {
@@ -678,6 +693,7 @@ class VoiceAgentService {
678
693
  this.callStartTime = 0;
679
694
  this.audioAnalyzer.stop();
680
695
  this.stopBotAudio();
696
+ this.wasInActiveCallBeforeHide = false;
681
697
  await this.cleanupPipecatClient();
682
698
  this.callStateSubject.next('ended');
683
699
  this.statusTextSubject.next('Call Ended');
@@ -729,6 +745,53 @@ class VoiceAgentService {
729
745
  this.durationInterval = null;
730
746
  }
731
747
  }
748
+ registerPageLifecycleListeners() {
749
+ if (!isPlatformBrowser(this.platformId) || typeof window === 'undefined' || typeof document === 'undefined') {
750
+ return;
751
+ }
752
+ const onVisibilityChange = () => {
753
+ if (document.hidden) {
754
+ this.wasInActiveCallBeforeHide = this.isCallActiveState(this.callStateSubject.value);
755
+ return;
756
+ }
757
+ if (this.wasInActiveCallBeforeHide) {
758
+ this.wasInActiveCallBeforeHide = false;
759
+ this.recoverAfterPageRestore();
760
+ }
761
+ };
762
+ const onPageShow = (event) => {
763
+ if (event.persisted && this.isCallActiveState(this.callStateSubject.value)) {
764
+ this.recoverAfterPageRestore();
765
+ }
766
+ };
767
+ document.addEventListener('visibilitychange', onVisibilityChange);
768
+ window.addEventListener('pageshow', onPageShow);
769
+ this.pageLifecycleCleanup.push(() => document.removeEventListener('visibilitychange', onVisibilityChange), () => window.removeEventListener('pageshow', onPageShow));
770
+ }
771
+ recoverAfterPageRestore() {
772
+ this.ngZone.run(() => {
773
+ if (!this.pcClient || !this.isCallActiveState(this.callStateSubject.value))
774
+ return;
775
+ // Older cached TS program state may not include this helper yet; call defensively.
776
+ this.audioAnalyzer.resumeContextIfSuspended?.();
777
+ this.startLocalMicAnalyzer();
778
+ this.resumeBotAudioPlayback();
779
+ });
780
+ }
781
+ resumeBotAudioPlayback() {
782
+ const botTrack = this.pcClient?.tracks()
783
+ ?.bot?.audio;
784
+ if (botTrack) {
785
+ this.setupBotAudioTrack(botTrack);
786
+ return;
787
+ }
788
+ if (this.botAudioElement) {
789
+ this.botAudioElement.play().catch((err) => console.warn('[HiveGpt Voice] Bot audio resume blocked', err));
790
+ }
791
+ }
792
+ isCallActiveState(state) {
793
+ return state === 'connecting' || state === 'connected' || state === 'listening' || state === 'talking';
794
+ }
732
795
  }
733
796
  VoiceAgentService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: VoiceAgentService, deps: [{ token: AudioAnalyzerService }, { token: PlatformTokenRefreshService }, { token: i0.NgZone }, { token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Injectable });
734
797
  VoiceAgentService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: VoiceAgentService, providedIn: 'root' });