native macos backend, reduce latency

This commit is contained in:
Boof2015
2026-03-21 19:07:47 -04:00
parent 78d8be23a3
commit c6fce51a42
12 changed files with 1304 additions and 112 deletions
+54 -5
View File
@@ -1,5 +1,9 @@
import { contextBridge, ipcRenderer } from 'electron'
import type { CaptureBackendSupport } from '../types/capture'
import type { CaptureBackendSupport, CaptureBackendSupportEntry } from '../types/capture'
import type { NativeCaptureAPI } from '../types/nativeCapture'
import type { VisualizerDSP } from '../renderer/audio/native/visualizer-dsp'
type NativeAddonModule = VisualizerDSP & NativeCaptureAPI
// Expose Electron API to renderer
contextBridge.exposeInMainWorld('electronAPI', {
@@ -9,7 +13,13 @@ contextBridge.exposeInMainWorld('electronAPI', {
toggleAlwaysOnTop: () => ipcRenderer.send('window:toggle-always-on-top'),
isAlwaysOnTop: () => ipcRenderer.invoke('window:is-always-on-top'),
getDesktopSources: () => ipcRenderer.invoke('audio:get-desktop-sources') as Promise<{ id: string; name: string }[]>,
getCaptureBackendSupport: () => ipcRenderer.invoke('capture:get-backend-support') as Promise<CaptureBackendSupport>,
getCaptureBackendSupport: async () => {
const support = await ipcRenderer.invoke('capture:get-backend-support') as CaptureBackendSupport
return {
...support,
nativeBackend: resolveNativeCaptureSupport(support.nativeBackend),
} satisfies CaptureBackendSupport
},
expandSettings: (panelHeight: number) => ipcRenderer.send('window:expand-settings', panelHeight),
collapseSettings: (panelHeight: number) => ipcRenderer.send('window:collapse-settings', panelHeight),
setSettingsHeight: (panelHeight: number) => ipcRenderer.send('window:set-settings-height', panelHeight),
@@ -36,15 +46,54 @@ contextBridge.exposeInMainWorld('electronAPI', {
})
// Native DSP module — load if available, gracefully degrade if not
let visualizerDSP: unknown = null
let nativeAddonModule: NativeAddonModule | null = null
try {
const isDev = process.env.NODE_ENV === 'development'
const modulePath = isDev
? require('path').join(__dirname, '../../native/build/Release/visualizer_dsp.node')
: require('path').join(process.resourcesPath!, 'native/visualizer_dsp.node')
visualizerDSP = require(modulePath)
nativeAddonModule = require(modulePath) as NativeAddonModule
} catch {
console.warn('Native DSP module not available — using JS fallback')
}
contextBridge.exposeInMainWorld('visualizerAPI', visualizerDSP)
function resolveNativeCaptureSupport(
fallbackEntry: CaptureBackendSupportEntry,
): CaptureBackendSupportEntry {
if (process.platform !== 'darwin') {
return fallbackEntry
}
const macosCapture = nativeAddonModule?.macosCapture
if (!macosCapture) {
return {
kind: 'native-macos',
available: false,
reason: 'Native capture module is not available in this build.',
}
}
const support = macosCapture.getSupport()
return {
kind: 'native-macos',
available: support.available,
reason: support.reason,
}
}
const visualizerAPI = nativeAddonModule
? {
oscilloscope: nativeAddonModule.oscilloscope,
spectrum: nativeAddonModule.spectrum,
vectorscope: nativeAddonModule.vectorscope,
}
: null
const nativeCaptureAPI = nativeAddonModule
? {
macosCapture: nativeAddonModule.macosCapture,
}
: null
contextBridge.exposeInMainWorld('visualizerAPI', visualizerAPI)
contextBridge.exposeInMainWorld('nativeCaptureAPI', nativeCaptureAPI)