commit 531c69006f10e931684ce0b76234d2b1c60a6d78 from: ale date: Fri Jul 17 04:10:11 2026 UTC Agrega IntelliJ IDEA Ultimate, amplía clock.allowed-rates de PipeWire; saca nokkvi - jetbrains.idea directo de nixpkgs (no Toolbox). allowUnfree ya estaba en true a nivel sistema (Nvidia/Steam). - default.clock.allowed-rates poblado en modules/desktop.nix -- sin esto PipeWire corre con clock fijo en 48kHz, forzando resample silencioso para streams "bit-perfect" que piden la tasa nativa de archivos hi-res. - nokkvi (cliente de Navidrome) se agregó y se sacó el mismo día -- ver NOTES.md para el detalle de empaquetado, queda como referencia. - En el camino se encontró un bug real en Noctalia (sound_player.cpp: onDrained() nunca desconecta el stream de sonido de UI, queda pegado al grafo de PipeWire indefinidamente) -- se armó un patch, se verificó en vivo, y se revirtió del repo porque no era la causa del audio cortado original (esa terminó siendo una función de hi-res streaming propia de psysonic, desactivada del lado de la app). Diagnóstico completo en NOTES.md: "IntelliJ IDEA Ultimate, nokkvi, y audio cortado en psysonic con álbumes hi-res". commit - 090f697ae5d2d9f38015ae07b3401d53ee9d12f5 commit + 531c69006f10e931684ce0b76234d2b1c60a6d78 blob - 5b6eafda2c00fbfda48867c4689ef93a6a7096c2 blob + 6215c2ecd33a96d723b26655151440d442af44ce --- NOTES.md +++ NOTES.md @@ -1223,6 +1223,107 @@ sistema que declarar. es para tenerlo instalado de forma permanente sin depender de acordarse del `nix-shell` cada vez. +## IntelliJ IDEA Ultimate, nokkvi, y audio cortado en psysonic con álbumes hi-res (2026-07-16/17) + +**IntelliJ IDEA Ultimate.** `jetbrains.idea` directo de nixpkgs en +`home.packages` (`home/ale/home.nix`), no JetBrains Toolbox — Toolbox baja +binarios fuera del store y se autoactualiza por su cuenta, no encaja con el +modelo declarativo de este repo (mismo motivo por el que LibrePods se +compila de fuente en vez de depender de un AppImage). `allowUnfree` ya +estaba en `true` a nivel sistema (`hosts/ale/configuration.nix`, por +Nvidia/Steam), `home-manager.useGlobalPkgs = true` lo hereda. Requiere +login/licencia JetBrains la primera vez que se abre. + +**nokkvi** (cliente nativo de Navidrome, Rust/Iced, +github.com/f-o-o-g-s/nokkvi) — coexiste con `psysonic`, no lo reemplaza +(decisión explícita del usuario). A diferencia de LibrePods, este proyecto +sí tiene releases oficiales de Linux con binario prebuilt, pero su +`Cargo.toml` pinea `iced` a un commit de la rama `master` upstream (no +crates.io) — compilarlo con `buildRustPackage` hubiera dependido de un +`outputHashes` frágil, roto en cada bump de esa fork. Se empaquetó en +`pkgs/nokkvi.nix` bajando el binario oficial del release (`fetchurl` + +`autoPatchelfHook`), verificando el `sha256` del tarball contra el +`.sha256` que el propio proyecto publica junto a cada release. Runtime deps +confirmadas con `readelf -d` real sobre el binario (fontconfig, freetype, +alsa-lib, pipewire, y `stdenv.cc.cc.lib` para `libgcc_s.so.1`, que no la +trae ningún paquete de arriba); `vulkan-loader`/`libxkbcommon`/`wayland` +como `runtimeDependencies` porque iced/wgpu (mismo stack que LibrePods) los +resuelven vía `dlopen` en runtime, no aparecen en `readelf -d`. Build +verificado en vivo (`nix build` + `nokkvi --version`). + +**Removido el mismo día** (decisión del usuario, sin razón registrada en +esta sesión) — `pkgs/nokkvi.nix` borrado y la línea sacada de +`home.packages`. Queda el detalle de empaquetado de arriba como referencia +real y ya verificada por si se reinstala más adelante (el patch de la +release/hash/runtime deps sigue siendo válido salvo que haya salido una +versión nueva). + +**Audio cortado en psysonic con álbumes hi-res (FLAC 24-bit/192kHz).** +Reporte del usuario: 2 álbumes nuevos (Electric Light Orchestra "Discovery" +y otro) sonaban cortados en psysonic, pero bien con otros clientes de +Navidrome y bien con el resto de la biblioteca en el propio psysonic. +Diagnóstico en varias rondas, con dos hallazgos reales confirmados en el +camino y una causa final que terminó siendo otra: + +- **Hallazgo real #1 -- `default.clock.allowed-rates` de PipeWire vacío.** + `pw-metadata -n settings` mostraba `clock.allowed-rates=[48000]` (default + de PipeWire sin configurar: una sola tasa fija). Los logs de psysonic + (`psysonic --logs --tail 300`) mostraban `audio stream opened at 192000 + Hz (exact)` para los álbumes hi-res -- psysonic tiene un modo + "bit-perfect" que intenta matchear la tasa nativa del archivo. Con el + clock fijo, PipeWire forzaba un resample 192kHz->48kHz por atrás. Se + agregó `services.pipewire.extraConfig.pipewire."92-clock-rates"` en + `modules/desktop.nix` con `default.clock.allowed-rates = [ 44100 48000 + 88200 96000 176400 192000 ]` -- **este cambio se mantuvo** porque sigue + siendo correcto para el DAC hi-res real de la máquina (HiBy FC4, USB, + confirmado con `cat /proc/asound/card1/stream0` que soporta hasta + 768kHz), más allá de que no resultó ser la causa completa del corte. +- **Hallazgo real #2 -- bug de Noctalia, stream de sonido de UI que nunca + se desconecta.** Con `wpctl status` se vio un stream activo permanente + llamado "Noctalia" (`node.name = noctalia-sound`, confirmado con + `pw-dump`) compitiendo por el mismo sink (HiBy FC4) incluso horas después + de haber sonado un solo efecto de UI (notificación, OSD de volumen). + Revisando el código fuente real del input (`src/pipewire/ + sound_player.cpp`, `SoundPlayer::onDrained()`): marca el stream como + `finished` pero nunca llama a `pw_stream_disconnect()` -- el + `pw_stream_destroy()` recién corre en la PRÓXIMA vez que suena otro + efecto (`removeFinished()`, invocado al principio de `play()`). Mientras + ese stream siguiera conectado, PipeWire no cambiaba el clock del grafo + para servir a otro cliente. Se armó un patch real + (`pkgs/noctalia-sound-disconnect.patch`, con `pw_stream_disconnect()` + agregado a `onDrained()`) y un override de `programs.noctalia.package` + duplicado en **dos** módulos independientes (el de NixOS en + `modules/desktop.nix` y el de home-manager en `home/ale/home.nix`, cada + uno con su propia opción `programs.noctalia.package` -- el de + home-manager instala en `/etc/profiles/per-user/ale/bin`, que gana en + `$PATH` sobre `/run/current-system/sw/bin` del módulo de NixOS, así que + hacía falta el override en los dos lados o el binario sin parchear + ganaba igual). Patch compilado y verificado en vivo: el stream "Noctalia" + efectivamente dejó de quedar colgado en `wpctl status` tras aplicarlo. + **Este bug es real y sigue sin arreglar upstream** (no se reportó + todavía), pero el patch/override se **revirtió** de este repo (borrados + `pkgs/noctalia-sound-disconnect.patch` y `pkgs/noctalia-patched.nix`, + sacados los dos overrides) porque no era la causa del audio cortado -- + ver siguiente punto. Si el sonido de UI colgado vuelve a molestar en el + futuro, el patch armado acá (buscar en el historial de git de este + archivo/repo, commit previo a la reversión) es un punto de partida real + y ya compilado una vez. +- **Causa real.** Con los dos hallazgos de arriba aplicados, el corte + seguía. Revisando `psysonic --logs` en el momento exacto de la + reproducción aparecieron `[hi-res-blend] outgoing track not cached for + blend reopen` y `[audio] ranged dl error (attempt 1/3): error decoding + response body -- reconnecting`, ambos correlacionados con la apertura de + streams a 192kHz. Se descartó que fuera ancho de banda/wifi (LAN directa + por Tailscale a 13ms, sin relay DERP -- `tailscale ping` confirmó + conexión directa; señal wifi fuerte, 79%/-41dBm/1170Mbit; `ip -s link` + con drop rate insignificante, ~0.08%). La causa terminó siendo una + función propia de psysonic (streaming/blend "bit-perfect" para hi-res) -- + el usuario la desactivó en la configuración de la app y el corte + desapareció por completo. No se llegó a encontrar el toggle exacto desde + esta sesión (el usuario lo hizo directo en la UI de psysonic) -- queda + pendiente documentar dónde vive esa opción si hace falta tocarla de nuevo + vía config declarativa. + ## Referencias usadas - https://docs.noctalia.dev/v5/getting-started/nixos/ blob - e09a539b92e3e86367d47f037fedb121eb9068e5 blob + 742e9fd1907f1615b301e161bec1ff07b7bc663c --- README.md +++ README.md @@ -40,6 +40,17 @@ Flake para migrar esta PC de FreeBSD a NixOS con Hyprl simple (sin módulo `programs.weechat` en home-manager); config de plugins/servers se hace desde dentro del propio WeeChat, no versionada en este repo. Ver `NOTES.md` (2026-07-16). +- **IntelliJ IDEA Ultimate** (`jetbrains.idea`, directo de nixpkgs en + `home/ale/home.nix`) — no JetBrains Toolbox, no encaja con el modelo + declarativo del repo. Requiere login/licencia JetBrains la primera vez. +- **PipeWire con `default.clock.allowed-rates` poblado** + (`modules/desktop.nix`) — sin esto el clock del grafo queda fijo en + 48kHz sin margen (default de PipeWire), y clientes "bit-perfect" que + piden la tasa nativa de archivos hi-res (ej. FLAC 24-bit/192kHz) fuerzan + un resample silencioso. Ver "IntelliJ IDEA Ultimate, nokkvi, y audio + cortado en psysonic con álbumes hi-res" en `NOTES.md` (2026-07-16/17) + para el diagnóstico completo (incluye un bug real de Noctalia encontrado + en el camino, con patch armado y después revertido por no ser la causa). ## Antes del primer `nixos-rebuild switch` blob - 8232a808f93cf6c90731455d34bdcf407ab9d539 blob + cd86ff55ce31bb33195379cf021e86a240e85066 --- home/ale/home.nix +++ home/ale/home.nix @@ -249,7 +249,6 @@ home.packages = with pkgs; [ yubikey-manager (callPackage ../../pkgs/librepods.nix { }) - (callPackage ../../pkgs/nokkvi.nix { }) gitstatus # da el binario gitstatusd que necesita Powerlevel10k (ver programs.zsh) meslo-lgs-nf # Nerd Font que recomienda p10k para sus glifos/iconos pfetch # info del sistema al abrir terminal (ver programs.zsh.initContent) blob - a12afb6e1cdcd7ae41da25dda05cac789a4c24ea blob + 1d1aa26c535bfcb86ff8458bc50774e6cfbf7b6c --- modules/desktop.nix +++ modules/desktop.nix @@ -47,6 +47,25 @@ wireplumber.enable = true; }; + # Sin esto, el clock del grafo de PipeWire queda fijo en 48000 Hz sin + # margen (default de PipeWire: default.clock.allowed-rates vacío = una + # sola tasa) -- confirmado en vivo con `pw-metadata -n settings`. Con esto + # poblado, el grafo puede cambiar de tasa para matchear la nativa de un + # stream "bit-perfect" (ej. psysonic con álbumes hi-res, "audio stream + # opened at 192000 Hz (exact)" en sus logs) en vez de forzar resample. + # + # NO fue la causa del audio cortado que motivó esto -- esa fue una función + # de hi-res streaming propia de psysonic (bug/comportamiento de esa app, + # se resolvió desactivándola ahí). Este cambio queda solo porque sigue + # siendo una mejora real y correcta para el DAC hi-res (HiBy FC4) más allá + # de ese diagnóstico puntual. + services.pipewire.extraConfig.pipewire."92-clock-rates" = { + "context.properties" = { + "default.clock.rate" = 48000; + "default.clock.allowed-rates" = [ 44100 48000 88200 96000 176400 192000 ]; + }; + }; + # AVRCP "dummy player" -- necesario para que los controles de reproducción # (play/pause/skip) de los AirPods (vía LibrePods, ver home/ale/home.nix) # funcionen con pipewire/wireplumber. Documentado en linux/README.md de blob - ba257f7688ee0efb46a4ad98c57a9a6f9fd25055 (mode 644) blob + /dev/null --- pkgs/nokkvi.nix +++ /dev/null @@ -1,73 +0,0 @@ -# Nokkvi (cliente de música nativo para Navidrome, github.com/f-o-o-g-s/nokkvi). -# A diferencia de LibrePods, acá SÍ hay releases oficiales de Linux con -# binario prebuilt -- pero el Cargo.toml del proyecto pinea `iced` a un -# commit de la rama `master` upstream (no crates.io), lo que haría que -# compilarlo de fuente con buildRustPackage dependa de un outputHashes -# frágil que se puede romper con cada bump de esa fork. Por eso acá se usa -# el binario oficial del release + autoPatchelfHook, en vez de compilar -# (decisión tomada con el usuario, ver conversación -- prefirió esto a -# nix-ld genérico + descarga manual sin declarar). -# -# El hash del tarball es el mismo `sha256` que publica el proyecto junto al -# release (ver .sha256 en la misma release de GitHub), así que además -# de fijar la build es una verificación de integridad contra lo que firma -# el autor. Para actualizar: cambiar `version` y `hash` (bajar el .sha256 -# del nuevo release y convertirlo con -# `nix hash convert --hash-algo sha256 --to sri `). -{ lib -, stdenv -, fetchurl -, autoPatchelfHook -, fontconfig -, freetype -, alsa-lib -, pipewire -, vulkan-loader -, libxkbcommon -, wayland -}: - -stdenv.mkDerivation rec { - pname = "nokkvi"; - version = "0.16.0"; - - src = fetchurl { - url = "https://github.com/f-o-o-g-s/nokkvi/releases/download/v${version}/nokkvi-v${version}-x86_64-unknown-linux-gnu.tar.gz"; - hash = "sha256-SmBVYD2T6beJLGPoBeTktborhXP4jBaZSIdTQfo9Szs="; - }; - - nativeBuildInputs = [ autoPatchelfHook ]; - - # Dependencias directas del binario (confirmado con `readelf -d`): - # libfontconfig, libfreetype, libasound (ALSA), libpipewire-0.3, libgcc_s - # (stdenv.cc.cc.lib -- el runtime de gcc, no viene con ningún paquete de - # arriba, autoPatchelfHook no la encuentra si no se agrega a mano). - buildInputs = [ fontconfig freetype alsa-lib pipewire stdenv.cc.cc.lib ]; - - # iced/wgpu (mismo stack que LibrePods) resuelven Vulkan/Wayland en - # runtime vía dlopen, no aparecen en `readelf -d` -- autoPatchelfHook - # necesita que estén disponibles igual para que el dlopen no falle. - runtimeDependencies = [ vulkan-loader libxkbcommon wayland ]; - - dontConfigure = true; - dontBuild = true; - - installPhase = '' - runHook preInstall - - install -Dm755 nokkvi $out/bin/nokkvi - install -Dm644 assets/org.nokkvi.nokkvi.desktop $out/share/applications/org.nokkvi.nokkvi.desktop - install -Dm644 assets/org.nokkvi.nokkvi.svg $out/share/icons/hicolor/scalable/apps/org.nokkvi.nokkvi.svg - install -Dm644 assets/org.nokkvi.nokkvi.png $out/share/icons/hicolor/512x512/apps/org.nokkvi.nokkvi.png - - runHook postInstall - ''; - - meta = with lib; { - description = "Native Navidrome music client (Rust/Iced) with PipeWire audio, gapless playback and GPU visualizers"; - homepage = "https://github.com/f-o-o-g-s/nokkvi"; - license = licenses.gpl3Only; # confirmado en Cargo.toml: "GPL-3.0-only" - platforms = platforms.linux; - mainProgram = "nokkvi"; - }; -}