hifimate 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (207) hide show
  1. hifimate-0.1.0/.gitignore +15 -0
  2. hifimate-0.1.0/INSTALL.md +518 -0
  3. hifimate-0.1.0/LICENSE +21 -0
  4. hifimate-0.1.0/NOTICE.md +20 -0
  5. hifimate-0.1.0/PKG-INFO +282 -0
  6. hifimate-0.1.0/README.md +258 -0
  7. hifimate-0.1.0/bin/hifimate-airplay-net +5 -0
  8. hifimate-0.1.0/bin/hifimate-bluetooth +5 -0
  9. hifimate-0.1.0/bin/hifimate-ctrl +5 -0
  10. hifimate-0.1.0/bin/hifimate-output +5 -0
  11. hifimate-0.1.0/bin/hifimate-receiver-hook +5 -0
  12. hifimate-0.1.0/bin/hifimate-rt +5 -0
  13. hifimate-0.1.0/bin/hifimate-runner +6 -0
  14. hifimate-0.1.0/bin/hifimate-spectrum +5 -0
  15. hifimate-0.1.0/config/hifimate.conf +16 -0
  16. hifimate-0.1.0/config/host-stack/camilladsp.yml +21 -0
  17. hifimate-0.1.0/config/host-stack/mpd.conf +8 -0
  18. hifimate-0.1.0/config/host-stack/music-mpd.conf +8 -0
  19. hifimate-0.1.0/config/host-stack/pipewire/client.conf.d/52-hifimate-realtime.conf +17 -0
  20. hifimate-0.1.0/config/host-stack/pipewire/pipewire-pulse.conf.d/50-hifimate-inputs.conf +3 -0
  21. hifimate-0.1.0/config/host-stack/pipewire/pipewire-pulse.conf.d/52-hifimate-realtime.conf +17 -0
  22. hifimate-0.1.0/config/host-stack/pipewire/pipewire.conf.d/50-hifimate-inputs.conf +48 -0
  23. hifimate-0.1.0/config/host-stack/pipewire/pipewire.conf.d/52-hifimate-realtime.conf +17 -0
  24. hifimate-0.1.0/config/host-stack/shairport-sync.conf +6 -0
  25. hifimate-0.1.0/config/host-stack/spectrum.json +11 -0
  26. hifimate-0.1.0/config/host-stack/upmpdcli.conf +9 -0
  27. hifimate-0.1.0/config/host-stack/wireplumber/wireplumber.conf.d/51-hifimate.conf +43 -0
  28. hifimate-0.1.0/config/host-stack/wireplumber/wireplumber.conf.d/52-hifimate-realtime.conf +18 -0
  29. hifimate-0.1.0/config/host-stack-manifest.json +183 -0
  30. hifimate-0.1.0/docs/ARCHITECTURE.md +468 -0
  31. hifimate-0.1.0/docs/SPECTRUM.md +48 -0
  32. hifimate-0.1.0/gui/ctrl.css +330 -0
  33. hifimate-0.1.0/gui/ctrl.html +109 -0
  34. hifimate-0.1.0/gui/ctrl.js +453 -0
  35. hifimate-0.1.0/gui/eq.css +155 -0
  36. hifimate-0.1.0/gui/eq.html +82 -0
  37. hifimate-0.1.0/gui/eq.js +532 -0
  38. hifimate-0.1.0/gui/nowplaying.css +36 -0
  39. hifimate-0.1.0/gui/nowplaying.js +155 -0
  40. hifimate-0.1.0/gui/roomfit-worklet.js +9 -0
  41. hifimate-0.1.0/gui/roomfit.css +97 -0
  42. hifimate-0.1.0/gui/roomfit.html +52 -0
  43. hifimate-0.1.0/gui/roomfit.js +328 -0
  44. hifimate-0.1.0/gui/settings.html +82 -0
  45. hifimate-0.1.0/gui/settings.js +148 -0
  46. hifimate-0.1.0/gui/spectrum-overlay.css +158 -0
  47. hifimate-0.1.0/gui/spectrum-overlay.js +919 -0
  48. hifimate-0.1.0/gui/spectrum-tap.js +25 -0
  49. hifimate-0.1.0/hifimate/__init__.py +13 -0
  50. hifimate-0.1.0/hifimate/airplay.py +144 -0
  51. hifimate-0.1.0/hifimate/airplay_net.py +123 -0
  52. hifimate-0.1.0/hifimate/bluetooth.py +122 -0
  53. hifimate-0.1.0/hifimate/bluetooth_alias.py +240 -0
  54. hifimate-0.1.0/hifimate/bluetooth_pair.py +208 -0
  55. hifimate-0.1.0/hifimate/cli.py +607 -0
  56. hifimate-0.1.0/hifimate/core.py +321 -0
  57. hifimate-0.1.0/hifimate/ctrl.py +716 -0
  58. hifimate-0.1.0/hifimate/ctrl_auth.py +149 -0
  59. hifimate-0.1.0/hifimate/ctrl_state.py +364 -0
  60. hifimate-0.1.0/hifimate/daemon.py +30 -0
  61. hifimate-0.1.0/hifimate/dsp_model.py +106 -0
  62. hifimate-0.1.0/hifimate/eq.py +286 -0
  63. hifimate-0.1.0/hifimate/format_cli.py +15 -0
  64. hifimate-0.1.0/hifimate/format_daemon.py +250 -0
  65. hifimate-0.1.0/hifimate/formats.py +398 -0
  66. hifimate-0.1.0/hifimate/identity.py +74 -0
  67. hifimate-0.1.0/hifimate/lane_state.py +28 -0
  68. hifimate-0.1.0/hifimate/lyrics.py +316 -0
  69. hifimate-0.1.0/hifimate/ma_api.py +119 -0
  70. hifimate-0.1.0/hifimate/mics/iphone-15-pro-max.json +500 -0
  71. hifimate-0.1.0/hifimate/mics/iphone-16-pro.json +522 -0
  72. hifimate-0.1.0/hifimate/mics/iphone-17-pro.json +524 -0
  73. hifimate-0.1.0/hifimate/mics/iphone-18-pro.json +488 -0
  74. hifimate-0.1.0/hifimate/mpd.py +108 -0
  75. hifimate-0.1.0/hifimate/nowplaying.py +286 -0
  76. hifimate-0.1.0/hifimate/output_devices.py +438 -0
  77. hifimate-0.1.0/hifimate/pw_events.py +55 -0
  78. hifimate-0.1.0/hifimate/realtime.py +72 -0
  79. hifimate-0.1.0/hifimate/receiver_events.py +200 -0
  80. hifimate-0.1.0/hifimate/receiver_hook.py +17 -0
  81. hifimate-0.1.0/hifimate/remote_pause.py +165 -0
  82. hifimate-0.1.0/hifimate/room_eq.py +92 -0
  83. hifimate-0.1.0/hifimate/roomfit.py +606 -0
  84. hifimate-0.1.0/hifimate/runtime_paths.py +58 -0
  85. hifimate-0.1.0/hifimate/settings.py +154 -0
  86. hifimate-0.1.0/hifimate/spectrum.py +608 -0
  87. hifimate-0.1.0/hifimate/spectrum_proxy.py +176 -0
  88. hifimate-0.1.0/hifimate/system.py +319 -0
  89. hifimate-0.1.0/hifimate/tls.py +131 -0
  90. hifimate-0.1.0/hifimate/user_filters.py +130 -0
  91. hifimate-0.1.0/music-assistant/.env.example +40 -0
  92. hifimate-0.1.0/music-assistant/README.md +158 -0
  93. hifimate-0.1.0/music-assistant/compose.yml +243 -0
  94. hifimate-0.1.0/music-assistant/custom-loader-run.sh +46 -0
  95. hifimate-0.1.0/music-assistant/hifimate_ctrl_token.py +91 -0
  96. hifimate-0.1.0/music-assistant/nginx-entrypoint.sh +32 -0
  97. hifimate-0.1.0/music-assistant/nginx.conf +92 -0
  98. hifimate-0.1.0/music-assistant/providers/bilibili/__init__.py +594 -0
  99. hifimate-0.1.0/music-assistant/providers/bilibili/bili_client.py +664 -0
  100. hifimate-0.1.0/music-assistant/providers/bilibili/constants.py +41 -0
  101. hifimate-0.1.0/music-assistant/providers/bilibili/icon.svg +1 -0
  102. hifimate-0.1.0/music-assistant/providers/bilibili/icon_monochrome.svg +1 -0
  103. hifimate-0.1.0/music-assistant/providers/bilibili/manifest.json +19 -0
  104. hifimate-0.1.0/music-assistant/providers/bilibili/parsers.py +541 -0
  105. hifimate-0.1.0/music-assistant/providers/bilibili/setup_flow.py +145 -0
  106. hifimate-0.1.0/music-assistant/providers/bilibili/strings.json +49 -0
  107. hifimate-0.1.0/music-assistant/providers/bilibili.md +89 -0
  108. hifimate-0.1.0/music-assistant/providers/migu/__init__.py +714 -0
  109. hifimate-0.1.0/music-assistant/providers/migu/constants.py +53 -0
  110. hifimate-0.1.0/music-assistant/providers/migu/icon.svg +1 -0
  111. hifimate-0.1.0/music-assistant/providers/migu/icon_monochrome.svg +1 -0
  112. hifimate-0.1.0/music-assistant/providers/migu/manifest.json +13 -0
  113. hifimate-0.1.0/music-assistant/providers/migu/migu_client.py +364 -0
  114. hifimate-0.1.0/music-assistant/providers/migu/parsers.py +744 -0
  115. hifimate-0.1.0/music-assistant/providers/migu/setup_flow.py +208 -0
  116. hifimate-0.1.0/music-assistant/providers/migu/strings.json +66 -0
  117. hifimate-0.1.0/music-assistant/providers/migu.md +84 -0
  118. hifimate-0.1.0/packaging/RELEASING.md +28 -0
  119. hifimate-0.1.0/packaging/check_wheel.py +52 -0
  120. hifimate-0.1.0/packaging/install.sh +73 -0
  121. hifimate-0.1.0/pyproject.toml +67 -0
  122. hifimate-0.1.0/scripts/bluetooth_speaker.py +193 -0
  123. hifimate-0.1.0/scripts/camilladsp_release.py +128 -0
  124. hifimate-0.1.0/scripts/check-format-stack.py +257 -0
  125. hifimate-0.1.0/scripts/configure_ma_players.py +200 -0
  126. hifimate-0.1.0/scripts/enable_ma_visualizer.py +105 -0
  127. hifimate-0.1.0/scripts/host_stack.py +218 -0
  128. hifimate-0.1.0/scripts/install.sh +606 -0
  129. hifimate-0.1.0/scripts/install_files.py +463 -0
  130. hifimate-0.1.0/scripts/install_secrets.py +80 -0
  131. hifimate-0.1.0/scripts/ma_setup.py +131 -0
  132. hifimate-0.1.0/scripts/output-device.sh +5 -0
  133. hifimate-0.1.0/scripts/providers/bilibili_live_smoke.py +142 -0
  134. hifimate-0.1.0/scripts/providers/migu_live_smoke.py +183 -0
  135. hifimate-0.1.0/scripts/realtime_permissions.py +156 -0
  136. hifimate-0.1.0/scripts/test_ma_providers.sh +29 -0
  137. hifimate-0.1.0/scripts/uninstall.sh +125 -0
  138. hifimate-0.1.0/systemd/hifimate-airplay-net.service +10 -0
  139. hifimate-0.1.0/systemd/hifimate-airplay.service +22 -0
  140. hifimate-0.1.0/systemd/hifimate-bluetooth.service +13 -0
  141. hifimate-0.1.0/systemd/hifimate-camilladsp.service +17 -0
  142. hifimate-0.1.0/systemd/hifimate-ctrl.service +18 -0
  143. hifimate-0.1.0/systemd/hifimate-dlna.service +24 -0
  144. hifimate-0.1.0/systemd/hifimate-mpd.service +12 -0
  145. hifimate-0.1.0/systemd/hifimate-music-mpd.service +12 -0
  146. hifimate-0.1.0/systemd/hifimate-spectrum.service +18 -0
  147. hifimate-0.1.0/systemd/hifimate.service +25 -0
  148. hifimate-0.1.0/tests/conftest.py +107 -0
  149. hifimate-0.1.0/tests/ctrl_browser.mjs +48 -0
  150. hifimate-0.1.0/tests/eq_browser.mjs +83 -0
  151. hifimate-0.1.0/tests/providers/bilibili/__init__.py +1 -0
  152. hifimate-0.1.0/tests/providers/bilibili/conftest.py +49 -0
  153. hifimate-0.1.0/tests/providers/bilibili/test_bili_client.py +219 -0
  154. hifimate-0.1.0/tests/providers/bilibili/test_parsers.py +242 -0
  155. hifimate-0.1.0/tests/providers/bilibili/test_provider.py +218 -0
  156. hifimate-0.1.0/tests/providers/bilibili/test_setup_flow.py +161 -0
  157. hifimate-0.1.0/tests/providers/migu/__init__.py +1 -0
  158. hifimate-0.1.0/tests/providers/migu/conftest.py +62 -0
  159. hifimate-0.1.0/tests/providers/migu/test_client.py +203 -0
  160. hifimate-0.1.0/tests/providers/migu/test_parsers.py +295 -0
  161. hifimate-0.1.0/tests/providers/migu/test_provider.py +379 -0
  162. hifimate-0.1.0/tests/providers/migu/test_setup_flow.py +188 -0
  163. hifimate-0.1.0/tests/roomfit_browser.mjs +38 -0
  164. hifimate-0.1.0/tests/settings_browser.mjs +13 -0
  165. hifimate-0.1.0/tests/spectrum_browser.mjs +443 -0
  166. hifimate-0.1.0/tests/test_airplay.py +109 -0
  167. hifimate-0.1.0/tests/test_airplay_net.py +82 -0
  168. hifimate-0.1.0/tests/test_bluetooth.py +74 -0
  169. hifimate-0.1.0/tests/test_bluetooth_alias.py +168 -0
  170. hifimate-0.1.0/tests/test_bluetooth_pair.py +109 -0
  171. hifimate-0.1.0/tests/test_bluetooth_speaker.py +94 -0
  172. hifimate-0.1.0/tests/test_builtin_output.py +180 -0
  173. hifimate-0.1.0/tests/test_cli.py +217 -0
  174. hifimate-0.1.0/tests/test_configure_ma_players.py +110 -0
  175. hifimate-0.1.0/tests/test_core.py +77 -0
  176. hifimate-0.1.0/tests/test_ctrl.py +387 -0
  177. hifimate-0.1.0/tests/test_dsp_model.py +79 -0
  178. hifimate-0.1.0/tests/test_eq.py +197 -0
  179. hifimate-0.1.0/tests/test_formats.py +292 -0
  180. hifimate-0.1.0/tests/test_host_packages.py +64 -0
  181. hifimate-0.1.0/tests/test_identity.py +83 -0
  182. hifimate-0.1.0/tests/test_install_lifecycle.py +378 -0
  183. hifimate-0.1.0/tests/test_install_scripts.py +517 -0
  184. hifimate-0.1.0/tests/test_install_secrets.py +46 -0
  185. hifimate-0.1.0/tests/test_linux_handoff.py +463 -0
  186. hifimate-0.1.0/tests/test_lyrics.py +206 -0
  187. hifimate-0.1.0/tests/test_ma_mpd.py +88 -0
  188. hifimate-0.1.0/tests/test_ma_setup.py +104 -0
  189. hifimate-0.1.0/tests/test_ma_visualizer.py +76 -0
  190. hifimate-0.1.0/tests/test_mpd.py +132 -0
  191. hifimate-0.1.0/tests/test_nowplaying.py +234 -0
  192. hifimate-0.1.0/tests/test_output_devices.py +242 -0
  193. hifimate-0.1.0/tests/test_pw_events.py +66 -0
  194. hifimate-0.1.0/tests/test_realtime.py +147 -0
  195. hifimate-0.1.0/tests/test_realtime_permissions.py +152 -0
  196. hifimate-0.1.0/tests/test_receiver_events.py +24 -0
  197. hifimate-0.1.0/tests/test_remote_pause.py +147 -0
  198. hifimate-0.1.0/tests/test_room_eq.py +104 -0
  199. hifimate-0.1.0/tests/test_roomfit.py +335 -0
  200. hifimate-0.1.0/tests/test_roomfit_session.py +182 -0
  201. hifimate-0.1.0/tests/test_runtime_paths.py +47 -0
  202. hifimate-0.1.0/tests/test_settings.py +124 -0
  203. hifimate-0.1.0/tests/test_spectrum.py +460 -0
  204. hifimate-0.1.0/tests/test_spectrum_install.py +177 -0
  205. hifimate-0.1.0/tests/test_spectrum_proxy.py +81 -0
  206. hifimate-0.1.0/tests/test_system_install.py +348 -0
  207. hifimate-0.1.0/tests/test_user_filters.py +121 -0
@@ -0,0 +1,15 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ .venv/
4
+ build/
5
+ dist/
6
+ *.egg-info/
7
+ .coverage
8
+ htmlcov/
9
+ .DS_Store
10
+ music-assistant/.env
11
+ music-assistant/data/
12
+ hifimate/_commit.txt
13
+ *.swp
14
+ *.swo
15
+ *~
@@ -0,0 +1,518 @@
1
+ # 安装与维护
2
+
3
+ 本文按顺序说明:先确认前置条件,再安装,然后完成首次设置。日常维护、卸载和故障排查在后面。
4
+ 安装后各个文件放在哪里,见 [README 的「安装后的文件」](README.md#安装后的文件)。
5
+ 从源码开发、测试和发布的说明集中在最后一章「[开发者](#8-开发者)」。
6
+
7
+ ## 1. 前置条件
8
+
9
+ 开始安装前,逐项确认下面几点。
10
+
11
+ ### 1.1 操作系统
12
+
13
+ 需要 PipeWire 1.0 及以上、WirePlumber 0.5 及以上。下表中的系统都已在官方容器里实际安装依赖并通过检查;
14
+ 完整的播放链路在 Debian 13 上实机验证过。
15
+
16
+ | 系统 | 支持情况 |
17
+ |---|---|
18
+ | Debian 13 (trixie) 及更新 | 支持(主要开发平台)。upmpdcli 需先添加[上游软件源](https://www.lesbonscomptes.com/upmpdcli/pages/downloads.html) |
19
+ | Ubuntu 26.04 LTS 及更新 | 支持。upmpdcli 需先添加 PPA `ppa:jean-francois-dockes/upnpp1` |
20
+ | Ubuntu 24.04 LTS | 支持,但要先升级 PipeWire(见下) |
21
+ | Fedora 43 及更新 | 支持。upmpdcli 用[上游提供的 RPM](https://www.lesbonscomptes.com/upmpdcli/pages/downloads.html) |
22
+ | Arch Linux | 支持,所有软件包都在官方仓库 |
23
+ | openSUSE Tumbleweed | 支持,所有软件包都在官方仓库 |
24
+ | Debian 12 | 不支持:PipeWire 0.3、WirePlumber 0.4 太旧,请升级到 Debian 13 |
25
+ | RHEL、CentOS Stream、Rocky、AlmaLinux | 暂不支持(见下) |
26
+
27
+ **Ubuntu 24.04 LTS** 自带 WirePlumber 0.4,读不了 HiFiMate 的配置。先用 PipeWire 上游维护者的 PPA 升级到
28
+ PipeWire 1.0.7、WirePlumber 0.5.2,再安装 HiFiMate:
29
+
30
+ ```sh
31
+ sudo add-apt-repository ppa:pipewire-debian/pipewire-upstream
32
+ sudo add-apt-repository ppa:pipewire-debian/wireplumber-upstream
33
+ sudo add-apt-repository ppa:jean-francois-dockes/upnpp1 # upmpdcli
34
+ sudo apt update && sudo apt full-upgrade
35
+ systemctl --user restart pipewire pipewire-pulse wireplumber # 或者重新登录
36
+ ```
37
+
38
+ 这两个 PPA 替换的是整台机器的音频核心组件,会影响机器上所有发声的程序。专门用来放音乐的主机,建议直接装 Ubuntu 26.04 LTS 或 Debian 13。
39
+
40
+ **RHEL、CentOS Stream、Rocky、AlmaLinux 暂不支持**,因为三个必需的组件在这些系统的官方源和 EPEL 里都没有:
41
+ MPD(DLNA 和 Music Assistant 两路输入都靠它)、upmpdcli(DLNA 接收)和 python3-dbus-next(蓝牙)。
42
+ 要支持,只能由我们自己编译并长期维护这些软件包,或者把它们放进容器(声卡、PipeWire、蓝牙都要穿透进容器),
43
+ 两条路的维护和验证成本都很高。想用红帽系的系统,可以改用 Fedora。
44
+
45
+ ### 1.2 硬件
46
+
47
+ - CPU 为 x86_64 或 aarch64(CamillaDSP 官方只提供这两种的 PulseAudio 版本)。
48
+ - 一台 USB DAC,要求支持双声道、32 位容器(S32_LE)的固定采样率列表。常见的 USB 音频 DAC 一般都满足,安装时会检查。
49
+ 没有 DAC 时可以用主机自带的模拟输出;HDMI、DisplayPort、S/PDIF 不支持。
50
+ - 使用蓝牙时需要蓝牙适配器(主机内置或 USB)。
51
+ - 声卡由 HiFiMate 独占。主机上其他用户(例如登录桌面的人)自己的 PipeWire 也会使用这块声卡,见 [1.4](#14-用户和权限)。
52
+
53
+ ### 1.3 软件
54
+
55
+ - **系统软件包**:PipeWire、WirePlumber、BlueZ、MPD、upmpdcli、Shairport Sync、Avahi,以及 Python 3.10+ 和
56
+ NumPy、PyYAML、websocket-client、dbus-next。安装器会用系统的包管理器(apt、dnf、pacman、zypper)自动安装,
57
+ 只有上表提到的 upmpdcli 软件源需要你事先添加;没添加时安装器会提示从哪里获取。
58
+ - **CamillaDSP 4.1.3**:安装器从 GitHub 下载官方版本并按固定的 SHA256 校验,不需要自己编译。
59
+ - **Samba**:共享音乐库用,安装器自动安装(不共享时加 `--without-share`)。
60
+ - **pipx**:一条命令安装时,如果系统里没有,安装脚本会自动装上。
61
+ - **Docker Engine 和 Compose v2**:使用 Music Assistant 时需要,安装器不会自动安装,请按
62
+ [Docker 官方说明](https://docs.docker.com/engine/install/)先装好并启动。
63
+
64
+ ### 1.4 用户和权限
65
+
66
+ - 安装需要 root:用 `sudo` 运行安装命令。安装器会创建一个专门运行 HiFiMate 的用户 `hifimate`
67
+ (不能登录,主目录 `/var/lib/hifimate`),把它加入 `audio`、`bluetooth`、`docker` 组,并让它开机自动运行,不需要有人登录。
68
+ 之后日常运行不再需要 sudo;管理命令 `sudo hifimate …` 本身用 sudo。
69
+ - `hifimate` 用户的 Linux 密码就是控制页密码,也是音乐共享的密码。这个账号的 shell 是 nologin,安装器还禁止它通过 SSH 登录,
70
+ 所以这个密码只能用来登录控制页和访问共享。
71
+ - 实时调度上限和蓝牙音箱类别这两项系统设置,安装器直接替 `hifimate` 用户设好(见 [3.4](#34-安装器做的系统设置)),卸载时还原。
72
+ - **这台主机最好专门用来放音乐。** 其他用户登录桌面时,他们自己的 PipeWire 也会使用同一块声卡,
73
+ 可能和 HiFiMate 抢声卡。在只用 SSH 管理的主机上,可以停掉管理员账号自己的音频服务,
74
+ 让声卡只归 HiFiMate(用管理员账号运行,以后要恢复把 `mask` 换成 `unmask`):
75
+
76
+ ```sh
77
+ systemctl --user mask --now pipewire.socket pipewire-pulse.socket pipewire.service pipewire-pulse.service wireplumber.service
78
+ ```
79
+
80
+ ### 1.5 网络和端口
81
+
82
+ 主机和手机、电脑需要在同一个局域网,并且局域网允许组播:AirPlay 用 mDNS、DLNA 用 SSDP 发现设备。
83
+
84
+ | 端口 | 用途 | 对局域网开放 |
85
+ |---|---|---|
86
+ | 80 | Music Assistant 和控制页(`/ctrl/`) | 是 |
87
+ | 443 | 房间校正页面(HTTPS) | 是 |
88
+ | 8095、8097 | Music Assistant 的网页接口和音频流 | 是(Music Assistant 自身需要) |
89
+ | AirPlay、DLNA 的端口 | 由 Shairport Sync、upmpdcli 自动选择 | 是 |
90
+ | 6600、6601、5008、5009、3003、3004、1234 | 内部服务 | 否,只监听 127.0.0.1 |
91
+
92
+ 80 端口被占用时可以换一个,见 [Music Assistant 使用说明](music-assistant/README.md#更换网页端口)。
93
+
94
+ ## 2. 安装
95
+
96
+ ### 2.1 一条命令安装
97
+
98
+ ```sh
99
+ curl -fsSL https://github.com/hifimate/hifimate/releases/latest/download/install.sh | sudo sh
100
+ ```
101
+
102
+ 这条命令依次完成:
103
+
104
+ 1. 没有 pipx 时,用系统的包管理器安装 pipx。
105
+ 2. 用 pipx 安装 `hifimate` 命令(`/usr/local/bin/hifimate`,软件包在 `/opt/pipx`)。
106
+ 3. 运行 `hifimate install`:
107
+ 1. 安装系统软件包(包括 Samba),下载 CamillaDSP;
108
+ 2. 创建用户 `hifimate`,准备 `/opt/hifimate`(程序和设置)和 `/srv/hifimate/music`(音乐库);
109
+ 3. 设置实时调度上限和蓝牙音箱类别;
110
+ 4. 以 `hifimate` 用户启动所有服务,部署 Music Assistant;
111
+ 5. 把音乐库共享为 `Music`。
112
+
113
+ 安装过程中会询问:
114
+
115
+ 1. **控制页密码**:至少 8 位。它就是 `hifimate` 用户的 Linux 密码,控制页登录时由系统(PAM)验证,HiFiMate 自己不保存密码;
116
+ 音乐共享(用户 `hifimate`)用同一个密码。
117
+ 2. **设备名称**,例如 `客厅`。手机上看到的是 `客厅 AirPlay`、`客厅 DLNA`、`客厅 Bluetooth`。
118
+ 名称可以用中文、空格、字母、数字和 `-_.()`,最长 42 字节(约 14 个汉字)。
119
+ 3. **输出设备**:只有一台兼容的 DAC 时自动选择;有多台时让你选。
120
+ 4. **Music Assistant 管理员**:用户名和密码,用于登录 Music Assistant 网页。这一步不能跳过,
121
+ HiFiMate 控制页对 Music Assistant 的控制依赖它。
122
+
123
+ 要给安装加选项,把 `| sudo sh` 换成 `| sudo sh -s -- 选项…`,例如:
124
+
125
+ ```sh
126
+ curl -fsSL https://github.com/hifimate/hifimate/releases/latest/download/install.sh | sudo sh -s -- --name 客厅 --without-music-assistant
127
+ ```
128
+
129
+ 已经装有 pipx 时,也可以分两步:`sudo PIPX_HOME=/opt/pipx PIPX_BIN_DIR=/usr/local/bin pipx install hifimate`,
130
+ 然后 `sudo hifimate install 选项…`。
131
+
132
+ ### 2.2 安装选项
133
+
134
+ | 选项 | 作用 |
135
+ |---|---|
136
+ | `--name 名称` | 设备名称;重新安装时省略则保留原名称 |
137
+ | `--output-device hw:CARD=卡ID,DEV=设备号` | 指定输出设备(查看可用设备见 [4.4](#44-更换输出设备)) |
138
+ | `--choose-output` | 列出可用的输出设备让你选 |
139
+ | `--music-directory 目录` | 音乐库的位置,默认 `/srv/hifimate/music`;已有的目录不改所有者,要让 `hifimate` 用户能读写 |
140
+ | `--without-share` | 不把音乐库共享到局域网 |
141
+ | `--without-music-assistant` | 不部署 Music Assistant(也就不需要 Docker) |
142
+ | `--without-ma-provider bilibili` 或 `migu` | 不安装某个自带的音乐源;`--without-ma-providers` 两个都不装 |
143
+ | `--realtime off` | 不使用实时调度 |
144
+ | `--no-install-deps` | 不调用包管理器,系统软件包由你自己装 |
145
+ | `--dry-run` | 只显示会做什么,不做任何改动 |
146
+ | `--non-interactive` | 无人值守,不询问任何问题(见 2.3) |
147
+
148
+ 选项会记在 `/etc/hifimate/install.json`(不含密码)。以后再运行 `sudo hifimate install` 只需给出要改的选项,其他选项沿用上次的;
149
+ `sudo hifimate upgrade` 也沿用这些选项。要完全按新给的选项安装,加 `--reset-options`。
150
+ 之前没装 Music Assistant、现在想加上,用 `--with-music-assistant`;之前没有共享、现在想加上,用 `--with-share`。
151
+
152
+ ### 2.3 无人值守安装
153
+
154
+ `--non-interactive` 不询问任何问题。原本要询问的内容必须事先给出,缺少时在改动任何东西之前报错退出。
155
+ 从管道运行且没有终端时,自动按无人值守处理。
156
+
157
+ 密码不能放在命令行参数里(参数对本机所有用户可见),用只有 root 可读的文件或环境变量给出:
158
+
159
+ | 内容 | 用文件 | 或者用环境变量 |
160
+ |---|---|---|
161
+ | 控制页(和音乐共享)的密码 | `--ctrl-password-file 文件` | `HIFIMATE_CTRL_PASSWORD` |
162
+ | Music Assistant 管理员用户名 | `--ma-admin-user 名称` | `HIFIMATE_MA_ADMIN_USER` |
163
+ | Music Assistant 管理员密码 | `--ma-admin-password-file 文件` | `HIFIMATE_MA_ADMIN_PASSWORD` |
164
+
165
+ 用文件(推荐):
166
+
167
+ ```sh
168
+ sudo install -m 600 /dev/null /root/hifimate.pw && sudo nano /root/hifimate.pw # 写入密码
169
+ curl -fsSL https://github.com/hifimate/hifimate/releases/latest/download/install.sh | sudo sh -s -- \
170
+ --name 客厅 --output-device hw:CARD=DAC,DEV=0 \
171
+ --ctrl-password-file /root/hifimate.pw --ma-admin-user admin --ma-admin-password-file /root/hifimate.pw
172
+ ```
173
+
174
+ 用环境变量时,`sudo` 默认会丢掉它们,要用 `--preserve-env` 显式传过去。不要写成 `sudo VAR=… sh`,那样密码会出现在进程列表里:
175
+
176
+ ```sh
177
+ export HIFIMATE_CTRL_PASSWORD='…' HIFIMATE_MA_ADMIN_USER=admin HIFIMATE_MA_ADMIN_PASSWORD='…'
178
+ curl -fsSL https://github.com/hifimate/hifimate/releases/latest/download/install.sh | \
179
+ sudo --preserve-env=HIFIMATE_CTRL_PASSWORD,HIFIMATE_MA_ADMIN_USER,HIFIMATE_MA_ADMIN_PASSWORD sh -s -- --name 客厅
180
+ ```
181
+
182
+ 说明:
183
+
184
+ - 密码 8–1024 个字符,不能有换行;文件末尾的一个换行会被去掉。
185
+ - 重新安装时给出控制页密码会替换旧密码(`hifimate` 用户的 Linux 密码和共享密码一起换);不给则保留。
186
+ - Music Assistant 已经有用户时,给出的管理员会被忽略,不会修改它的密码。
187
+
188
+ ## 3. 安装后的设置
189
+
190
+ ### 3.1 打开控制页
191
+
192
+ 浏览器打开 `http://<主机IP>/ctrl/`。主机 IP 可以在主机上用 `hostname -I` 查看;用手机或其他电脑访问时不能填 `127.0.0.1`。
193
+ 查看状态不需要登录,操作时用控制页密码登录,登录 30 天内有效。
194
+
195
+ ### 3.2 设置 Music Assistant
196
+
197
+ HiFiMate 已经被设为 Music Assistant 的播放器(`<名称> MA`),第一次使用只需添加音乐源,步骤见
198
+ [Music Assistant 使用说明](music-assistant/README.md#首次设置)。
199
+
200
+ ### 3.3 蓝牙配对
201
+
202
+ 在控制页的蓝牙卡片里点「配对 120 s」,或在主机上运行 `sudo hifimate pair`(`--seconds` 可改为 10–600 秒),
203
+ 然后在手机的蓝牙设置里选 `<名称> Bluetooth`。第一台配对成功的设备会被信任,窗口随即关闭。以后手机直接连接即可,不需要再开窗口。
204
+ 手机以前配对过、在手机上删除后重新配对,也是同样的步骤。
205
+
206
+ 确认系统的蓝牙服务和 Docker 服务是开机启动的:`systemctl is-enabled bluetooth docker`。
207
+
208
+ ### 3.4 安装器做的系统设置
209
+
210
+ 下面两项由安装器以 root 身份设好,卸载时自动还原:
211
+
212
+ - **实时调度上限**:允许 `hifimate` 用户的 CamillaDSP、MPD、Shairport Sync 和 PipeWire 音频线程以低优先级实时调度运行,
213
+ 在负载高或使用实时内核(PREEMPT_RT)时减少爆音。写在 `/etc/systemd/system/user@<UID>.service.d/90-hifimate-rtprio.conf`。
214
+ 不需要时安装加 `--realtime off`。
215
+ - **蓝牙音箱类别**:在 `/etc/bluetooth/main.conf` 里加两行带 HiFiMate 标记的设置,让手机把主机显示为音箱图标,
216
+ 并允许已配对过的手机重新配对。会重启一次蓝牙服务。`main.conf` 里已有你自己设置的 Class 时不会修改。
217
+
218
+ 控制页密码:安装器写入 `/etc/pam.d/hifimate`(只用 pam_unix 验证密码),用 `chpasswd` 设置 `hifimate` 用户的 Linux 密码,
219
+ 并写入 `/etc/ssh/sshd_config.d/hifimate.conf` 禁止这个用户 SSH 登录。这两个文件在 `uninstall --purge` 删除用户时一起删除。
220
+
221
+ 另外,共享音乐库会在 `/etc/samba/smb.conf` 末尾加一段带标记的 `[Music]` 设置,并给 `hifimate` 用户设 Samba 密码;
222
+ `smb.conf` 里其他内容不动,已经有别的 `[Music]` 共享时不会修改。
223
+
224
+ ### 3.5 让主机一直在线(可选)
225
+
226
+ 主机用 Wi‑Fi 或者是笔记本时,下面的设置能避免断网和休眠。它们属于整台主机的策略,HiFiMate 不会自动设置,卸载时也不会还原。
227
+
228
+ **关闭 Wi‑Fi 省电**(只适用于用 NetworkManager 管理 Wi‑Fi 的主机):
229
+
230
+ ```sh
231
+ sudo tee /etc/NetworkManager/conf.d/20-hifimate-wifi-powersave.conf >/dev/null <<'EOF'
232
+ [connection]
233
+ wifi.powersave = 2
234
+ EOF
235
+ sudo nmcli general reload conf
236
+ ```
237
+
238
+ 重新连接 Wi‑Fi 后生效,用 `iw dev <网卡> get power_save` 检查。还原:删除这个文件,再执行 `sudo nmcli general reload conf`。
239
+
240
+ **合盖不休眠**(笔记本):
241
+
242
+ ```sh
243
+ sudo mkdir -p /etc/systemd/logind.conf.d
244
+ sudo tee /etc/systemd/logind.conf.d/60-hifimate-lid.conf >/dev/null <<'EOF'
245
+ [Login]
246
+ HandleLidSwitch=ignore
247
+ HandleLidSwitchDocked=ignore
248
+ HandleLidSwitchExternalPower=ignore
249
+ IdleAction=ignore
250
+ EOF
251
+ sudo systemctl restart systemd-logind
252
+ ```
253
+
254
+ 重启 `systemd-logind` 可能会让当前桌面会话退出,请在不用桌面时执行。还原:删除这个文件,再重启 `systemd-logind`。
255
+
256
+ **完全禁止休眠**(确认这台主机不需要任何休眠时):
257
+
258
+ ```sh
259
+ sudo systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target suspend-then-hibernate.target
260
+ ```
261
+
262
+ 还原时把 `mask` 换成 `unmask`。
263
+
264
+ ## 4. 日常维护
265
+
266
+ ### 4.1 查看状态
267
+
268
+ ```sh
269
+ sudo hifimate status
270
+ ```
271
+
272
+ 显示安装的版本、输出设备、音乐库,以及每个服务和 Music Assistant 容器是否正常。控制页的「服务」部分显示同样的信息和日志。
273
+ 查看日志:
274
+
275
+ ```sh
276
+ sudo hifimate logs # 所有服务最近 100 行
277
+ sudo hifimate logs airplay -f # 只看 AirPlay,持续输出;也可以是 dlna、bluetooth、camilladsp、mpd、ctrl 等
278
+ ```
279
+
280
+ 各服务的作用见 [ARCHITECTURE.md](docs/ARCHITECTURE.md#2-组成部分)。
281
+
282
+ ### 4.2 升级
283
+
284
+ ```sh
285
+ sudo hifimate upgrade # 升级到最新版本
286
+ sudo hifimate upgrade --version 0.2.0 # 升级或回到指定版本
287
+ ```
288
+
289
+ 升级会沿用上次安装的选项,并重启所有服务,正在播放的音乐会中断。你的密码、EQ、房间校正、音乐库和 Music Assistant 数据都会保留。
290
+
291
+ ### 4.3 自己的 EQ
292
+
293
+ EQ 在 EQ 页面(`http://<主机IP>/ctrl/eq/`)编辑,见 [README](README.md#自己的-eq)。它保存在 `/opt/hifimate/config/dsp-filters.yml`,
294
+ 也可以用 `sudo nano` 直接编辑;页面和手动编辑互相兼容,页面保存时如果发现文件在这期间被改过,会提醒而不会覆盖。规则:
295
+
296
+ - 只能有 `Filter` 步骤;滤波器类型可用 Biquad、BiquadCombo、Gain、Delay、DiffEq、Conv。Volume 和 Loudness 不允许。
297
+ - 声道写 `[0]`(左)、`[1]`(右)或 `[0, 1]`;定义的每个滤波器都要在 `pipeline` 里用到。
298
+ - 处理顺序是:预留余量(Headroom)→ 你的 EQ → 房间校正。所有采样率都用同一份 EQ。
299
+ - 手动改完运行 `sudo hifimate reload-filters`(页面上点「应用」即可)。写法有错时会说明原因,播放照常进行,只是不带你的 EQ。
300
+
301
+ ### 4.4 更换输出设备
302
+
303
+ 在控制页的输出卡片里切换,或者在主机上:
304
+
305
+ ```sh
306
+ sudo hifimate output # 列出可用的输出设备
307
+ sudo hifimate output --choose # 选择并切换
308
+ sudo hifimate output --device hw:CARD=DAC,DEV=0 # 直接切换到指定设备
309
+ ```
310
+
311
+ 切换会中断正在播放的音乐。列表里的名称以「USB」或「本机」开头,后面是 `hw:CARD=…,DEV=…` 形式的设备 ID,
312
+ 也可以把 ID 用于安装选项 `--output-device`。
313
+
314
+ 输出设备是 `auto` 时:只有一台兼容 USB DAC 就用它;没有 USB DAC 时用唯一的本机模拟输出;
315
+ 有多台时需要明确指定。
316
+
317
+ ### 4.5 修改名称和密码
318
+
319
+ - 改名称:`sudo hifimate install --name 新名称`。
320
+ - 改控制页密码:`sudo hifimate password`。它修改 `hifimate` 用户的 Linux 密码和音乐共享的密码,并让所有已登录的浏览器重新登录。
321
+ - Music Assistant 的密码在 Music Assistant 网页里修改。
322
+
323
+ ### 4.6 其他配置
324
+
325
+ 在设置页面(控制页右上角的齿轮)修改:
326
+
327
+ | 设置 | 默认 | 作用 |
328
+ |---|---|---|
329
+ | 淡入 | 400 毫秒 | 开始播放时从静音升到正常音量,20–2000 毫秒 |
330
+ | 释放 DAC | 5 分钟 | 没有声音多久后暂停发送端并关闭 DAC,可以设为不释放 |
331
+ | 允许的采样率 | DAC 支持的全部 | 可以排除个别采样率;被排除的曲目会报错并保持静音,不会重采样 |
332
+
333
+ 保存后仲裁服务会重启,正在播放的音乐中断几秒。这些设置保存在 `/opt/hifimate/config/settings.json`,重新安装和升级都会保留。
334
+
335
+ `/opt/hifimate/config/hifimate.conf` 是安装器管理的默认值,记录在安装清单里,**不要手改**:改过之后,下次安装或升级会拒绝继续。
336
+ 要在主机上改上面这几项,编辑 `settings.json`(键名 `fade_ms`、`idle_timeout_s`、`rates`),再运行 `sudo hifimate restart`。
337
+
338
+ ## 5. 卸载
339
+
340
+ ```sh
341
+ sudo hifimate uninstall --dry-run # 先看看会删除什么
342
+ sudo hifimate uninstall
343
+ sudo PIPX_HOME=/opt/pipx PIPX_BIN_DIR=/usr/local/bin pipx uninstall hifimate # 最后删除 hifimate 命令本身
344
+ ```
345
+
346
+ 卸载会停止并删除 HiFiMate 的服务和程序,删除 Music Assistant 的容器,还原蓝牙名称,撤销实时调度上限、蓝牙音箱类别和音乐共享。
347
+ 下面这些会保留,再次安装时会继续使用:
348
+
349
+ - 系统软件包(PipeWire、BlueZ、MPD、Samba 等),它们可能还有别的用途;
350
+ - 音乐库 `/srv/hifimate/music`;
351
+ - 用户 `hifimate`(和它的密码),以及属于你的数据:`/opt/hifimate` 里的 EQ、房间校正和测量记录、本地证书、
352
+ Music Assistant 的设置和另行安装的音乐源,`/var/lib/hifimate` 里的 Music Assistant 数据。
353
+
354
+ 要连用户和这些数据一起删除(音乐库仍然保留):
355
+
356
+ ```sh
357
+ sudo hifimate uninstall --purge
358
+ ```
359
+
360
+ 不要不经卸载就直接删除这些目录,那样会留下服务、系统设置和改过的蓝牙名称。
361
+
362
+ ## 6. 故障排查
363
+
364
+ **手机上看不到设备**
365
+
366
+ 1. `sudo hifimate status` 确认所有服务都是 active。
367
+ 2. 确认手机和主机在同一个网段,路由器没有开启「AP 隔离」或屏蔽 mDNS。
368
+ 3. 主机有多个网卡时,AirPlay 只在默认路由的网卡上广播,确认手机能访问那个网卡的地址。
369
+
370
+ **能连接但没有声音**
371
+
372
+ 1. 控制页的信号图里看当前输入是不是你正在播放的那一路,输出设备是否正确。
373
+ 2. 看控制页「错误」日志,或者 `sudo hifimate logs hifimate`。常见原因是 DAC 不支持这个采样率
374
+ (HiFiMate 不会偷偷重采样,而是报错并保持静音),或者 DAC 被别的程序占用(见下一条)。
375
+ 3. 确认 DAC 本身的音量和输入选择。
376
+
377
+ **DAC 被占用**
378
+
379
+ 主机上其他用户自己的 PipeWire 会打开同一块声卡,例如有人登录了桌面。专门放音乐的主机上,按 [1.4](#14-用户和权限) 停掉这些用户的音频服务;
380
+ 有桌面的电脑上,HiFiMate 播放时不要在桌面上同时用这块声卡放声音。
381
+
382
+ **切换输入后原来的设备没有暂停**
383
+
384
+ 有些发送端不接受远程暂停,例如不提供远程控制的 AirPlay 发送端、不响应暂停指令的蓝牙手机。这时 HiFiMate 照样切换到新的输入,
385
+ 原来的设备需要手动暂停。DLNA 和 Music Assistant 总能暂停,但控制 App 的界面不一定马上同步。控制页的日志会记录每次暂停请求的结果。
386
+
387
+ **蓝牙名称没有变**
388
+
389
+ 查看 `sudo hifimate logs bluetooth`。安装器已经把 `hifimate` 用户加入 `bluetooth` 组;改过组之后要重新安装一次
390
+ (`sudo hifimate install`),新的组才对服务生效。
391
+
392
+ **连不上共享文件夹**
393
+
394
+ 1. `systemctl status smbd`(openSUSE、Fedora 上是 `smb`)确认 Samba 在运行;防火墙要放行 Samba(Fedora 上安装器已自动放行)。
395
+ 2. 用户名是 `hifimate`,密码是控制页密码。密码不对时用 `sudo hifimate password` 重新设置。
396
+ 3. Windows 提示「不能访问」时,确认没有关闭 SMB2/3(HiFiMate 不支持过时的 SMB1)。
397
+
398
+ **80 端口被占用,Music Assistant 起不来**
399
+
400
+ 见 [Music Assistant 使用说明](music-assistant/README.md#更换网页端口)。
401
+
402
+ **安装器提示 PipeWire 或 WirePlumber 版本太旧**
403
+
404
+ 见 [1.1 操作系统](#11-操作系统)。
405
+
406
+ ## 7. 安装在主机上的内容
407
+
408
+ 日常会用到的文件见 [README 的「安装后的文件」](README.md#安装后的文件)。完整列表:
409
+
410
+ | 位置 | 内容 |
411
+ |---|---|
412
+ | `/usr/local/bin/hifimate`、`/opt/pipx/` | `hifimate` 命令和它的 Python 环境 |
413
+ | `/opt/hifimate/` | 程序、服务定义、配置,以及你的 EQ、房间校正、证书、Music Assistant 的部署配置 |
414
+ | `/var/lib/hifimate/` | 用户 `hifimate` 的主目录:PipeWire、WirePlumber 的配置片段和 systemd 用户服务的链接(`.config/`),Music Assistant 的数据 |
415
+ | `/srv/hifimate/music/` | 音乐库 |
416
+ | `/etc/hifimate/install.json` | 记住的安装选项 |
417
+ | `/etc/systemd/system/user@<UID>.service.d/90-hifimate-rtprio.conf` | 实时调度上限 |
418
+ | `/etc/bluetooth/main.conf` 中带 HiFiMate 标记的两行 | 蓝牙音箱类别 |
419
+ | `/etc/samba/smb.conf` 末尾带 HiFiMate 标记的 `[Music]` 段、`/etc/avahi/services/hifimate-smb.service` | 音乐共享,以及让 Mac 在「网络」里看到它 |
420
+ | `/etc/pam.d/hifimate` | 控制页验证密码用的 PAM 设置(只有 pam_unix) |
421
+ | `/etc/ssh/sshd_config.d/hifimate.conf` | 禁止 `hifimate` 用户通过 SSH 登录 |
422
+ | `/var/lib/hifimate-realtime/`、`/var/lib/hifimate-bluetooth-speaker/` | 上面两项系统设置的归属记录,卸载时据此还原 |
423
+
424
+ 安装器记录了自己写入的每个文件的哈希。你手动改过的 HiFiMate 程序文件,重新安装和卸载时都会拒绝覆盖或删除,并提示是哪个文件。
425
+
426
+ ## 8. 开发者
427
+
428
+ ### 8.1 从源码安装
429
+
430
+ 两种方式都从源码目录运行,改代码后重新运行同一条命令即可部署(会重启所有服务)。
431
+
432
+ **系统方式**(与用户的安装相同,用专门的 `hifimate` 用户):
433
+
434
+ ```sh
435
+ git clone https://github.com/hifimate/hifimate.git
436
+ cd hifimate
437
+ sudo python3 -B -m hifimate.cli install --dry-run # 只显示计划
438
+ sudo python3 -B -m hifimate.cli install --name 客厅
439
+ ```
440
+
441
+ 它把源码目录复制到 `/var/tmp` 交给 `hifimate` 用户,其余与 `sudo hifimate install` 完全相同。
442
+
443
+ **用户方式**(装在当前用户的 `~/hifimate`,不建用户、不共享;适合开发机或没有 root 的机器):
444
+
445
+ ```sh
446
+ scripts/install.sh --install-deps --enable --with-music-assistant --name 客厅 # 只显示计划
447
+ scripts/install.sh --apply --install-deps --enable --with-music-assistant --name 客厅 # 实际安装
448
+ ```
449
+
450
+ `scripts/install.sh` 是实际的安装器,两种方式最终都调用它;不带 `--apply` 时只显示计划。
451
+ 用户方式下 `--apply`、`--enable`、`--with-music-assistant`、`--install-deps` 都要显式给出,需要 sudo 的两项系统设置用
452
+ `--setup-realtime`、`--setup-bluetooth-speaker`,服务要开机运行还需 `loginctl enable-linger "$USER"`。
453
+ 用户方式下控制页密码就是你自己的登录密码(PAM 服务 `hifimate`;没有 `/etc/pam.d/hifimate` 时用系统的 `other` 设置,
454
+ 部分发行版的 `other` 一律拒绝,这时照 [3.4](#34-安装器做的系统设置) 写入那个文件)。
455
+ 卸载用 `scripts/uninstall.sh --apply`。也可以用 `hifimate install`(不带 sudo)走同样的用户方式;
456
+ 一键安装脚本用 `HIFIMATE_USER_MODE=1` 时也是用户方式。
457
+
458
+ 只检查依赖:
459
+
460
+ ```sh
461
+ python3 scripts/host_stack.py --check
462
+ scripts/install.sh --list-outputs
463
+ ```
464
+
465
+ ### 8.2 测试
466
+
467
+ ```sh
468
+ python3 -m pip install -e '.[test,host]' # 或者使用发行版的 python3-pytest 等软件包
469
+ python3 -B -W error -m pytest -q
470
+ node tests/ctrl_browser.mjs # 控制页的浏览器测试
471
+ node tests/spectrum_browser.mjs # 频谱的浏览器测试
472
+ node tests/roomfit_browser.mjs # 房间校正页的浏览器测试
473
+ ```
474
+
475
+ 测试不会碰本机的服务、声卡和 sudo:系统命令都被替换成假的,误调用会直接失败。
476
+ Music Assistant 音乐源的测试需要 Music Assistant 本身,在它的镜像里运行:`scripts/test_ma_providers.sh`。
477
+ 对真实服务的冒烟测试在 `scripts/providers/*_live_smoke.py`。
478
+
479
+ 推送前建议在干净的 Python 3.11 容器里跑一遍(CI 用 3.11 和 3.13),本机装过的东西有时会掩盖问题:
480
+
481
+ ```sh
482
+ docker run --rm -v "$PWD":/src:ro python:3.11-bookworm sh -c '
483
+ apt-get update -qq && apt-get install -y -qq nodejs git openssl iproute2 >/dev/null
484
+ cp -r /src /w && cd /w && pip install -q -e ".[test,host]" && python -B -W error -m pytest -q'
485
+ ```
486
+
487
+ 在临时的 PipeWire 实例里检查采样率切换(不打开声卡):
488
+
489
+ ```sh
490
+ python3 scripts/check-format-stack.py
491
+ python3 scripts/check-format-stack.py --mpd
492
+ ```
493
+
494
+ ### 8.3 调试仲裁服务
495
+
496
+ 仲裁服务在 `/run/user/<UID>/hifimate/format.sock` 提供本地接口,只接受同一用户。系统安装时查看当前状态:
497
+
498
+ ```sh
499
+ sudo runuser -u hifimate -- env XDG_RUNTIME_DIR=/run/user/$(id -u hifimate) \
500
+ PYTHONPATH=/opt/hifimate/lib python3 -m hifimate.format_cli '{"action":"status"}'
501
+ ```
502
+
503
+ 返回里 `ready: true` 且 `effective` 不为空,表示整条链路已经核对过;`effective` 给出图时钟、DSP 和 DAC 的实际采样率。
504
+ `error` 是失败原因。以 `hifimate` 用户运行任何命令(例如 `systemctl --user`、`pactl`)都用上面的 `runuser … env XDG_RUNTIME_DIR=…` 前缀。
505
+
506
+ ### 8.4 打包和发布
507
+
508
+ `pyproject.toml` 用 hatchling 构建;wheel 里除了 `hifimate` 包,还在 `hifimate/_dist/` 下带着安装器需要的全部文件。
509
+ 版本号只写在 `hifimate/__init__.py`。发布步骤见 [packaging/RELEASING.md](packaging/RELEASING.md)。
510
+
511
+ 本地构建并检查 wheel:
512
+
513
+ ```sh
514
+ python3 -m pip wheel --no-deps -w dist .
515
+ python3 -B packaging/check_wheel.py dist/hifimate-*.whl
516
+ ```
517
+
518
+ 代码结构和工作原理见 [ARCHITECTURE.md](docs/ARCHITECTURE.md)。
hifimate-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 wangwenlin
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,20 @@
1
+ # 第三方说明 / Third-party notices
2
+
3
+ HiFiMate 自身的代码按 MIT 许可证发布(见 `LICENSE`)。仓库里不包含其他项目的源码或二进制;
4
+ 下面这些由安装器在安装时从上游取得,或在运行时作为独立程序使用,各自遵循自己的许可证:
5
+
6
+ | 组件 | 用法 | 许可证 |
7
+ |---|---|---|
8
+ | [CamillaDSP](https://github.com/HEnquist/camilladsp) 4.1.3 | 安装器下载官方发布版,未修改 | GPL-3.0 / MPL-2.0 |
9
+ | [Music Assistant](https://github.com/music-assistant/server) | 经 [ma_custom_loader](https://github.com/neqq3/ma_custom_loader)(neqq3)打包的 Custom Loader 镜像,运行时拉取 | Apache-2.0 |
10
+ | [ma-provider-subscriber](https://github.com/neqq3/ma_custom_loader)(neqq3) | Docker 镜像,运行时拉取 | Apache-2.0 |
11
+ | PipeWire、WirePlumber、BlueZ、MPD、upmpdcli、Shairport Sync、Avahi、Samba | 发行版软件包,独立进程 | 各自许可证 |
12
+ | websocket-client、PyYAML、dbus-next、NumPy | 发行版软件包 | 各自许可证 |
13
+ | ncm-api、migu-api-enhanced、MA provider subscriber 及其 provider | Docker 镜像 / 运行时下载 | 各自许可证 |
14
+
15
+ - 频谱的显示效果参照了 [audioMotion-analyzer](https://github.com/hvianna/audioMotion-analyzer)(AGPL-3.0)公开的
16
+ 行为:1/24 倍频程分带、Bark/Mel 频率刻度公式、线性幅度的 boost 映射和 LED 外观。代码是本项目独立编写的,
17
+ 没有复制其源码;在此致谢。
18
+ - 房间校正中 iPhone 15 Pro Max、16 Pro、17 Pro、18 Pro 麦克风的补偿曲线,来自 Faber Acoustical 公开发表的测量图
19
+ (见 `hifimate/mics/*.json` 的 `source` 字段和 README 的「房间校正」一节),经数字化处理,版权归原作者。
20
+ - Bilibili、咪咕、网易云音乐等名称和图标是其各自所有者的商标,仅用于标识对应服务。