Snapcast 多房间音频控制一体化

目录

动机

想要手头的两台 MBP 能同时无延迟播放音频,拒绝使用直播流的形式。

主旨

Vmware Ubuntu 中安装 snapserver

接受 Airplay 的信号

sudo apt install snapserver

sudo apt install -y shairport-sync
sudo systemctl disable --now shairport-sync
  1. 该虚拟机网络采用桥接方式

  2. 注意该服务会自动启动,你可能需要设置下配置文件位置 sudo vi /lib/systemd/system/snapserver.service

    Untitled

    Untitled

    Untitled

  3. 配置文件 /etc/snapserver.conf 中添加:source = airplay:///shairport-sync?name=Airplay

    [stream]
    source = airplay:///shairport-sync?name=Airplay
    

    Untitled

  4. 重启 sudo service snapserver restart

  5. snapweb 是需要手动添加的,建议从 macos 中复制到该虚拟机,在 mac 上的位置为:

    /usr/local/Cellar/snapcast/0.27.0/share/snapserver

    Untitled

  6. 使用 Tabby 终端连接上虚拟机的 SFTP 上传,上传到配置文件中 doc_root 配置的位置:

    Untitled

    Untitled

macOS 上启动 snapclient

brew install snapcast

snapclient

会自动找到局域网中的 server 并连接

总结

任意终端打开控制网页:

Untitled

Untitled

发现两台 MBP 都连接上了,使用 iPhone 隔空投送到 Snapcast:

Untitled

两台 MBP 无缝播放音乐咯!

缺点是无法用两台 MBP 中的一个作为输出,还需要 iPhone 介入,应该有解决方案,之后再看了

  • 在其中一台 MBP 中部署了 navidrome,然后通过 iPhone 放歌。配合 iPhone 上的 substreamer 免费 app ,好用到飞起。但要注意 local music 的质量,需要 ~~mp3tag~~Tagr (自动提取真的好用极了)这样的软件编辑好音频元数据。

Untitled

专辑封面哪里找?Last.fm | Play music, find songs, and discover artists

Untitled

音乐下载使用 msc:https://github.com/zonemeen/musicn https://github.com/zonemeen/musicn

参考文章

GitHub Snapcast

标签 :

相关文章

并查集

并查集三步走 并查集,开始的时候大家都是孤岛,根节点就是自己,然后我们不断地合并、修改指针,直到所有边都访问到。 数组初始化,每个节点的 parent 指针都指向自己。数组 roots 存放所有节点的祖先节点(根节点,路径压缩)【如果要求子集中元素数量,那么还要再创建一个 counts 数组,存储一份子集元素中的数量,需要在 union 中更新】。 根据所有相连的边,不断地进行查找、合并。 查找用递归、同时能修改查找路径上的所有节点的 parent 指针,合并前先调用查找然后看是否同一子图,是则合并失败,不是则直接将 parent 指针修改一下即可。 **有向图是否有环?**拓扑排序 DAG !

阅读更多
图数据库 Cypher 查询语言的子查询 CALL (subquery)

子查询允许将查询组合起来,这在使用UNION或聚合时特别有用。 子查询与封闭查询交互的方式有一些限制: 子查询只能引用外部查询中显式导入的变量。 子查询不能返回与外围查询中变量名称相同的变量。 从子查询返回的所有变量随后都可在外部查询中使用。 WITH导入变量进子句必须:

阅读更多
如何在 React 中进行状态管理?使用 Zustand!

计数器 import { create } from 'zustand' const useStore = create(set => ({ count: 1, inc: () => set(state => ({ count: state.count + 1 })), })) function Controls() { const inc = useStore(state => state.inc) return <button onClick={inc}>one up</button> } function Counter() { const count = useStore(state => state.count) return <h1>{count}</h1> } 用法 创建状态 state 操作 action Basic typescript usage doesn’t require anything special except for writing create<State>()(...) instead of create(...)… import { create } from 'zustand' interface BearState { bears: number increase: (by: number) => void } const useBearStore = create<BearState>()((set) => ({ bears: 0, increase: (by) => set((state) => ({ bears: state.bears + by })), })) const useFishStore = create((set) => ({ salmon: 1, tuna: 2, deleteEverything: () => set({}, true), // clears the entire store, actions included deleteTuna: () => set((state) => omit(state, ['tuna']), true), })) const useSoundStore = create((set, get) => ({ sound: "grunt", action: () => { const sound = get().sound // you still have access to state outside of it through get // ... } }) export default useBearStore 在 react 之外使用呢?

阅读更多