|
1 | 1 | import type { Percentage } from '../../types'; |
2 | 2 |
|
3 | | -const MINIMUM_VOLUME_PERCENTAGE = 0 as Percentage; |
4 | | -const MAXIMUM_VOLUME_PERCENTAGE = 100 as Percentage; |
5 | | -const VOLUME_STEP = 10 as Percentage; |
| 3 | +import { rendererLogError } from '../core/logger'; |
| 4 | +import { volumePercentageToLevel } from '../ui/volume'; |
| 5 | + |
| 6 | +// Cache audio instance to avoid re-creating elements on every notification. |
| 7 | +let cachedAudio: HTMLAudioElement | null = null; |
6 | 8 |
|
7 | 9 | /** |
8 | | - * Play the user's configured notification sound at the given volume. |
9 | | - * |
10 | | - * Resolves the notification sound file path from the main process, then |
11 | | - * plays it via the Web Audio API. |
| 10 | + * Plays the notification sound at the specified volume. |
| 11 | + * The audio element is lazily created and cached to avoid re-creating it on every call. |
| 12 | + * The cache is cleared if playback fails so the next call can retry. |
12 | 13 | * |
13 | | - * @param volume - The playback volume as a percentage (0–100). |
| 14 | + * @param volume - The volume level to play the sound at, as a percentage (`0`–`100`). |
14 | 15 | */ |
15 | 16 | export async function raiseSoundNotification(volume: Percentage) { |
16 | | - const path = await window.gitify.notificationSoundPath(); |
17 | | - |
18 | | - const audio = new Audio(path); |
19 | | - audio.volume = volumePercentageToLevel(volume); |
20 | | - audio.play(); |
21 | | -} |
22 | | - |
23 | | -/** |
24 | | - * Convert volume percentage (0-100) to level (0.0-1.0) |
25 | | - */ |
26 | | -export function volumePercentageToLevel(percentage: Percentage): number { |
27 | | - return percentage / 100; |
28 | | -} |
| 17 | + if (!cachedAudio) { |
| 18 | + const path = await window.gitify.notificationSoundPath(); |
29 | 19 |
|
30 | | -/** |
31 | | - * Returns true if can decrease volume percentage further |
32 | | - */ |
33 | | -export function canDecreaseVolume(volumePercentage: Percentage) { |
34 | | - return volumePercentage - VOLUME_STEP >= MINIMUM_VOLUME_PERCENTAGE; |
35 | | -} |
36 | | - |
37 | | -/** |
38 | | - * Returns true if can increase volume percentage further |
39 | | - */ |
40 | | -export function canIncreaseVolume(volumePercentage: Percentage) { |
41 | | - return volumePercentage + VOLUME_STEP <= MAXIMUM_VOLUME_PERCENTAGE; |
42 | | -} |
43 | | - |
44 | | -/** |
45 | | - * Decrease the volume by one step, clamped to the minimum. |
46 | | - * |
47 | | - * @param volume - The current volume percentage. |
48 | | - * @returns The new volume percentage after decrement, or the minimum if already at the floor. |
49 | | - */ |
50 | | -export function decreaseVolume(volume: Percentage) { |
51 | | - if (canDecreaseVolume(volume)) { |
52 | | - return volume - VOLUME_STEP; |
| 20 | + cachedAudio = new Audio(path); |
53 | 21 | } |
54 | 22 |
|
55 | | - return MINIMUM_VOLUME_PERCENTAGE; |
56 | | -} |
| 23 | + const audio = cachedAudio; |
57 | 24 |
|
58 | | -/** |
59 | | - * Increase the volume by one step, clamped to the maximum. |
60 | | - * |
61 | | - * @param volume - The current volume percentage. |
62 | | - * @returns The new volume percentage after increment, or the maximum if already at the ceiling. |
63 | | - */ |
64 | | -export function increaseVolume(volume: Percentage) { |
65 | | - if (canIncreaseVolume(volume)) { |
66 | | - return volume + VOLUME_STEP; |
67 | | - } |
| 25 | + audio.volume = volumePercentageToLevel(volume); |
68 | 26 |
|
69 | | - return MAXIMUM_VOLUME_PERCENTAGE; |
| 27 | + try { |
| 28 | + await audio.play(); |
| 29 | + } catch (err) { |
| 30 | + rendererLogError('audio', 'Failed to play notification sound:', err); |
| 31 | + cachedAudio = null; |
| 32 | + } |
70 | 33 | } |
0 commit comments