Skip to content

Commit ded27c0

Browse files
authored
fix: keep active call on lock screen (#80)
1 parent 089872b commit ded27c0

File tree

7 files changed

+68
-25
lines changed

7 files changed

+68
-25
lines changed

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
"@nethesis/nethesis-brands-svg-icons": "github:nethesis/Font-Awesome#ns-brands",
5050
"@nethesis/nethesis-light-svg-icons": "github:nethesis/Font-Awesome#ns-light",
5151
"@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid",
52-
"@nethesis/phone-island": "^0.17.11",
52+
"@nethesis/phone-island": "^0.18.0",
5353
"@tailwindcss/forms": "^0.5.7",
5454
"@types/lodash": "^4.14.202",
5555
"@types/node": "^18.19.9",

src/main/lib/ipcEvents.ts

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@ const { keyboard, Key } = require("@nut-tree-fork/nut-js");
2121
// Global flag to ensure audio warm-up runs only once per app session
2222
let hasRunAudioWarmup = false
2323

24+
// Global flag to track if there's an active call (prevents PhoneIsland reload during calls)
25+
let hasActiveCall = false
26+
27+
// Export function to check active call state from other modules
28+
export function isCallActive(): boolean {
29+
return hasActiveCall
30+
}
31+
2432
function onSyncEmitter<T>(
2533
channel: IPC_EVENTS,
2634
asyncCallback: (...args: any[]) => Promise<T>
@@ -272,9 +280,20 @@ export function registerIpcEvents() {
272280
const account = store.get('account') as Account
273281

274282
setTimeout(() => {
275-
Log.info('Send CHANGE_PREFERRED_DEVICES event with', account.preferredDevices)
283+
// Include flag to indicate if audio warmup should run (only first time)
284+
const shouldRunWarmup = !hasRunAudioWarmup
285+
if (shouldRunWarmup) {
286+
hasRunAudioWarmup = true
287+
}
288+
Log.info('Send CHANGE_PREFERRED_DEVICES event with', {
289+
preferredDevices: account.preferredDevices,
290+
shouldRunWarmup
291+
})
276292
AccountController.instance.updatePreferredDevice(account.preferredDevices)
277-
PhoneIslandController.instance.window.emit(IPC_EVENTS.CHANGE_PREFERRED_DEVICES, account.preferredDevices)
293+
PhoneIslandController.instance.window.emit(IPC_EVENTS.CHANGE_PREFERRED_DEVICES, {
294+
...account.preferredDevices,
295+
shouldRunWarmup
296+
})
278297
}, 250)
279298
})
280299

@@ -362,7 +381,16 @@ export function registerIpcEvents() {
362381
}
363382
})
364383

384+
ipcMain.on(IPC_EVENTS.EMIT_CALL_ACTIVE, (_) => {
385+
if (!hasActiveCall) {
386+
Log.info('Call active (started or answered) - setting hasActiveCall = true')
387+
hasActiveCall = true
388+
}
389+
})
390+
365391
ipcMain.on(IPC_EVENTS.EMIT_CALL_END, (_) => {
392+
Log.info('Call ended - setting hasActiveCall = false')
393+
hasActiveCall = false
366394
try {
367395
NethLinkController.instance.window.emit(IPC_EVENTS.EMIT_CALL_END)
368396
} catch (e) {

src/main/main.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { app, ipcMain, nativeTheme, powerMonitor, protocol, systemPreferences, dialog, shell, globalShortcut } from 'electron'
2-
import { registerIpcEvents } from '@/lib/ipcEvents'
2+
import { registerIpcEvents, isCallActive } from '@/lib/ipcEvents'
33
import { AccountController } from './classes/controllers'
44
import { PhoneIslandController } from './classes/controllers/PhoneIslandController'
55
import { Account, AuthAppData, AvailableThemes } from '@shared/types'
@@ -564,7 +564,14 @@ async function onAppResume() {
564564
if (autoLoginResult) {
565565
NethLinkController.instance.window.getWindow()?.reload()
566566
await delay(500)
567-
PhoneIslandController.instance.window.getWindow()?.reload()
567+
// Don't reload PhoneIsland if there's an active call - this would destroy the call
568+
const activeCall = isCallActive()
569+
if (activeCall) {
570+
Log.info('APP POWER RESUME - Skipping PhoneIsland reload due to active call')
571+
} else {
572+
Log.info('APP POWER RESUME - Reloading PhoneIsland (no active call)')
573+
PhoneIslandController.instance.window.getWindow()?.reload()
574+
}
568575
}
569576
}
570577
isInPowerResume = false

src/renderer/src/hooks/usePhoneIslandEventListeners.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,15 +89,21 @@ export const usePhoneIslandEventListener = () => {
8989
}),
9090

9191
...eventHandler(PHONE_ISLAND_EVENTS["phone-island-call-answer"]),
92-
...eventHandler(PHONE_ISLAND_EVENTS["phone-island-call-answered"]),
92+
...eventHandler(PHONE_ISLAND_EVENTS["phone-island-call-answered"], () => {
93+
// Incoming call answered - mark as active call
94+
window.electron.send(IPC_EVENTS.EMIT_CALL_ACTIVE)
95+
}),
9396

9497
...eventHandler(PHONE_ISLAND_EVENTS["phone-island-call-audio-input-switch"]),
9598
...eventHandler(PHONE_ISLAND_EVENTS["phone-island-call-audio-input-switched"]),
9699
...eventHandler(PHONE_ISLAND_EVENTS["phone-island-call-audio-output-switch"]),
97100
...eventHandler(PHONE_ISLAND_EVENTS["phone-island-call-audio-output-switched"]),
98101

99102
...eventHandler(PHONE_ISLAND_EVENTS["phone-island-call-start"]),
100-
...eventHandler(PHONE_ISLAND_EVENTS["phone-island-call-started"]),
103+
...eventHandler(PHONE_ISLAND_EVENTS["phone-island-call-started"], () => {
104+
// Outgoing call started - mark as active call
105+
window.electron.send(IPC_EVENTS.EMIT_CALL_ACTIVE)
106+
}),
101107
...eventHandler(PHONE_ISLAND_EVENTS["phone-island-call-end"]),
102108
...eventHandler(PHONE_ISLAND_EVENTS["phone-island-call-ended"], () => {
103109
window.electron.send(IPC_EVENTS.EMIT_CALL_END)

src/renderer/src/pages/PhoneIslandPage.tsx

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ export function PhoneIslandPage() {
3232
const isUrlOpening = useRef<boolean>(false)
3333
const urlOpenAttempts = useRef<number>(0)
3434
const urlOpenListenerRegistered = useRef<boolean>(false)
35-
const hasRunWarmup = useRef<boolean>(false)
3635

3736
useEffect(() => {
3837
resize(phoneIsalndSizes)
@@ -75,29 +74,31 @@ export function PhoneIslandPage() {
7574
eventDispatch(PHONE_ISLAND_EVENTS['phone-island-call-end'])
7675
})
7776

78-
window.electron.receive(IPC_EVENTS.CHANGE_PREFERRED_DEVICES, (devices: PreferredDevices) => {
79-
Log.info('Received CHANGE_PREFERRED_DEVICES in PhoneIslandPage:', devices)
77+
window.electron.receive(IPC_EVENTS.CHANGE_PREFERRED_DEVICES, (devices: PreferredDevices & { shouldRunWarmup?: boolean }) => {
78+
const { shouldRunWarmup, audioInput, videoInput, audioOutput } = devices
79+
Log.info('Received CHANGE_PREFERRED_DEVICES in PhoneIslandPage:', { devices, shouldRunWarmup })
8080

8181
// Run audio warm-up first, only once after PhoneIsland is fully initialized
82-
// Only on Windows/macOS where the issue occurs
83-
if (!hasRunWarmup.current) {
84-
hasRunWarmup.current = true
85-
Log.info('Requesting audio warm-up from main process...')
82+
// Main process tracks whether warmup has already run (survives re-renders/reconnections)
83+
// Phone-island also checks for active calls before running warmup
84+
if (shouldRunWarmup) {
85+
Log.info('Requesting audio warm-up from main process (first initialization)...')
8686
setTimeout(() => {
8787
eventDispatch(PHONE_ISLAND_EVENTS['phone-island-init-audio'])
8888
}, 1000)
8989

9090
// Dispatch device changes after warm-up completes (after ~5 seconds)
9191
setTimeout(() => {
92-
eventDispatch(PHONE_ISLAND_EVENTS['phone-island-audio-input-change'], { deviceId: devices.audioInput })
93-
eventDispatch(PHONE_ISLAND_EVENTS['phone-island-video-input-change'], { deviceId: devices.videoInput })
94-
eventDispatch(PHONE_ISLAND_EVENTS['phone-island-audio-output-change'], { deviceId: devices.audioOutput })
92+
eventDispatch(PHONE_ISLAND_EVENTS['phone-island-audio-input-change'], { deviceId: audioInput })
93+
eventDispatch(PHONE_ISLAND_EVENTS['phone-island-video-input-change'], { deviceId: videoInput })
94+
eventDispatch(PHONE_ISLAND_EVENTS['phone-island-audio-output-change'], { deviceId: audioOutput })
9595
}, 5000)
9696
} else {
97-
// If warm-up already done or not needed, dispatch immediately
98-
eventDispatch(PHONE_ISLAND_EVENTS['phone-island-audio-input-change'], { deviceId: devices.audioInput })
99-
eventDispatch(PHONE_ISLAND_EVENTS['phone-island-video-input-change'], { deviceId: devices.videoInput })
100-
eventDispatch(PHONE_ISLAND_EVENTS['phone-island-audio-output-change'], { deviceId: devices.audioOutput })
97+
// If warm-up already done or not needed (reconnection), dispatch device changes immediately
98+
Log.info('Skipping audio warm-up (already done or reconnection), dispatching device changes immediately')
99+
eventDispatch(PHONE_ISLAND_EVENTS['phone-island-audio-input-change'], { deviceId: audioInput })
100+
eventDispatch(PHONE_ISLAND_EVENTS['phone-island-video-input-change'], { deviceId: videoInput })
101+
eventDispatch(PHONE_ISLAND_EVENTS['phone-island-audio-output-change'], { deviceId: audioOutput })
101102
}
102103
})
103104

src/shared/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ export enum IPC_EVENTS {
7575
STOP_DRAG = "STOP_DRAG",
7676
ENABLE_CLICK = "ENABLE_CLICK",
7777
DELETE_ACCOUNT = "DELETE_ACCOUNT",
78+
EMIT_CALL_ACTIVE = "EMIT_CALL_ACTIVE",
7879
EMIT_CALL_END = "EMIT_CALL_END",
7980
EMIT_MAIN_PRESENCE_UPDATE = "EMIT_MAIN_PRESENCE_CHANGE",
8081
EMIT_QUEUE_UPDATE = "EMIT_QUEUE_UPDATE",

0 commit comments

Comments
 (0)