Skip to content

Repository files navigation

sync-audio

局域网多设备音频 / 视频同步播放 · 把闲置设备拼成一套环绕声系统

sync-audio 让局域网内多台设备(电脑 / 手机 / iPad)同时播放同一段音频,节拍重音对齐即同步成功。除「所有设备放同一首歌」外,还支持把 5.1 / 7.1 声道的每个声道拆分到不同设备(左声道一个手机、低音炮一个音箱……),把家里的闲置设备拼成一套真正的物理环绕声系统。

无需安装任何 App,打开浏览器即可。


特性亮点

  • 毫秒级同步:SNTP 时钟校准 + WebSocket 广播 + Web Audio 精确调度,重音对齐可听感验证
  • 真实文件播放:mp3 / wav / mp4,主控浏览器端 ffmpeg.wasm 解码,服务器零解码负担
  • 多声道分配(5.1 / 7.1):为每台设备指定声道,把多台设备拼成物理环绕声
  • 视频文件:只广播音轨,画面仅主控本机显示,与音频时间轴联动(播放 / 暂停 / 拖进度条同步)
  • 主控自动切换:任何设备可接管主控,断线自动移交其他设备
  • 手机不熄屏:HTTPS + Wake Lock(可选)
  • 同步可观测:设备周期性上报速率 / 漂移,analyze-log.js 一键分析同步质量

快速开始

环境要求:Node.js ≥ 14(仅依赖 ws);openssl 可选(用于自动生成 HTTPS 证书,Windows 装 Git 自带,Linux / macOS 一般自带)。

git clone https://github.com/wangk372/sync-audio.git
cd sync-audio
npm install        # 仅安装 ws
node server.js

启动后终端会打印所有访问地址(本机与局域网 IP,一般是 192.168.x.x)。

后台运行(推荐):Windows 用 .\run-test.ps1,类 Unix 用 ./run-test.sh,日志自动落盘到 logs/


各设备访问地址

设备 地址 说明
主控(主机) http://localhost:8080 第一个打开的页面即成为主控,只有它能开始 / 暂停
子设备(手机 / iPad) http://<主机IP>:8080 即连即用;明文 HTTP 无法自动保持屏幕常亮
子设备(要自动常亮) https://<主机IP>:8443 需先装一次证书(见下文),播放时屏幕自动不熄

<主机IP> 以启动日志为准,是主机的局域网 IP,不是子设备自己的 IP。


使用指南

基础使用(beat 模式)

  1. 主控:主机浏览器打开 http://localhost:8080,页面显示「开始同步播放」即表示你是主控
  2. 子设备:手机 / iPad 打开 http://<主机IP>:8080,即连即用;iOS 需先点一下页面任意位置激活声音
  3. 主控点「开始同步播放」→ 所有设备同步出声(节拍重音对齐即成功)
  4. 主控点「暂停播放」→ 全部设备同步暂停
  5. 没声音?先点「本地自检音」:能听到 = 本机正常,问题在网络链路

播放音乐 / 视频文件(file 模式)

  1. 主控点「选择音频 / 视频文件」选 mp3 / wav / mp4 等(首次需加载解码器约 30MB,之后秒载)
  2. 解码完成显示 文件名 · 时长 · N 声道 · 已解码就绪
  3. 点「开始同步播放」→ 所有设备同步播放该文件
  4. 未选文件时点「开始」= 内置节拍音,两种模式可自由切换

声道 & 视频分配

  • 主控切换:任何设备点「我要成为主控」即可接管;主控断开会自动移交给其他设备
  • 声道分配:主控可在「声道分配」卡片为每台设备指定听哪个声道(左 / 右 / 中置 / 低音炮 / 左环绕 / 右环绕……,选项数 = 当前文件声道数)。主控页面播放中显示音频进度条;主控切走 / 断流超 3 秒,服务器自动停止广播
  • 视频文件:只抽取音轨广播(不解码画面),所有设备同步出声;画面仅主控本机显示,跟随音频时间轴自动对齐,播完停在最后一帧。其他设备只听声音,无画面

播放时不熄屏(可选,推荐)

Web 浏览器无法在锁屏下继续播放(平台限制),策略是「播放时保持屏幕常亮」(Wake Lock):

  1. 手机浏览器打开 http://<主机IP>:8080/ca.pem 下载证书
  2. 安卓:设置 → 安全 → 安装 CA 证书 iOS:安装描述文件 → 设置 → 通用 → 关于本机 → 证书信任设置 → 开启完全信任
  3. 之后访问 https://<主机IP>:8443 → 播放时自动常亮、停止自动恢复

HTTPS 证书为服务器启动时用 openssl 自动生成的自签证书,SAN 自动覆盖当前局域网 IP。


日志与同步质量分析

  • 服务器自动写日志:logs/run-<时间戳>.log(主控切换时自动新建文件,不会堆在一起)
  • 分析同步质量:node analyze-log.js logs/run-<最新时间戳>.log

常见问题

  • 手动锁屏后声音被暂停:平台限制,无解;保持亮屏(Wake Lock 或调长自动锁屏)即可避免
  • 无声:查服务器日志 [rep] 行看各设备上报状态(audioCtx 是否 running、队列是否在涨);iOS 需先点一下页面任意位置激活声音
  • 主控刷新页面:仍是主控(身份自动恢复),日志不会因此新建
  • 克隆后无法离线解码ffmpeg-core 的 wasm 二进制(约 30MB)被 .gitignore 排除,未随仓库提交;首次运行会自动从 jsdelivr CDN 下载。如需完全离线,可手动把 ffmpeg-core.js / ffmpeg-core.wasm 放入 public/vendor/ffmpeg/

技术原理

flowchart LR
    MC["主控浏览器<br/>ffmpeg.wasm 解码"] -- "上传 PCM 帧" --> SRV["服务器<br/>WebSocket 广播"]
    SRV -- "广播音频帧 + 时间戳" --> SUB["子设备浏览器<br/>SNTP 校准 + Web Audio 调度"]
    SUB -. "校准往返 syncReq / syncResp" .-> SRV
Loading
  • 同步原理:服务器以自身时钟为基准,设备通过 SNTP 风格往返测量校准时钟偏移;音频帧时间戳指向「未来 + LEAD(默认 1200ms)」,各设备按本地时钟对齐播放,从根源消除累积漂移
  • 协议:JSON 控制消息(hello / welcomesyncReq / syncRespstart / stop / seek)+ 二进制音频帧
  • 依赖极简:服务器端仅 ws;解码完全在浏览器端完成(ffmpeg.wasm

目录结构

sync-audio/
├── server.js            # HTTP + HTTPS + WebSocket 服务器(广播、校准、主控管理、证书生成)
├── public/
│   ├── index.html       # 浏览器端(主控 + 子设备同一页面,自动识别身份)
│   └── vendor/ffmpeg/   # ffmpeg.wasm 加载器(优先本地,缺失时回退 CDN)
├── analyze-log.js       # 同步质量分析工具
├── test-client.js       # 协议级验证脚本(node test-client.js)
├── run-test.ps1 / .sh   # 后台启动脚本(Windows / 类 Unix)
├── logs/                # 运行时日志(git 忽略)
└── certs/               # 自动生成的 HTTPS 证书(git 忽略)

About

局域网多设备音频 / 视频同步播放:把闲置设备拼成一套环绕声系统

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages