Files
yass/client/main.js

111 lines
3.1 KiB
JavaScript

const { app, BrowserWindow, desktopCapturer, ipcMain } = require('electron');
const path = require('path');
const PipewireHelper = require('./pipewire');
// Ensure Chromium tries to use PipeWire for screen sharing on Linux
app.commandLine.appendSwitch('enable-features', 'WebRTCPipeWireCapturer');
let mainWindow = null;
function createWindow() {
mainWindow = new BrowserWindow({
width: 1000,
height: 800,
icon: path.join(__dirname, 'icon.png'),
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
nodeIntegration: false,
contextIsolation: true,
}
});
mainWindow.loadFile('index.html');
mainWindow.on('closed', () => {
mainWindow = null;
});
}
app.whenReady().then(async () => {
// Setup the virtual microphone as soon as the app starts
await PipewireHelper.createVirtualMic();
createWindow();
// Monitor PipeWire graph for new/removed audio streams
PipewireHelper.startMonitoring(async () => {
try {
const apps = await PipewireHelper.getAudioApplications();
if (mainWindow && !mainWindow.isDestroyed()) {
mainWindow.webContents.send('audio-apps-updated', apps);
}
} catch (e) {
console.error('Failed to refresh audio apps:', e);
}
});
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
});
app.on('will-quit', async () => {
PipewireHelper.stopMonitoring();
await PipewireHelper.destroyVirtualMic();
});
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
// Handle IPC request from renderer to get screen/audio sources
ipcMain.handle('get-sources', async () => {
let inputSources = await desktopCapturer.getSources({
types: ['window', 'screen'],
fetchWindowIcons: true
});
// Note: On Wayland, source names come from the ScreenCast portal directly.
// The wayland-helper override was removed because it returned stale/incorrect window titles.
return inputSources.map(source => ({
id: source.id,
name: source.name,
thumbnail: source.thumbnail.toDataURL()
}));
});
// Handle Pipewire specific audio isolation requests
ipcMain.handle('get-audio-apps', async () => {
return await PipewireHelper.getAudioApplications();
});
ipcMain.handle('link-app-audio', async (event, appName) => {
return await PipewireHelper.linkApplicationToMic(appName);
});
ipcMain.handle('link-monitor-audio', async () => {
return await PipewireHelper.linkMonitorToMic();
});
// Handle saving and loading the config.json profile
const fs = require('fs');
const configPath = path.join(__dirname, 'config.json');
ipcMain.handle('get-config', () => {
try {
if (fs.existsSync(configPath)) {
return JSON.parse(fs.readFileSync(configPath, 'utf8'));
}
} catch (e) { console.error("Could not read config", e); }
return { serverUrl: 'http://localhost:3000', serverPassword: '' };
});
ipcMain.handle('save-config', (event, newConfig) => {
fs.writeFileSync(configPath, JSON.stringify(newConfig, null, 2), 'utf8');
});