- P2P: NSD advertiser, LAN TLS signaling server (port 8765), WebRTC peer
manager, remote signaling client, control/file channel handlers
- LAN auth-pair endpoint generates pairing code via OkHttp (with auto
token refresh) for phone app auto-discovery login
- Shared self-signed certificate (lck_lan.p12) for secure LAN comms
- Service starts at app launch and on BOOT_COMPLETED via BootReceiver
- P2P session waits for auto-login before starting NSD/signaling
- Native encoder: encoded frame callback for H.264 passthrough to WebRTC
- WebRTC dependency switched to io.github.webrtc-sdk (Maven Central)
Continuously records gameplay in the background when a game is connected.
Keeps the last N minutes (configurable) as ~30s self-contained segment files
on disk, with auto-trimming and thumbnail generation per segment.
C++ CortexRecorder writes .seg binary format in real-time, integrated into
StreamingEngine alongside existing ClipRecorder. StreamingManager routes
frames to cortex-only engine when not streaming, and enables cortex on the
streaming engine during live streams for seamless coexistence.
New Cortex tab in bottom navigation with enable toggle, duration presets,
storage usage, and session list with thumbnails.
- Add PairingCodeResponse, PairingStatusResponse models + API endpoints
- Add pairing code card to Accounts screen with countdown + auto-dismiss on redeem
- Add Portal service color/label to chat and dashboard live section
- Move portal visibility toggle to dashboard, add UpdateProfileRequest
- Replace Live Chat section with unified Live section showing per-destination
cards with chat button (unread badge) and open-in-browser button
- Show error placeholder when a service fails to connect
- Cleanup button now deletes both ENDED and DRAFT plans
- deletePlan handles 404 gracefully (still removes from Room DB)
- Expose chat connection status and account display names in ViewModel
- WebSocket chat client with auto-reconnect and re-subscribe on connect
- ChatScreen with message bubbles, mod/broadcaster badges, send capability
- Dashboard Live Chat section with unread badges per destination
- Chat notification manager for background notifications
- Chat navigation route and ViewModel
- Fix encoder PTS: use wall-clock relative timestamps to prevent backward
jumps when transitioning from standby to game frames (MediaCodec drops)
- Suppress standby frames while game is active (500ms timeout) to prevent
flickering between game video and color bars
- Remove standby color bar pattern, use plain dark background
- Fix vertical flip and BGR→RGB swizzle in composition base pass shader
- Pass buffer index through native pipeline for pool slot release callback
- Start engine for already-LIVE plans when APP_STREAMING mode is active
- Use texture pool dimensions for encoder resolution instead of hardcoded 1920x1080
- Backend: POST /providers/accounts/custom-rtmp to save reusable RTMP servers
- Backend: Encrypt rtmpUrl/streamKey in existing token fields, decrypt on GET
- Backend: Skip token revocation on DELETE for CUSTOM_RTMP accounts
- Backend: Decrypt CUSTOM_RTMP credentials into destinations on plan create/update
- Android: Add rtmpUrl/streamKey to LinkedAccount entity + shared parcelable (Room v6)
- Android: Add Custom RTMP dialog in AccountsScreen, auto-fill in plan destination picker
- Android: Handle CUSTOM_RTMP accounts in CreatePlanViewModel.loadExistingPlan
- Add local RTMP test server (tools/rtmp-server.js) with auto-ffplay on publish
- Add composition pipeline native code
- Add AppPreferences for persisted default streaming mode (IN_GAME/APP_STREAMING)
- Add GameInfoProvider to resolve package names to icons via PackageManager
- Add GameInfoRow composable used across dashboard, plans, and clients screens
- Show backend version in dashboard status card
- Default execution mode toggle on dashboard, picked up by new plans
- Plan edit mode with full CRUD support
- Fix CMake IMPORTED_NO_SONAME to prevent absolute Windows paths in DT_NEEDED
- Catch Throwable (not just Exception) for UnsatisfiedLinkError in streaming start
- Add C++ native streaming engine (RTMP client, EGL context, streaming engine, JNI bridge)
- Add pre-built arm64-v8a libs (librtmp, libssl, libcrypto, libz) and headers
- Add Kotlin streaming layer (NativeStreamingEngine, StreamingManager, StreamingStats)
- Add AIDL streaming interface (ILckStreamingService, ILckStreamingCallback, StreamingConfig)
- Add LckStreamingServiceImpl with BIND_STREAMING action support
- Add APP_STREAMING execution mode with auto-start/stop on plan lifecycle
- SDK: add bindStreaming(), submitVideoFrame(), submitAudioFrame() to LckControlClient
- Dashboard: replace linked accounts with server status card, move health polling from nav
- Remove health check dot overlay from Dashboard nav icon
- Accounts: add enable/disable toggle per account (persists locally, excluded from default plans)
- Plans: add gameId field linked to game package ID, resolved from ClientTracker for default plans
- Service: pass executionMode+gameId through createStreamPlan, filter enabled accounts in createDefaultPlan
- Room DB migration 4→5: add isEnabled column to linked_accounts, gameId column to stream_plans
- Add docs (hub vs control comparison)
Remove USE_LCK_CONTROL permission from service to fix binding failures
caused by Android revoking custom permissions on app reinstall. Add
auto-cleanup of dead clients via RemoteCallbackList.onCallbackDied and
handle corrupted EncryptedSharedPreferences keyset gracefully. Lower
SDK minSdk to 32.
- Service handles auth: auto-login via Quest SDK on onCreate, periodic
token refresh, isAuthenticated/login AIDL methods
- Clients tab shows actual connected game clients from ClientTracker
instead of plans filtered by status
- Create Plan service picker shows "YouTube - DisplayName" per linked
account instead of raw service IDs
- createDefaultPlan AIDL method creates plan with one destination per
linked account (unlisted)
- Session validation on Activity open via getMe() call
- Backend health indicator (green/red dot) on Dashboard nav icon
- ConnectedClientInfo parcelable for client data over AIDL
- SDK client exposes isAuthenticated, login, createDefaultPlan,
getConnectedClients, authenticated StateFlow
- Allow multiple linked accounts per service (YouTube, Twitch)
- LinkedAccount PK changed from serviceId to backend UUID
- StreamDestination now references linkedAccountId
- Room DB migration v2→v3 for new schema
- Unlink endpoint changed to DELETE by account ID
- Accounts UI always shows "Add Account" for all providers
- preparePlan matches destinations by ID instead of serviceId
- Use asyncInitialize with message pump for proper SDK callback delivery
- Fall back to oculusId when numeric user ID unavailable (DUC pending)
- Gracefully handle missing nonce
- Auto-upgrade to full nonce validation when numeric ID becomes available
- versionCode from commit count + offset (always incremental)
- versionName from git tag (semantic versioning)
- BuildConfig.DISPLAY_VERSION shows "0.1.0+N.hash" in login screen
- Updated deploy.ps1 to use git versioning instead of manual bumps