// System-audio loopback — renderer-driven. Chromium's // `chromeMediaSource: 'desktop'` constraint on getUserMedia accepts a // source id and returns a MediaStream that contains the OS mixer output. // Main's only job is to resolve which source id the renderer should feed // to getUserMedia (typically the primary screen). See the display-media // handler in main.ts which grants the request automatically. import { desktopCapturer, ipcMain } from 'electron'; import { CHANNELS } from '../ipc-types'; export interface ResolveLoopbackSourceResult { sourceId: string; } export function register(): void { ipcMain.handle( CHANNELS.AUDIO_LOOPBACK_RESOLVE_SOURCE, async (): Promise => { // Enumerate only screens; windows don't expose audio loopback on // Windows and there's no meaningful "system audio" tied to a // single window anyway. Primary screen is the first entry — the // id is stable across calls as long as the display config doesn't // change mid-session. const sources = await desktopCapturer.getSources({ types: ['screen'], fetchWindowIcons: false, }); const first = sources[0]; if (!first) return null; return { sourceId: first.id }; }, ); // The legacy start/stop channels are left unregistered on purpose — // their constants still exist in ipc-types.ts for backwards compatible // import paths, but there is no corresponding handler. }