Files
Toju/src/app/domains/voice-session/README.md
2026-03-23 01:34:18 +01:00

4.6 KiB

Voice Session Domain

Tracks voice session metadata across client-side navigation and manages the voice workspace UI state (expanded, minimized, hidden). This domain does not touch WebRTC directly; actual connections live in voice-connection and infrastructure/realtime.

Module map

voice-session/
├── application/
│   ├── voice-session.facade.ts              Tracks active voice session, drives floating controls
│   └── voice-workspace.service.ts           Workspace mode (hidden/expanded/minimized), focused stream, mini-window position
│
├── domain/
│   ├── voice-session.logic.ts               isViewingVoiceSessionServer, buildVoiceSessionRoom
│   └── voice-session.models.ts              VoiceSessionInfo interface
│
├── infrastructure/
│   └── voice-settings.storage.ts            Persists audio device IDs, volumes, bitrate, latency, noise reduction to localStorage
│
├── feature/
│   ├── voice-controls/                      Full voice control panel (mic, deafen, devices, screen share, settings)
│   └── floating-voice-controls/             Minimal overlay when user navigates away from the voice server
│
└── index.ts                                 Barrel exports

How the pieces connect

The facade manages session bookkeeping. The workspace service owns view state. Settings storage provides persistence for user preferences. Neither service opens any WebRTC connections.

graph TD
    VSF[VoiceSessionFacade]
    VWS[VoiceWorkspaceService]
    VSS[voiceSettingsStorage]
    Logic[voice-session.logic]
    VC[VoiceControlsComponent]
    FC[FloatingVoiceControlsComponent]
    Store[NgRx Store]

    VC --> VSF
    VC --> VWS
    VC --> VSS
    FC --> VSF
    FC --> VWS
    VSF --> Logic
    VSF --> Store
    VWS --> VSF

    click VSF "application/voice-session.facade.ts" "Tracks active voice session" _blank
    click VWS "application/voice-workspace.service.ts" "Workspace mode and focused stream" _blank
    click VSS "infrastructure/voice-settings.storage.ts" "localStorage persistence for audio settings" _blank
    click Logic "domain/voice-session.logic.ts" "Pure helper functions" _blank
    click VC "feature/voice-controls/" "Full voice control panel" _blank
    click FC "feature/floating-voice-controls/" "Minimal floating overlay" _blank

Session lifecycle

stateDiagram-v2
    [*] --> NoSession
    NoSession --> Active: startSession(info)
    Active --> Active: checkCurrentRoute(serverId)
    Active --> NoSession: endSession()
    
    state Active {
        [*] --> ViewingServer
        ViewingServer --> AwayFromServer: navigated to different server
        AwayFromServer --> ViewingServer: navigated back / navigateToVoiceServer()
    }

When a voice session is active and the user navigates away from the voice-connected server, showFloatingControls becomes true and the floating overlay appears. Clicking the overlay dispatches RoomsActions.viewServer to navigate back.

Workspace modes

VoiceWorkspaceService controls the voice workspace panel state. The workspace is only visible when the user is viewing the voice-connected server.

stateDiagram-v2
    [*] --> Hidden
    Hidden --> Expanded: open()
    Expanded --> Minimized: minimize()
    Expanded --> Hidden: close() / showChat()
    Minimized --> Expanded: restore()
    Minimized --> Hidden: close()
    Expanded --> Hidden: voice session ends
    Minimized --> Hidden: voice session ends

The minimized mode renders a draggable mini-window. Its position is tracked in miniWindowPosition and clamped to viewport bounds on resize. focusedStreamId controls which screen-share stream gets the widescreen treatment in expanded mode.

Voice settings

Settings are stored in localStorage under a single JSON key. All values are validated and clamped on load to defend against corrupt storage.

Setting Default Range
inputDevice "" device ID string
outputDevice "" device ID string
inputVolume 100 0 -- 100
outputVolume 100 0 -- 100
audioBitrate 96 kbps 32 -- 256
latencyProfile "balanced" low / balanced / high
noiseReduction true boolean
screenShareQuality "balanced" low / balanced / high
askScreenShareQuality true boolean
includeSystemAudio false boolean

loadVoiceSettingsFromStorage() and saveVoiceSettingsToStorage(patch) are the only entry points. The save function merges the patch with the current stored value so callers only need to pass changed fields.