- 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