feat: v1.2.0 — auto-reconnect, recording, monitor bounds, WASAPI loopback
- Auto-reconnect: stream retries with exponential backoff (2s→30s max) on unexpected exit; stops only when user clicks Stop - Recording: global RecordingBar with folder picker, segment duration (min), per-stream checkbox, Select All; uses FFmpeg tee muxer for simultaneous SRT + segmented .ts file output - Monitor capture: PowerShell System.Windows.Forms.Screen gives exact pixel bounds (x/y/width/height); per-monitor deviceName is now unique (desktop_monitor_N); gdigrab uses -offset_x/-offset_y/-video_size - Window capture: windowTitle now explicitly propagated in handleVideoSelect - System audio: added WASAPI Loopback option (no VB-Audio required), existing virtual-audio-capturer kept as fallback - Reconnecting event forwarded to renderer; status shows "Reconnecting…" with attempt count in logs - IPC: pick-folder (dialog.showOpenDialog) and open-folder (shell.openPath) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+16
-11
@@ -2,7 +2,7 @@ const { contextBridge, ipcRenderer } = require('electron')
|
||||
|
||||
contextBridge.exposeInMainWorld('electronAPI', {
|
||||
// Config
|
||||
getConfig: () => ipcRenderer.invoke('get-config'),
|
||||
getConfig: () => ipcRenderer.invoke('get-config'),
|
||||
saveConfig: (config) => ipcRenderer.invoke('save-config', config),
|
||||
|
||||
// Devices
|
||||
@@ -10,25 +10,30 @@ contextBridge.exposeInMainWorld('electronAPI', {
|
||||
getWindows: () => ipcRenderer.invoke('get-windows'),
|
||||
|
||||
// Streams
|
||||
startStream: (config) => ipcRenderer.invoke('start-stream', config),
|
||||
stopStream: (id) => ipcRenderer.invoke('stop-stream', id),
|
||||
getActiveStreams: () => ipcRenderer.invoke('get-active-streams'),
|
||||
startStream: (config) => ipcRenderer.invoke('start-stream', config),
|
||||
stopStream: (id) => ipcRenderer.invoke('stop-stream', id),
|
||||
getActiveStreams: () => ipcRenderer.invoke('get-active-streams'),
|
||||
|
||||
// Tolbek receiver
|
||||
startTolbek: (config) => ipcRenderer.invoke('start-tolbek', config),
|
||||
stopTolbek: () => ipcRenderer.invoke('stop-tolbek'),
|
||||
stopTolbek: () => ipcRenderer.invoke('stop-tolbek'),
|
||||
|
||||
// File system helpers
|
||||
pickFolder: () => ipcRenderer.invoke('pick-folder'),
|
||||
openFolder: (p) => ipcRenderer.invoke('open-folder', p),
|
||||
|
||||
// Window controls
|
||||
minimizeWindow: () => ipcRenderer.invoke('minimize-window'),
|
||||
hideWindow: () => ipcRenderer.invoke('hide-window'),
|
||||
hideWindow: () => ipcRenderer.invoke('hide-window'),
|
||||
updateTrayCount: (count) => ipcRenderer.send('update-tray-count', count),
|
||||
|
||||
// Event listeners
|
||||
onStreamStatus: (cb) => ipcRenderer.on('stream-status', (_, data) => cb(data)),
|
||||
onStreamLog: (cb) => ipcRenderer.on('stream-log', (_, data) => cb(data)),
|
||||
onStreamError: (cb) => ipcRenderer.on('stream-error', (_, data) => cb(data)),
|
||||
onStreamEnded: (cb) => ipcRenderer.on('stream-ended', (_, data) => cb(data)),
|
||||
onAllStreamsStopped: (cb) => ipcRenderer.on('all-streams-stopped', () => cb()),
|
||||
onStreamStatus: (cb) => ipcRenderer.on('stream-status', (_, d) => cb(d)),
|
||||
onStreamLog: (cb) => ipcRenderer.on('stream-log', (_, d) => cb(d)),
|
||||
onStreamError: (cb) => ipcRenderer.on('stream-error', (_, d) => cb(d)),
|
||||
onStreamEnded: (cb) => ipcRenderer.on('stream-ended', (_, d) => cb(d)),
|
||||
onStreamReconnecting: (cb) => ipcRenderer.on('stream-reconnecting', (_, d) => cb(d)),
|
||||
onAllStreamsStopped: (cb) => ipcRenderer.on('all-streams-stopped', () => cb()),
|
||||
|
||||
removeAllListeners: (channel) => ipcRenderer.removeAllListeners(channel)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user