mirror of
https://github.com/Psychotoxical/psysonic.git
synced 2026-07-22 07:15:47 +00:00
2e9618cf54
* fix(audio): promote WASAPI render thread to MMCSS Pro Audio on Windows
Wraps the outermost audio source in a `PriorityBoostSource` that calls
`AvSetMmThreadCharacteristicsW("Pro Audio")` on its first sample. The
cpal output-stream callback runs `Source::next` on the WASAPI render
thread, which is otherwise normal-priority and gets preempted under
WebView2 / DWM / GPU pressure — producing the audible click/stutter
reported in issue #334. No-op on Linux/macOS (PipeWire/rtkit and
CoreAudio promote their audio threads externally).
* fix(build): repair Windows compile after audio split + lib decompose
Two pre-existing build breakers on Windows that surfaced after the
`use super::*;` cleanup (9cc74a7) and the lib-decompose refactor
(cfeec22):
- `audio/device_watcher.rs` lost the `output_enumeration_includes_pinned`
import. Add it cfg-gated to `not(target_os = "linux")` since it's only
called inside the non-Linux pinned-device fallback path.
- `lib_commands/sync/tray.rs::is_tiling_wm()` is `#[cfg(target_os = "linux")]`,
but its Tauri command wrapper `is_tiling_wm_cmd()` is unconditional.
Add a `#[cfg(not(target_os = "linux"))]` stub returning `false`.
No behavior change on Linux. Restores `cargo build` on Windows + macOS.
* perf(ui): pause cosmetic animations when window loses OS focus
Companion to the WASAPI MMCSS fix in this branch — issue #334
reported audible audio stutter on low-end laptops, partly traced
to WebView2 still compositing CSS animations + waveform canvas at
full rate while the user has alt-tabbed into another app.
Existing `data-app-hidden` / `data-psy-native-hidden` flags pause
animations only when the window is fully hidden (minimized or
behind a tray). When the window is visible-but-unfocused — the
common "music in the background while I work" case — every infinite
keyframe + 60fps rAF loop keeps running.
Add a parallel `data-app-blurred` flag driven by `window.focus`/
`window.blur`, plus matching `__psyBlurred` on the global window
object for imperative checks. The CSS rule that pauses every
`animation-play-state` on hidden gets a third selector for blurred.
WaveformSeek's two 60fps rAF loops (animated styles + settings demo)
extend their existing `document.hidden || __psyHidden` short-circuit
to also include the new blurred flag, falling back to the same
400ms polling path that already exists for hidden.
Verified visually on the dashboard: alt-tab → `<html
data-app-blurred="true">`, mesh blobs in the fullscreen player +
marquee + waveform 60fps loop all pause. Click back into the
window → blob/marquee/waveform resume immediately.
Cross-platform: focus/blur events fire reliably on all targets, so
the optimization applies to Windows, Linux (incl. WebKitGTK with
software compositing where the savings are largest), and macOS.
* chore: remove stale app-icon.png from repo root
* perf(ui): add 'Reduce animations' toggle that caps animated seekbar styles to 30 fps
Off by default. When on, animated seekbar styles (pulsewave, particletrail,
liquidfill, retrotape) skip every other rAF and advance the animation timer by
a doubled delta, so wave speed is unchanged while draws are halved. Aimed at
low-end Windows GPUs where the 60 fps shadow-blur loop drives ~40 % WebView2
GPU usage even when focused.
Toggle lives directly under the seekbar style picker in Settings → Appearance.
i18n in all 8 supported languages.
92 lines
3.2 KiB
TOML
92 lines
3.2 KiB
TOML
[package]
|
||
name = "psysonic"
|
||
version = "1.45.0-dev"
|
||
description = "Psysonic Desktop Music Player"
|
||
authors = []
|
||
license = ""
|
||
repository = ""
|
||
default-run = "psysonic"
|
||
edition = "2021"
|
||
rust-version = "1.89"
|
||
|
||
[lib]
|
||
name = "psysonic_lib"
|
||
crate-type = ["staticlib", "cdylib", "rlib"]
|
||
|
||
[[bin]]
|
||
name = "psysonic"
|
||
path = "src/main.rs"
|
||
|
||
[build-dependencies]
|
||
tauri-build = { version = "2", features = [] }
|
||
|
||
[dependencies]
|
||
tauri = { version = "2", features = ["tray-icon", "image-png"] }
|
||
tauri-plugin-single-instance = "2"
|
||
tauri-plugin-shell = "2"
|
||
tauri-plugin-global-shortcut = "2"
|
||
tauri-plugin-store = "2"
|
||
tauri-plugin-dialog = "2"
|
||
tauri-plugin-fs = "2"
|
||
serde = { version = "1", features = ["derive"] }
|
||
serde_json = "1"
|
||
rodio = { version = "0.19", default-features = false, features = ["symphonia-all"] }
|
||
symphonia = { version = "0.5", default-features = false, features = ["flac", "mp3", "pcm", "aac", "alac", "isomp4", "vorbis", "ogg", "wav", "adpcm"] }
|
||
reqwest = { version = "0.12", default-features = false, features = ["stream", "json", "multipart", "rustls-tls", "rustls-tls-native-roots", "blocking"] }
|
||
futures-util = "0.3"
|
||
md5 = "0.7"
|
||
tokio = { version = "1", features = ["rt", "time", "sync"] }
|
||
biquad = "0.4"
|
||
ringbuf = "0.3"
|
||
tauri-plugin-window-state = "2.4.1"
|
||
tauri-plugin-process = "2"
|
||
tauri-plugin-updater = "2"
|
||
souvlaki = { version = "0.8", default-features = false, features = ["use_zbus"] }
|
||
discord-rich-presence = "0.2"
|
||
url = "2"
|
||
thread-priority = "1"
|
||
lofty = "0.22"
|
||
sysinfo = { version = "0.33", default-features = false, features = ["disk"] }
|
||
id3 = "1.16.4"
|
||
symphonia-adapter-libopus = "0.2.7"
|
||
rusqlite = { version = "0.37", features = ["bundled"] }
|
||
ebur128 = "0.1"
|
||
|
||
[target.'cfg(unix)'.dependencies]
|
||
libc = "0.2"
|
||
|
||
[target.'cfg(target_os = "linux")'.dependencies]
|
||
zbus = { version = "5.9", default-features = false, features = ["blocking-api"] }
|
||
# Match wry/tauri’s WebKitGTK stack — used only to turn off kinetic wheel scrolling.
|
||
webkit2gtk = { version = "2.0", default-features = false, features = ["v2_40"] }
|
||
|
||
[target.'cfg(windows)'.dependencies]
|
||
windows = { version = "0.58", features = [
|
||
"Win32_Foundation",
|
||
"Win32_Graphics",
|
||
"Win32_Graphics_Gdi",
|
||
"Win32_System_Com",
|
||
"Win32_System_Threading",
|
||
"Win32_UI_Controls",
|
||
"Win32_UI_Shell",
|
||
"Win32_UI_WindowsAndMessaging",
|
||
] }
|
||
|
||
[patch.crates-io]
|
||
# Local patch for Symphonia's isomp4 demuxer:
|
||
# - Fixes descriptor.unwrap() panic on malformed esds atoms (older iTunes M4A)
|
||
# - Tolerates SL predefined=0x01 (null) used by some older iTunes-purchased files
|
||
# - Gracefully skips malformed trak atoms (e.g. MJPEG cover-art streams) instead
|
||
# of failing the entire probe
|
||
symphonia-format-isomp4 = { path = "patches/symphonia-format-isomp4" }
|
||
|
||
# Local patch for cpal's CoreAudio backend on macOS:
|
||
# - Forces IOType::DefaultOutput for all output streams so that macOS never
|
||
# triggers the TCC microphone-permission prompt. Upstream cpal uses
|
||
# IOType::HalOutput when the user pins a non-default device, which routes
|
||
# through AUHAL — that component is flagged as input-capable and triggers
|
||
# the mic consent dialog on first launch / after each update.
|
||
# - Tradeoff: output-device selection is a no-op on macOS (stream follows
|
||
# system default). Surfaced in the Settings UI.
|
||
cpal = { path = "patches/cpal-0.15.3" }
|