Compare commits
No commits in common. "main" and "0.0.57" have entirely different histories.
2 changed files with 4 additions and 101 deletions
71
main.js
71
main.js
|
|
@ -2,10 +2,9 @@ const { app, BrowserWindow, session, desktopCapturer, ipcMain, clipboard } = req
|
||||||
const { autoUpdater } = require('electron-updater');
|
const { autoUpdater } = require('electron-updater');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const packageJson = require('./package.json');
|
const packageJson = require('./package.json');
|
||||||
const PERIODIC_UPDATE_CHECK_INTERVAL_MS = 1 * 60 * 1000;
|
|
||||||
|
|
||||||
const updateState = {
|
const updateState = {
|
||||||
status: 'idle', // idle | checking | available | downloading | downloaded | installing | not-available | error
|
status: 'idle', // idle | checking | available | downloading | downloaded | not-available | error
|
||||||
info: null,
|
info: null,
|
||||||
error: null,
|
error: null,
|
||||||
};
|
};
|
||||||
|
|
@ -25,8 +24,6 @@ function isNewerVersionAvailable(info) {
|
||||||
}
|
}
|
||||||
|
|
||||||
let updateCheckInProgress = false;
|
let updateCheckInProgress = false;
|
||||||
let installInProgress = false;
|
|
||||||
let periodicUpdateTimer = null;
|
|
||||||
|
|
||||||
function resolveBackendUrl() {
|
function resolveBackendUrl() {
|
||||||
const configuredUrl = (process.env.CHATTZ_URL || process.env.APP_BASE_URL || '').trim();
|
const configuredUrl = (process.env.CHATTZ_URL || process.env.APP_BASE_URL || '').trim();
|
||||||
|
|
@ -52,10 +49,6 @@ function webContentsOrigin(webContents) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function runUpdateCheck(reason = 'manual') {
|
async function runUpdateCheck(reason = 'manual') {
|
||||||
if (installInProgress) {
|
|
||||||
console.log(`Update check skipped (${reason}): install already in progress`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (updateCheckInProgress) {
|
if (updateCheckInProgress) {
|
||||||
console.log(`Update check skipped (${reason}): another check is already in progress`);
|
console.log(`Update check skipped (${reason}): another check is already in progress`);
|
||||||
return;
|
return;
|
||||||
|
|
@ -85,57 +78,6 @@ async function runUpdateCheck(reason = 'manual') {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function installDownloadedUpdate() {
|
|
||||||
if (installInProgress) {
|
|
||||||
console.log('Update install already in progress');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
installInProgress = true;
|
|
||||||
updateState.status = 'installing';
|
|
||||||
updateState.error = null;
|
|
||||||
broadcastUpdateState();
|
|
||||||
|
|
||||||
const wins = BrowserWindow.getAllWindows();
|
|
||||||
for (const win of wins) {
|
|
||||||
if (win.isDestroyed()) continue;
|
|
||||||
try {
|
|
||||||
win.removeAllListeners('close');
|
|
||||||
win.destroy();
|
|
||||||
} catch (err) {
|
|
||||||
console.warn('Failed to destroy window before update install', err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setImmediate(() => {
|
|
||||||
try {
|
|
||||||
autoUpdater.quitAndInstall(false, true);
|
|
||||||
} catch (err) {
|
|
||||||
installInProgress = false;
|
|
||||||
updateState.status = 'error';
|
|
||||||
updateState.error = err && err.message ? err.message : String(err);
|
|
||||||
broadcastUpdateState();
|
|
||||||
console.error('quitAndInstall failed', err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
if (installInProgress) {
|
|
||||||
console.warn('Update install is still waiting for app shutdown');
|
|
||||||
}
|
|
||||||
}, 15000);
|
|
||||||
}
|
|
||||||
|
|
||||||
function startPeriodicUpdateChecks() {
|
|
||||||
if (periodicUpdateTimer || !app.isPackaged) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
periodicUpdateTimer = setInterval(() => {
|
|
||||||
void runUpdateCheck('periodic');
|
|
||||||
}, PERIODIC_UPDATE_CHECK_INTERVAL_MS);
|
|
||||||
}
|
|
||||||
|
|
||||||
function createWindow() {
|
function createWindow() {
|
||||||
const sess = session.fromPartition('persist:chattz');
|
const sess = session.fromPartition('persist:chattz');
|
||||||
const backendUrl = resolveBackendUrl();
|
const backendUrl = resolveBackendUrl();
|
||||||
|
|
@ -267,7 +209,6 @@ app.whenReady().then(() => {
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.on('download-update', () => {
|
ipcMain.on('download-update', () => {
|
||||||
if (installInProgress) return;
|
|
||||||
updateState.status = 'downloading';
|
updateState.status = 'downloading';
|
||||||
updateState.error = null;
|
updateState.error = null;
|
||||||
broadcastUpdateState();
|
broadcastUpdateState();
|
||||||
|
|
@ -275,14 +216,13 @@ app.whenReady().then(() => {
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.on('quit-and-install', () => {
|
ipcMain.on('quit-and-install', () => {
|
||||||
installDownloadedUpdate();
|
autoUpdater.quitAndInstall();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Check once on startup
|
// Check once on startup
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
void runUpdateCheck('startup');
|
void runUpdateCheck('startup');
|
||||||
}, 5000);
|
}, 5000);
|
||||||
startPeriodicUpdateChecks();
|
|
||||||
|
|
||||||
app.on('activate', () => {
|
app.on('activate', () => {
|
||||||
if (BrowserWindow.getAllWindows().length === 0) {
|
if (BrowserWindow.getAllWindows().length === 0) {
|
||||||
|
|
@ -297,13 +237,6 @@ app.on('window-all-closed', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.on('before-quit', () => {
|
|
||||||
if (periodicUpdateTimer) {
|
|
||||||
clearInterval(periodicUpdateTimer);
|
|
||||||
periodicUpdateTimer = null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function safeOrigin(value) {
|
function safeOrigin(value) {
|
||||||
try {
|
try {
|
||||||
return new URL(value).origin;
|
return new URL(value).origin;
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,6 @@ const state = {
|
||||||
viewMode: 'chat', // 'chat' or 'video'
|
viewMode: 'chat', // 'chat' or 'video'
|
||||||
iceServers: [{ urls: "stun:stun.l.google.com:19302" }],
|
iceServers: [{ urls: "stun:stun.l.google.com:19302" }],
|
||||||
peerGainNodes: new Map(), // userId -> GainNode
|
peerGainNodes: new Map(), // userId -> GainNode
|
||||||
peerAudioNodes: new Map(), // userId -> { sourceNode, compressorNode, gainNode }
|
|
||||||
visibleVolumeSliders: new Set(), // userIds whose sliders are visible
|
visibleVolumeSliders: new Set(), // userIds whose sliders are visible
|
||||||
},
|
},
|
||||||
voicePresencePollId: null,
|
voicePresencePollId: null,
|
||||||
|
|
@ -1040,24 +1039,7 @@ function shouldInitiateOffer(peerId) {
|
||||||
return state.me.id > peerId;
|
return state.me.id > peerId;
|
||||||
}
|
}
|
||||||
|
|
||||||
function disconnectPeerAudioNodes(peerId) {
|
|
||||||
const nodes = state.voice.peerAudioNodes.get(peerId);
|
|
||||||
if (!nodes) return;
|
|
||||||
|
|
||||||
for (const node of [nodes.sourceNode, nodes.compressorNode, nodes.gainNode]) {
|
|
||||||
try {
|
|
||||||
node?.disconnect();
|
|
||||||
} catch { }
|
|
||||||
}
|
|
||||||
|
|
||||||
state.voice.peerAudioNodes.delete(peerId);
|
|
||||||
state.voice.peerGainNodes.delete(peerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
function stopAndClearAudioPipeline() {
|
function stopAndClearAudioPipeline() {
|
||||||
for (const peerId of state.voice.peerAudioNodes.keys()) {
|
|
||||||
disconnectPeerAudioNodes(peerId);
|
|
||||||
}
|
|
||||||
if (state.voice.deepFilterProcessor) {
|
if (state.voice.deepFilterProcessor) {
|
||||||
state.voice.deepFilterProcessor.destroy();
|
state.voice.deepFilterProcessor.destroy();
|
||||||
state.voice.deepFilterProcessor = null;
|
state.voice.deepFilterProcessor = null;
|
||||||
|
|
@ -1283,7 +1265,7 @@ async function createLocalVoiceStream() {
|
||||||
sampleRate: 48000,
|
sampleRate: 48000,
|
||||||
echoCancellation: true,
|
echoCancellation: true,
|
||||||
noiseSuppression: false,
|
noiseSuppression: false,
|
||||||
autoGainControl: true,
|
autoGainControl: false,
|
||||||
},
|
},
|
||||||
video: false,
|
video: false,
|
||||||
};
|
};
|
||||||
|
|
@ -1406,27 +1388,16 @@ function ensurePeerConnection(peerId) {
|
||||||
const ctx = state.voice.audioContext;
|
const ctx = state.voice.audioContext;
|
||||||
if (ctx.state === 'suspended') ctx.resume();
|
if (ctx.state === 'suspended') ctx.resume();
|
||||||
|
|
||||||
disconnectPeerAudioNodes(peerId);
|
|
||||||
|
|
||||||
const sourceNode = ctx.createMediaStreamSource(audio.srcObject);
|
const sourceNode = ctx.createMediaStreamSource(audio.srcObject);
|
||||||
const compressorNode = ctx.createDynamicsCompressor();
|
|
||||||
const gainNode = ctx.createGain();
|
const gainNode = ctx.createGain();
|
||||||
|
|
||||||
compressorNode.threshold.setValueAtTime(-24, ctx.currentTime);
|
|
||||||
compressorNode.knee.setValueAtTime(18, ctx.currentTime);
|
|
||||||
compressorNode.ratio.setValueAtTime(4, ctx.currentTime);
|
|
||||||
compressorNode.attack.setValueAtTime(0.003, ctx.currentTime);
|
|
||||||
compressorNode.release.setValueAtTime(0.25, ctx.currentTime);
|
|
||||||
|
|
||||||
const currentVolume = state.userVolumes.get(peerId) ?? 1.0;
|
const currentVolume = state.userVolumes.get(peerId) ?? 1.0;
|
||||||
gainNode.gain.setValueAtTime(currentVolume, ctx.currentTime);
|
gainNode.gain.setValueAtTime(currentVolume, ctx.currentTime);
|
||||||
|
|
||||||
sourceNode.connect(compressorNode);
|
sourceNode.connect(gainNode);
|
||||||
compressorNode.connect(gainNode);
|
|
||||||
gainNode.connect(ctx.destination);
|
gainNode.connect(ctx.destination);
|
||||||
|
|
||||||
state.voice.peerGainNodes.set(peerId, gainNode);
|
state.voice.peerGainNodes.set(peerId, gainNode);
|
||||||
state.voice.peerAudioNodes.set(peerId, { sourceNode, compressorNode, gainNode });
|
|
||||||
|
|
||||||
// Mute the original element as we play through Web Audio destination
|
// Mute the original element as we play through Web Audio destination
|
||||||
audio.volume = 0;
|
audio.volume = 0;
|
||||||
|
|
@ -1611,7 +1582,6 @@ async function joinVoice() {
|
||||||
pc.close();
|
pc.close();
|
||||||
state.voice.peerConnections.delete(msg.user_id);
|
state.voice.peerConnections.delete(msg.user_id);
|
||||||
}
|
}
|
||||||
disconnectPeerAudioNodes(msg.user_id);
|
|
||||||
document.getElementById(`audio-${msg.user_id}`)?.remove();
|
document.getElementById(`audio-${msg.user_id}`)?.remove();
|
||||||
} else if (msg.type === "signal") {
|
} else if (msg.type === "signal") {
|
||||||
await handleSignal(msg.from_user_id, msg.kind, msg.data);
|
await handleSignal(msg.from_user_id, msg.kind, msg.data);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue