Files
ytLlive/Services/index.md
T

6.0 KiB
Raw Blame History

Services — index

External-facing logic: YouTube API, persistence. See schema.md for the memory-map conventions.

File Purpose
YouTubeAuthService.cs OAuth2 via Google: loopback callback (http://localhost:8765/oauth2/callback), token exchange, refresh, channel fetch. Constructor takes optional HttpClient + sessionChanged callback (test seam + save hook); session persists via Helpers/TokenStore (DPAPI); ClearSession() signs out (called by MainViewModel.StopStream on End Livestream)
YouTubeStreamService.cs Broadcast/stream management via the v3 API (enableAutoStart/Stop). Not yet switched to the variable reusable stream
YouTubeChatService.cs Polls liveChat/messages, raises MessageReceived; IDisposable
LayoutStore.cs SQLite persistence (Microsoft.Data.Sqlite) at %APPDATA%\ytLlive\ytLlive.db; assets stored as BLOBs keyed by SHA-256 content hash; save/open layout files; schema user_version 6 (Source.ClipShape/IsMirrored via ALTER TABLE for pre-v2 DBs; v3 = singleton Webcam + per-scene WebcamSceneConfig, migrated idempotently without backfill — the stale Source.DeviceId column remains but is no longer read/written; v4 = WebcamSceneConfig.RectWidth/RectHeight, the pre-Round rect for the round-to-rect restore; v5 = Source.IsBackdrop + Source.CaptureKey, the live-capture backdrop; v6 = Scene.HasBackdrop — Live-only policy, one-time backfill turns Starting/BRB/Chat/Ending off + drops their backdrop sources; MainViewModel.EnforceBackdropPolicy re-normalizes on every load)
VideoFrame.cs Normalized CPU frame seam (Width/Height/tightly-packed BGRA byte[]) — the only pixel type the rest of the app knows about; future capture sources (screen, background-removed webcam) feed the same seam
CameraDeviceInfo.cs (Id, DisplayName) for a physical capture device
ICameraEnumerator.cs GetCamerasAsync() — seam so the picker/CameraManager never touch WinRT (tests inject fakes)
ICameraFrameSource.cs StartAsync/StopAsync/FrameAvailable(VideoFrame) — seam for a running capture source
MediaCaptureCameraEnumerator.cs WinRT enumeration via DeviceInformation.FindAllAsync(DeviceClass.VideoCapture)
MediaCaptureFrameSource.cs CPU-first MediaCapture source (MemoryPreference = Cpu, BGRA8 via CreateFrameReaderAsync); frames arrive on a worker thread
CameraManager.cs Webcam capture ownership: refcounted by DeviceId, one shared WriteableBitmap per camera, dispatcher-coalesced ~render-rate UI updates (latest-frame drop); PreviewBitmapChanged/CameraFailed events. ReleaseAsync decrements a ref (stops at zero); ReleaseAllAsync force-drops every ref + stops the source (webcam swap / layout reload). GetPreviewBitmap(deviceId) returns the current shared bitmap so a WebcamSceneConfig added mid-session (after the first frame already created the bitmap) still receives the live frames
IFullScreenDetector.cs Seam for the win32 full-screen detector: int? GetForegroundFullScreenMonitorIndex(), int PrimaryMonitorIndex(), IReadOnlyList<DisplayInfo> GetDisplays()
Win32FullScreenDetector.cs GetForegroundWindow + DwmGetWindowAttribute(DWMWA_EXTENDED_FRAME_BOUNDS) + MonitorFromWindow + GetMonitorInfo; monitor covers all four edges → full-screen; own process excluded; monitor order = EnumDisplayMonitors order (static GetMonitorHandle(int) maps index→HMONITOR for the capture factory). GetDisplays() returns DisplayInfo (index/name/resolution/bounds/IsPrimary, friendly name via EnumDisplayDevices) for the in-app "Capture Display" picker; PrimaryMonitorIndex() is the auto-key fallback when no full-screen game is detected
IScreenCaptureSource.cs Key + StartAsync/StopAsync/FrameAvailable(VideoFrame) — seam so ScreenCaptureManager never touches WinRT (tests inject fakes)
Direct3D11Helper.cs The one shared IDirect3DDevice per process: P/Invoke d3d11.dll!D3D11CreateDevice (hardware, BGRA_SUPPORT, explicit 11.1-first feature array) → QI IDXGIDevice → the WinRT interop export CreateDirect3D11DeviceFromDXGIDeviceMarshalInterface<IDirect3DDevice>.FromAbi. CsWinRT does not project Windows.Graphics.Direct3D11.Direct3D11Helper, so this hand-rolls it. Do not revert to QI-for-IDirect3DDxgiInterfaceAccess — the device no longer exposes it on newer Windows (E_NOINTERFACE on build 26200)
CaptureInterop.cs ComImport bridges the WinRT-projection gap: IGraphicsCaptureItemInterop (CreateForMonitor/CreateForWindow), IInitializeWithWindow (GraphicsCapturePicker owner window so the OS picker shows)
ScreenCaptureFrameSource.cs One Direct3D11CaptureFramePool (free-threaded, 2 buffers) + session per target; frames → SoftwareBitmap.CreateCopyFromSurfaceAsync (BGRA, alpha ignored) → VideoFrame, bytes read via WindowsRuntimeMarshal.TryGetDataUnsafe (CsWinRT-safe — the IMemoryBufferByteAccess ComImport cast fails on every frame and is gone). Surfaces > 1920×1080 downscaled bilinearly to the master; conversion failures logged ≤ once/5 s. DRM content = black frames (OS limit). CreateForMonitor/CreateForWindow/CreateForPicker
ScreenCaptureManager.cs Screen-capture ownership mirroring CameraManager: refcounted by target key, one shared WriteableBitmap, dispatcher-coalesced latest-frame copies; PreviewBitmapChanged/CaptureFailed events; ReleaseAllAsync used on re-designation
ScreenCaptureSourceFactory.cs Resolve(key) parses monitor:<n> / window:<hwnd> / picker:<name> into a source; PickAsync() shows the OS GraphicsCapturePicker and returns the picker: key (transient — a reload falls back to auto-detection)

Related: constructed in ViewModels/MainViewModel.cs (no DI container yet). Models in Models/index.md. OAuth credentials live in Helpers/OAuthCredentials.cs.