refactor: stricter domain: voice-connection

This commit is contained in:
2026-04-11 15:08:04 +02:00
parent cea3dccef1
commit 7a0664b3c4
13 changed files with 36 additions and 33 deletions

View File

@@ -23,7 +23,7 @@ import { ScreenShareFacade } from '../../application/facades/screen-share.facade
import { selectOnlineUsers } from '../../../../store/users/users.selectors'; import { selectOnlineUsers } from '../../../../store/users/users.selectors';
import { User } from '../../../../shared-kernel'; import { User } from '../../../../shared-kernel';
import { DEFAULT_VOLUME } from '../../../../core/constants'; import { DEFAULT_VOLUME } from '../../../../core/constants';
import { VoicePlaybackService } from '../../../../domains/voice-connection/application/voice-playback.service'; import { VoicePlaybackService } from '../../../../domains/voice-connection';
@Component({ @Component({
selector: 'app-screen-share-viewer', selector: 'app-screen-share-viewer',

View File

@@ -7,12 +7,15 @@ Bridges the application layer to the low-level realtime infrastructure for voice
``` ```
voice-connection/ voice-connection/
├── application/ ├── application/
│ ├── voice-connection.facade.ts Proxy to RealtimeSessionFacade for voice and camera signals/methods │ ├── facades/
── voice-activity.service.ts RMS-based speaking detection via AnalyserNode (per-user signals) │ └── voice-connection.facade.ts Proxy to RealtimeSessionFacade for voice and camera signals/methods
│ └── voice-playback.service.ts Per-peer GainNode chain, 0-200% volume, deafen support │ └── services/
│ ├── voice-activity.service.ts RMS-based speaking detection via AnalyserNode (per-user signals)
│ └── voice-playback.service.ts Per-peer GainNode chain, 0-200% volume, deafen support
├── domain/ ├── domain/
│ └── voice-connection.models.ts Re-exports LatencyProfile, VoiceStateSnapshot from shared-kernel / realtime │ └── models/
│ └── voice-connection.model.ts Re-exports LatencyProfile, VoiceStateSnapshot from shared-kernel / realtime
└── index.ts Barrel exports └── index.ts Barrel exports
``` ```
@@ -31,11 +34,11 @@ graph TD
VAS --> VCF VAS --> VCF
VPS --> VCF VPS --> VCF
click VCF "application/voice-connection.facade.ts" "Proxy to RealtimeSessionFacade" _blank click VCF "application/facades/voice-connection.facade.ts" "Proxy to RealtimeSessionFacade" _blank
click VAS "application/voice-activity.service.ts" "RMS-based speaking detection" _blank click VAS "application/services/voice-activity.service.ts" "RMS-based speaking detection" _blank
click VPS "application/voice-playback.service.ts" "Per-peer GainNode volume chain" _blank click VPS "application/services/voice-playback.service.ts" "Per-peer GainNode volume chain" _blank
click RSF "../../infrastructure/realtime/realtime-session.service.ts" "Low-level WebRTC composition root" _blank click RSF "../../infrastructure/realtime/realtime-session.service.ts" "Low-level WebRTC composition root" _blank
click Models "domain/voice-connection.models.ts" "Re-exported types" _blank click Models "domain/models/voice-connection.model.ts" "Re-exported types" _blank
``` ```
## Voice connection facade ## Voice connection facade
@@ -67,8 +70,8 @@ graph LR
RMS -- yes --> Speaking[speakingSignal = true] RMS -- yes --> Speaking[speakingSignal = true]
RMS -- no, 8 frames --> Silent[speakingSignal = false] RMS -- no, 8 frames --> Silent[speakingSignal = false]
click Stream "application/voice-activity.service.ts" "VoiceActivityService.trackStream()" _blank click Stream "application/services/voice-activity.service.ts" "VoiceActivityService.trackStream()" _blank
click Poll "application/voice-activity.service.ts" "VoiceActivityService.poll()" _blank click Poll "application/services/voice-activity.service.ts" "VoiceActivityService.poll()" _blank
``` ```
| Parameter | Value | | Parameter | Value |

View File

@@ -1,7 +1,7 @@
import { Injectable, inject } from '@angular/core'; import { Injectable, inject } from '@angular/core';
import { ChatEvent } from '../../../shared-kernel'; import { ChatEvent } from '../../../../shared-kernel';
import { RealtimeSessionFacade } from '../../../core/realtime'; import { RealtimeSessionFacade } from '../../../../core/realtime';
import { LatencyProfile } from '../domain/voice-connection.models'; import { LatencyProfile } from '../../domain/models/voice-connection.model';
@Injectable({ providedIn: 'root' }) @Injectable({ providedIn: 'root' })
export class VoiceConnectionFacade { export class VoiceConnectionFacade {

View File

@@ -25,8 +25,8 @@ import {
Signal Signal
} from '@angular/core'; } from '@angular/core';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { VoiceConnectionFacade } from './voice-connection.facade'; import { VoiceConnectionFacade } from '../facades/voice-connection.facade';
import { DebuggingService } from '../../../core/services/debugging.service'; import { DebuggingService } from '../../../../core/services/debugging.service';
/* eslint-disable @typescript-eslint/member-ordering, @typescript-eslint/prefer-for-of, max-statements-per-line */ /* eslint-disable @typescript-eslint/member-ordering, @typescript-eslint/prefer-for-of, max-statements-per-line */
const SPEAKING_THRESHOLD = 0.015; const SPEAKING_THRESHOLD = 0.015;

View File

@@ -4,11 +4,11 @@ import {
inject inject
} from '@angular/core'; } from '@angular/core';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { STORAGE_KEY_USER_VOLUMES } from '../../../core/constants'; import { STORAGE_KEY_USER_VOLUMES } from '../../../../core/constants';
import { ScreenShareFacade } from '../../../domains/screen-share'; import { ScreenShareFacade } from '../../../../domains/screen-share';
import { User } from '../../../shared-kernel'; import { User } from '../../../../shared-kernel';
import { selectAllUsers, selectCurrentUser } from '../../../store/users/users.selectors'; import { selectAllUsers, selectCurrentUser } from '../../../../store/users/users.selectors';
import { VoiceConnectionFacade } from './voice-connection.facade'; import { VoiceConnectionFacade } from '../facades/voice-connection.facade';
export interface PlaybackOptions { export interface PlaybackOptions {
isConnected: boolean; isConnected: boolean;

View File

@@ -0,0 +1,3 @@
export { LATENCY_PROFILE_BITRATES } from '../../../../infrastructure/realtime/realtime.constants';
export type { LatencyProfile } from '../../../../shared-kernel';
export type { VoiceStateSnapshot } from '../../../../infrastructure/realtime/realtime.types';

View File

@@ -1,3 +0,0 @@
export { LATENCY_PROFILE_BITRATES } from '../../../infrastructure/realtime/realtime.constants';
export type { LatencyProfile } from '../../../shared-kernel';
export type { VoiceStateSnapshot } from '../../../infrastructure/realtime/realtime.types';

View File

@@ -1,4 +1,4 @@
export * from './application/voice-connection.facade'; export * from './application/facades/voice-connection.facade';
export * from './application/voice-activity.service'; export * from './application/services/voice-activity.service';
export * from './application/voice-playback.service'; export * from './application/services/voice-playback.service';
export * from './domain/voice-connection.models'; export * from './domain/models/voice-connection.model';

View File

@@ -22,7 +22,7 @@ import {
import { VoiceSessionFacade } from '../../application/voice-session.facade'; import { VoiceSessionFacade } from '../../application/voice-session.facade';
import { loadVoiceSettingsFromStorage, saveVoiceSettingsToStorage } from '../../infrastructure/voice-settings.storage'; import { loadVoiceSettingsFromStorage, saveVoiceSettingsToStorage } from '../../infrastructure/voice-settings.storage';
import { VoiceConnectionFacade } from '../../../../domains/voice-connection'; import { VoiceConnectionFacade } from '../../../../domains/voice-connection';
import { VoicePlaybackService } from '../../../../domains/voice-connection/application/voice-playback.service'; import { VoicePlaybackService } from '../../../../domains/voice-connection';
import { ScreenShareFacade, ScreenShareQuality } from '../../../../domains/screen-share'; import { ScreenShareFacade, ScreenShareQuality } from '../../../../domains/screen-share';
import { UsersActions } from '../../../../store/users/users.actions'; import { UsersActions } from '../../../../store/users/users.actions';
import { selectCurrentUser } from '../../../../store/users/users.selectors'; import { selectCurrentUser } from '../../../../store/users/users.selectors';

View File

@@ -25,7 +25,7 @@ import {
import { VoiceSessionFacade } from '../../application/voice-session.facade'; import { VoiceSessionFacade } from '../../application/voice-session.facade';
import { loadVoiceSettingsFromStorage, saveVoiceSettingsToStorage } from '../../infrastructure/voice-settings.storage'; import { loadVoiceSettingsFromStorage, saveVoiceSettingsToStorage } from '../../infrastructure/voice-settings.storage';
import { VoiceActivityService, VoiceConnectionFacade } from '../../../../domains/voice-connection'; import { VoiceActivityService, VoiceConnectionFacade } from '../../../../domains/voice-connection';
import { PlaybackOptions, VoicePlaybackService } from '../../../../domains/voice-connection/application/voice-playback.service'; import { PlaybackOptions, VoicePlaybackService } from '../../../../domains/voice-connection';
import { ScreenShareFacade, ScreenShareQuality } from '../../../../domains/screen-share'; import { ScreenShareFacade, ScreenShareQuality } from '../../../../domains/screen-share';
import { UsersActions } from '../../../../store/users/users.actions'; import { UsersActions } from '../../../../store/users/users.actions';
import { selectCurrentUser } from '../../../../store/users/users.selectors'; import { selectCurrentUser } from '../../../../store/users/users.selectors';

View File

@@ -37,7 +37,7 @@ import { ScreenShareFacade } from '../../../domains/screen-share';
import { NotificationsFacade } from '../../../domains/notifications'; import { NotificationsFacade } from '../../../domains/notifications';
import { VoiceActivityService, VoiceConnectionFacade } from '../../../domains/voice-connection'; import { VoiceActivityService, VoiceConnectionFacade } from '../../../domains/voice-connection';
import { VoiceSessionFacade, VoiceWorkspaceService } from '../../../domains/voice-session'; import { VoiceSessionFacade, VoiceWorkspaceService } from '../../../domains/voice-session';
import { VoicePlaybackService } from '../../../domains/voice-connection/application/voice-playback.service'; import { VoicePlaybackService } from '../../../domains/voice-connection';
import { VoiceControlsComponent } from '../../../domains/voice-session/feature/voice-controls/voice-controls.component'; import { VoiceControlsComponent } from '../../../domains/voice-session/feature/voice-controls/voice-controls.component';
import { isChannelNameTaken, normalizeChannelName } from '../../../store/rooms/room-channels.rules'; import { isChannelNameTaken, normalizeChannelName } from '../../../store/rooms/room-channels.rules';
import { import {

View File

@@ -21,7 +21,7 @@ import { ElectronBridgeService } from '../../../../core/platform/electron/electr
import { VoiceConnectionFacade } from '../../../../domains/voice-connection'; import { VoiceConnectionFacade } from '../../../../domains/voice-connection';
import { SCREEN_SHARE_QUALITY_OPTIONS, ScreenShareQuality } from '../../../../domains/screen-share'; import { SCREEN_SHARE_QUALITY_OPTIONS, ScreenShareQuality } from '../../../../domains/screen-share';
import { loadVoiceSettingsFromStorage, saveVoiceSettingsToStorage } from '../../../../domains/voice-session'; import { loadVoiceSettingsFromStorage, saveVoiceSettingsToStorage } from '../../../../domains/voice-session';
import { VoicePlaybackService } from '../../../../domains/voice-connection/application/voice-playback.service'; import { VoicePlaybackService } from '../../../../domains/voice-connection';
import { NotificationAudioService, AppSound } from '../../../../core/services/notification-audio.service'; import { NotificationAudioService, AppSound } from '../../../../core/services/notification-audio.service';
import { PlatformService } from '../../../../core/platform'; import { PlatformService } from '../../../../core/platform';

View File

@@ -8,7 +8,7 @@ import {
} from '@angular/core'; } from '@angular/core';
import { NgIcon, provideIcons } from '@ng-icons/core'; import { NgIcon, provideIcons } from '@ng-icons/core';
import { lucideVolume2, lucideVolumeX } from '@ng-icons/lucide'; import { lucideVolume2, lucideVolumeX } from '@ng-icons/lucide';
import { VoicePlaybackService } from '../../../domains/voice-connection/application/voice-playback.service'; import { VoicePlaybackService } from '../../../domains/voice-connection';
import { ContextMenuComponent } from '../context-menu/context-menu.component'; import { ContextMenuComponent } from '../context-menu/context-menu.component';
@Component({ @Component({