Skip to content
ShanWuYinShePublic

About

跨端双向设备映射中心:把电脑的系统声音、麦克风、鼠标与键盘实时映射到手机/平板/另一台电脑(Go + Wails + Svelte,Opus 低带宽传输)

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

AnyDevice - 跨端双向设备映射中心 🎵🖱️🎮

CI

将台式机/电脑的声音与鼠标实时无线映射到手机、平板、另一台电脑或电视上。自带原生独立桌面应用窗口(双击直接弹窗,无需浏览器):既能作为提供方把本机系统声音、麦克风、鼠标与键盘共享给对端,也能作为使用方把对端能力逐项映射到本机播放或执行。智能路由优先物理网卡(虚拟网卡会被标记、仍可在 UI 手动选择),支持在 UI 上切换通信网卡与设备映射。


🌟 核心特性

  • 自带原生独立桌面应用窗口(Wails 原生窗口,无需浏览器):
    • 桌面窗口采用 Wails 原生窗口(macOS WKWebView / Windows WebView2 / Linux WebKitGTK):macOS 双击 AnyDevice.app、Windows 双击 any_device.exe、Linux 运行 any_device-linux-amd64(发布资产名;本地构建产物为 bin/any_device_linux_amd64),直接弹出专属独立应用窗口——无浏览器地址栏、无控制台黑窗、无浏览器启动器竞态,关窗即安全退出。
    • macOS 的 .app 由 scripts/build.sh 打包(Info.plist 带 ATS 本地网络例外与麦克风用途声明),不依赖本机安装 Chrome/Edge;窗口内的 WebSocket 直连 ws://127.0.0.1:<port>,页面与 /api 请求仍走内置 handler。
    • 窗口与局域网服务共用同一套 UI 与 API:窗口内的页面请求直达内置服务,局域网端口照常服务手机/平板/其他电脑。
    • 服务先于窗口就绪:先完成端口监听再打开窗口,首屏不会因服务未就绪而白屏。
    • 也可以通过 -no-ui 运行于纯后台守护进程模式。
    • 仅开发调试用的无标签 go build 会回退为浏览器 --app 独立窗口模式(Chrome/Edge 独立 profile;macOS 上若没有 Chrome/Edge 则回退 webview_go/WKWebView);发布产物一律是原生窗口。
  • 对等的发现与映射模型(提供方 + 使用方):
    • 📥 接收侧(把对端能力映射到本机):
      • 🎧 系统声音:把对端电脑的声音串流到本机/手机播放;
      • 🎙️ 麦克风:把对端麦克风拾音映射到本机收听;
      • 🖱️ 鼠标 / ⌨️ 键盘遥测:把对端光标坐标、按键事件实时投射到接收端卡片显示。
    • 📤 共享侧(把本机能力开放给对端):
      • 在「本机共享」设置里逐项开放系统声音、麦克风、物理鼠标与物理键盘,对端发现本机后自行决定是否映射;
      • 电脑对电脑时双方各自打开本程序、互相映射对方设备,即可实现完整物理鼠标与键盘同步:移动、左右/中键、滚轮、按键在对端实时还原;
      • 滚轮同步:捕获端滚动滚轮,对端即时还原滚动方向与幅度;跨平台按「格/行」归一化(Windows 高精度滚轮/触控板的 1/40 细分增量会累积到一格再滚,不会一格变 120 行)。
      • 自动重连:映射保持期间,对端连接失败或中断会按指数退避(1s 起步、30s 上限)自动重连,重连期间卡片显示「连接中」、失败时显示「连接失败」、恢复后显示「已连接」;关闭映射即停止重连。
    • ℹ️ 说明:手机端当前为纯接收端(无需安装 App,扫码即用);曾有的「手机当无线触控板反向遥控」界面已随交互重构移除,其遗留接口(/api/peers/control、/api/mapping/mode、/api/inbound*、/api/outbound*)与整套出站设备管理子系统已一并清理。
  • 智能网卡与 IP 路由解析:
    • 采用操作系统路由探测(OS Routing Table Resolution)自动定位真实物理出网网卡,主 IP 选择优先物理网卡,并把 VMware / VirtualBox / WSL / Hyper-V / Docker 等虚拟网卡标记为「虚拟」(列表仍可见、可手动选择)。
    • 支持 -ip 手动指定对外广播/访问用的局域网 IP(监听始终为 :port 全接口,不改绑定地址)。
  • 秒级设备发现与稳定在线状态:
    • 节点启动时立即突发广播(0/400/800ms 三连发,通常 1 秒内全网可感知,不再等满一个心跳周期),并向每个可广播网段(含虚拟网卡网段)发送定向广播,多网卡/虚拟机环境也能可靠互发现;
    • 手机/浏览器接入按来源归并(刷新页面不产生重复条目),断开后快速显示离线:浏览器/手机接入约 5 秒内、自动发现的对端约 7–9 秒内;
    • 手机或另一台电脑打开控制台时,设备列表不会显示它自己(按查看者过滤)。
  • 设备改名跨重启持久化:
    • 本机名称与对端备注保存在本地配置文件(默认用户配置目录下 AnyDevice/config.json,可用环境变量 ANY_DEVICE_CONFIG 指定其他路径),重启不再丢失;
    • 对端备注优先于对端广播名显示,且不会被后续发现心跳覆盖。
  • 按客户端解码能力自适应(Opus ↔ float32 PCM):
    • 对端音频默认传 Opus(码率随发送端负载自适应:平衡档 128kbps / 高负载档 96kbps / 空闲音质档 160kbps,带宽约为 float32 PCM 的 1/24);
    • 本机 UI 客户端若没有 WebCodecs AudioDecoder(macOS Wails 窗口的 WKWebView、Safari),服务端在转发对端音频时自动解码成 float32 PCM 再下发,原生窗口内播放不会因浏览器内核缺解码器而无声;
    • 有解码能力的客户端(Chrome/Edge/WebView2)仍收 Opus,局域网带宽不受影响(/api/status 的 audio_pcm_clients 可查看当前声明走 PCM 的客户端数);
    • 设备卡片上的「接收码率」是对端推流到本机的真实网络字节率(服务端按对端逐条统计,/api/peers 的 mapping.rx_*_kbps,不同对端互不混淆):Opus 约 16 KB/s,旧版对端 PCM 约 350–380 KB/s;本机把 Opus 解码成 PCM 播放的部分不计入该数字,所以原生窗口与浏览器看到的是同一个网络码率。
  • 延迟 / 音质 / 性能三者自适应(不牺牲其中一项换另一项):
    • 播放端自适应抖动缓冲:环形缓冲的预缓冲目标不再固定 100ms,而是 40–200ms 自适应——初始 60ms(低延迟起步),发生欠载(缓冲被抽空)立即 +30ms 并重新预缓冲(先保住不断音),稳定运行满 5s 再每次 -5ms 逐步压低延迟;目标不会越过 [40, 200] 边界。
    • 发送端编码参数自适应(internal/audio/adaptive.go):默认平衡档 128kbps / 复杂度 5;编码队列积压(≥4 帧)、丢帧或「采集→编码完成」延迟连续两次采样偏高(≥35ms)时降档到 96kbps / 复杂度 3(优先保延迟与其它程序性能);持续低负载(≤28ms 且无积压/丢帧)15s 后升档到 160kbps / 复杂度 7(音质优先);切换带 8s 冷却,避免高负载抖动导致参数横跳。Opus 帧长仍为 20ms、采集设备周期未动——自适应用来平衡 CPU 与音质,不用帧长换延迟。
    • 发送端 /api/status 新增 sys_audio_bitrate / sys_audio_complexity / sys_audio_adaptive_level / sys_audio_dropped(及 mic_ 同名)反映当前编码参数、自适应档位与累计丢帧;对端卡片的延迟分项里会显示「对端编码 128kbps · 复杂度 5 · 自适应档 平衡」(旧版对端无该行)。
    • 旧版兼容:audio_stats 新增 bitrate/complexity/level 字段对旧前端安全(未知字段忽略);旧版对端不上报时前端按「无编码信息」处理(以 bitrate 是否存在门控,level 缺省不误判为省 CPU 档)。
  • 按需订阅,空闲零空转(真·按需启停):
    • 本机 UI 窗口默认不订阅音频/鼠标/键盘流,只有真正开启映射时才通过 set_mapping 动态订阅;
    • 无人订阅时不打开音频设备、不安装系统级输入钩子:应用启动只做设备枚举与服务监听,采集引擎与 WH_MOUSE_LL/WH_KEYBOARD_LL(macOS CGEventTap)在第一个订阅到达时才启动,订阅归零并超过宽限期(音频 8s、键鼠 5s)后自动停止/卸载;
    • 系统声与麦克风分开订阅:只映射系统声时不会同时打开麦克风采集(Windows 采集 APO/降噪处理会白耗 CPU,麦克风常驻采集也是隐私问题);旧版对端仍按 audio 并集语义兼容;
    • 「本机共享」开关真正门控采集:关闭系统声/麦克风/鼠标/键盘共享后,即使仍有对端订阅也会立即停止对应采集/卸载钩子(此前该开关只改发现广播);
    • Opus 编码参数按负载自适应(默认平衡档 128kbps/复杂度 5,高负载降 96kbps/复杂度 3、空闲升 160kbps/复杂度 7,见上一条);音频采集线程保持 miniaudio 默认优先级——实测降优先级对游戏帧率几乎无感,却可能在 CPU 满载时导致采集 overrun(断音),收益/风险不成比例;
    • 诊断:/api/status 的 sys_audio_engine/mic_audio_engine/mouse_capture/keyboard_capture 直接反映各采集引擎与钩子的运行状态,无人订阅时应全为 false;日志会输出「无订阅者,停止…采集/卸载…钩子(空闲零空转)」。
  • 纯系统原生驱动(事件驱动捕获):
    • 音频:Windows WASAPI Loopback / macOS CoreAudio / Linux(miniaudio:PulseAudio/ALSA;PipeWire 环境经其兼容层)。
    • macOS 采集系统声需先安装虚拟回环设备(BlackHole / Soundflower / Loopback Audio 等,按设备名自动识别);未安装时系统声不可用——只提示、不会改采麦克风(可选 ANY_DEVICE_TEST_TONE=1 生成调试占位音)。
    • 鼠标/键盘捕获参照 Deskflow 的事件驱动模型:Windows 低级钩子(WH_MOUSE_LL/WH_KEYBOARD_LL)、macOS CGEventTap(只听模式),实时捕获移动、按键、滚轮,未授权时自动回退轮询模式;
    • 注入采用现代 API:Windows SendInput、macOS CGEventPost(字符键附带 Unicode 直通、修饰键状态实时跟踪);注入事件自带标记并在捕获钩子中过滤,杜绝捕获/注入回环。
    • 输入鲁棒性与防卡键保障:
      • 小键盘支持:覆盖数字小键盘(Numpad 0-9、加减乘除、小数点、小键盘回车与 NumLock),Windows 区分小键盘回车与主回车并带扩展键标志注入;
      • 按键释放精准识别:鼠标事件携带具体 button 标识,彻底解决右键/中键抬起因状态复位被误当左键抬起处理导致按键永久卡死的问题;
      • 拖拽与系统钩子自愈:macOS 捕获完整覆盖鼠标拖拽事件(LeftMouseDragged 等)并在模拟端还原拖拽状态;钩子因系统超时/交互暂停时自动重新激活(kCGEventTapDisabledByTimeout 自愈);
      • 断开与切换防卡键保护:对端连接断开或本地映射切换关闭时,自动释放所有被跟踪按下的物理按键、修饰键与鼠标按键,杜绝卡键残留。
  • 全平台零安装接收端:手机/平板端扫码即用,无需安装额外 App。

🔧 排查诊断

环境变量 作用
ANY_DEVICE_AUDIO_DEBUG=1 音频链路诊断:捕获端每 2 秒输出 chunk/字节速率与静音标记;转发端输出帧到达统计
ANY_DEVICE_KB_DEBUG=1 键鼠链路诊断:捕获端事件、执行端收到的事件与键盘模拟执行(均写日志文件)
ANY_DEVICE_TEST_TONE=1 生成 20ms 占位测试音:-mode test-tone 时强制使用;macOS/Linux 未装虚拟回环设备时也会作为回退。默认关闭(不设不出声),供远程端验证音频链路

日志位置:原生窗口没有控制台,日志同时写入文件——macOS .app 形态写入用户配置目录 ~/Library/Application Support/AnyDevice/any_device.log(包内文件受代码签名保护,禁止写入);Windows / 裸二进制写入可执行文件同目录的 any_device.log。界面底部(页脚)会显示日志实际路径。

性能 / 与其他程序共存的自查:

  1. 无人映射时 curl -s http://127.0.0.1:8080/api/status(端口按实际)应看到 sys_audio_engine、mic_audio_engine、mouse_capture、keyboard_capture 全为 false——此时应用不占用音频设备、不安装全局输入钩子;
  2. 开启映射后对应字段变 true,关闭映射后约 5–8 秒回到 false(宽限期用于避免映射开关抖动导致设备反复初始化);
  3. 只映射系统声时 mic_audio_subs 应为 0、mic_audio_engine 应为 false(不采麦克风);
  4. 在「本机共享」里关闭某项后,即使对端仍订阅,对应 *_engine/*_capture 也应为 false(共享开关真正门控采集,而不只是改发现广播);
  5. Windows 上怀疑影响游戏帧率时:任务管理器/Process Explorer 分别看 any_device.exe 与 msedgewebview2.exe(Wails 窗口的 WebView2 子进程)的 CPU/GPU;再按「只开着不映射 → 映射系统声 → 映射键鼠」逐项对比,并用 PresentMon/CapFrameX 对比帧时间而不是只看平均帧率;把窗口最小化再测可区分「窗口/GPU 合成」与「采集/推流」的影响;
  6. 只作为提供方(把本机声音/键鼠共享给别的设备)时,可用 -no-ui 无窗口运行,彻底去掉桌面窗口与 WebView2 的合成开销,再用手机/另一台电脑的浏览器打开 http://<本机IP>:8080 操作。
  7. 远端设备/浏览器连接本机 UI 时,连接动作本身不应启动采集:sys_audio_engine/mic_audio_engine/mouse_capture/keyboard_capture 应保持 false(现代对端立即发送订阅声明;旧版对端最多 500ms 后按默认全订阅兜底,之后才启动)。

音频延迟显示(判断延迟在发送端还是接收端):

  1. 映射音频后,对端卡片的声音行会出现延迟 chip(如 ≈95ms),悬停可见分项: 采集块 + 编码 + 发送(对端上报的发送端耗时)+ 网络(RTT/2) + 播放缓冲 + 输出延迟; 播放缓冲一项会同时给出「实际水位(自适应目标 Yms)」,旁边的 欠载 N 表示接收端环形缓冲被抽空后重新预缓冲的次数。
  2. 判断方法:播放缓冲大 / 欠载数字持续增长 → 延迟主要在接收端(本机负载高、预缓冲与重新预缓冲); 采集块/编码/发送分项大 → 延迟主要在发送端(采集缓冲、Opus 组帧/编码或发送队列); 网络 RTT 大 → 网络问题(Wi-Fi/跨网段)。/api/status 的 sys_audio_chunk_ms/sys_audio_encode_ms/audio_send_ms 是发送端分项的直接来源; 发送端编码档位/码率/丢帧看 sys_audio_adaptive_level/sys_audio_bitrate/sys_audio_dropped(对端卡片悬停也能看到上报值)。
  3. 自适应是否生效:稳定播放 20s 以上,延迟 title 里的「自适应目标」应从 60ms 逐步降到 40ms;若网络/本机偶发卡顿导致欠载,目标会 +30ms 抬高并在稳定后继续下探。
  4. 说明:该数字是分项估算,不是端到端时钟同步测量;旧版对端不上报采集端分项时只显示网络与本机播放侧; 部分 WebView 不提供 outputLatency 时输出延迟按 0 计(总量会偏小)。
  5. 手动添加 IP 的对端会异步拉取其 /api/self 补全能力声明与真实 OS/设备名(此前 audio_format 为空会触发协议防呆、禁用音频映射)。

音频映射无声时的自查:

  1. ANY_DEVICE_AUDIO_DEBUG=1 启动捕获端与播放端——若捕获端显示「捕获已停止增长」或「全零 chunk」比例很高(如 全零 chunk 100%)/速率极低,说明捕获设备上确实没有声音在播放(WASAPI Loopback 只捕获默认输出设备上正在播放的声音;macOS 需先装虚拟回环设备,见核心特性);
  2. 检查捕获端设备卡片显示的系统声/麦克风设备名,确认与你实际听声的设备一致;
  3. macOS 端:音频采集需要「麦克风」授权(按需启停设计下在首次真正开始音频采集时弹窗),键鼠跨端映射需要「系统设置 → 隐私与安全性 → 辅助功能」勾选 AnyDevice.app(未授权时启动有警告提示);
  4. 浏览器场景可在开发者控制台执行 window.__audioDebug() 查看 AudioContext 状态、环形缓冲水位/欠载计数、自适应目标(stats.sys.targetMs)与 AudioWorklet 加载情况。

🚀 极简使用说明

1. 启动程序(电脑端)

直接双击运行:

  • macOS:双击 bin/AnyDevice.app(也可先拖到「应用程序」再启动)。Apple Silicon 用 arm64 包、Intel Mac 用 amd64 包,或直接用 universal 包(一个包通吃,体积约两倍)
  • Windows 台式机:双击运行 any_device.exe
  • Linux:
    • 推荐 AppImage:chmod +x AnyDevice-*.AppImage && ./AnyDevice-*.AppImage —— 运行库已打包在内,无需安装任何依赖。
    • 或用裸二进制 ./any_device-linux-amd64(发布资产名;本地构建产物为 bin/any_device_linux_amd64,体积小),需系统运行库(另需 libpulse0/libasound2/libjack0,桌面发行版通常已随音频栈安装): sudo apt install libgtk-3-0 libwebkit2gtk-4.0-37(Ubuntu 22.04 / Debian 12)。 Fedora:sudo dnf install gtk3 webkit2gtk4.0(Fedora 41/42 仍提供独立的 webkit2gtk4.0 源码包)。 若发行版只提供 WebKitGTK 4.1(如 Ubuntu 24.04),请用 AppImage,或安装 gtk3-devel webkit2gtk4.1-devel 后自行加 webkit2_41 构建标签(go build -tags wails,desktop,production,webkit2_41)。
    • 无图形环境时加 -no-ui 以纯服务模式运行,用手机/浏览器扫码接入。

程序启动后会自动弹出独立桌面应用窗口:顶部为「扫码接入 / 添加设备 / 本机共享」三个入口,下方概览区显示本机名称、通信网卡与实时通道状态,点「扫码接入」即可显示连接二维码与本机局域网地址。

多显示器:窗口由 macOS 按系统默认策略放置,局域网服务与二维码地址不受窗口位于哪块屏幕影响;手机扫码访问的是本机局域网 IP。

2. 手机/另一端连接

拿起手机对着电脑屏幕上的二维码一扫,即可连接。手机上打开页面后,「对端设备」卡片里逐项决定把电脑的哪种能力映射到手机:

  • 系统声音 → 手机当音箱(电脑扬声器原声);
  • 麦克风 → 手机收听电脑麦克风;
  • 物理鼠标 / 物理键盘 → 手机卡片实时显示对端光标坐标与按键遥测。

电脑对电脑时,两台都打开本程序,各自在对方的设备卡片上选择要映射的能力,即可双向同步声音、鼠标与键盘。


🛠️ 常用命令行参数

参数 默认值 说明
-no-ui false 纯后台/命令行模式运行,不弹桌面应用窗口
-port 8080 指定服务端口
-ip "" 启动时指定对外广播/二维码使用的局域网 IP(不改监听地址;运行期切换网卡请在 UI 里操作)
-mode auto 音频捕获模式:当前仅 test-tone 有实际作用(强制占位测试音,仍需 ANY_DEVICE_TEST_TONE=1 才出声);auto/loopback/capture 为兼容保留,无额外行为
-list false 列出本机所有可用音频设备并退出
-list-nics false 列出本机所有网卡与 IP 地址并退出
-device -1 手动指定系统声设备序号(仅 Windows 系统声生效;macOS/Linux 系统声自动找虚拟回环设备、麦克风固定默认设备;-list 查看序号)
-no-qr false 关闭终端二维码打印

💻 编译与构建

UI 使用 Svelte 5 + Vite(源码在 frontend/),构建产物输出到 internal/web/dist/ 并由 go:embed 打进二进制,无需任何运行时前端服务。

# 一键构建(前端 + macOS 原生窗口 .app + Windows 交叉编译)
./scripts/build.sh

# macOS 架构选择(默认 arm64):
MAC_ARCH=amd64 ./scripts/build.sh      # Intel Mac
MAC_ARCH=universal ./scripts/build.sh  # 双架构通吃(体积约两倍)

# Linux AppImage(需 libgtk-3-dev libwebkit2gtk-4.0-dev libopus-dev pkg-config;ImageMagick 可选,缺省时图标直接用原图):
ARCH=amd64 ./scripts/build-appimage.sh
ARCH=arm64 ./scripts/build-appimage.sh

# 只改了 Go 代码、前端未动时:
#   macOS 原生窗口 -> 重新打包 .app(Info.plist 必须随包,裸二进制窗口内
#   WebSocket/麦克风会因缺少 ATS/用途声明而失败):
go build -tags wails,desktop,production \
    -ldflags "-s -w -extldflags '-framework UniformTypeIdentifiers'" \
    -o bin/AnyDevice.app/Contents/MacOS/any_device main.go
codesign -s - -f bin/AnyDevice.app

# 无标签构建只用于快速调试(浏览器 --app 窗口回退,不是发布形态):
go build -o any_device main.go

# Linux 原生窗口(需 libgtk-3-dev libwebkit2gtk-4.0-dev libopus-dev):
go build -tags wails,desktop,production -o any_device_linux_amd64 main.go

macOS 原生窗口必须运行在 .app 包内(AnyDevice.app/Contents/MacOS/any_device);直接把可执行文件拷出包外会丢失 Info.plist,窗口内 WebSocket 会被 ATS 拦截。

依赖打包:音频 Opus 编码在 macOS arm64/amd64 与 Windows x64 使用仓库内 vendored 静态库(third_party/libopus/),.app 与 .exe 静态链接、运行时不需要安装 Homebrew 或 opus;BSD-3-Clause 许可文本会随 .app 放进 Contents/Resources/third_party/ 并在仓库 third_party/libopus/COPYING 保留。Linux 静态链接系统 libopus(构建需 libopus-dev),运行期不再需要 libopus0;但 GTK3/WebKitGTK 官方不提供静态库且 WebKit 的进程模型要求动态加载,故 Linux 包无法做到全静态,运行库仍需安装(见上文启动说明)。

CI 自动构建产物

推送 main 或提交 PR 时,GitHub Actions 会跑完整质量门(gofmt/vet/test/前端检查 + 三平台构建)并上传可下载的安装包(Actions 页面 run 的 Artifacts 区,保留 14 天):

Artifact 内容
AnyDevice_macOS 三个 .app:_arm64(Apple Silicon)/ _amd64(Intel)/ _universal(双架构通吃);均含 Info.plist + 图标 + 许可文本 + ad-hoc 签名
AnyDevice_windows_amd64 any_device.exe(Wails 原生窗口)+ any_device_portable.exe(浏览器壳回退)
AnyDevice_linux_amd64 Linux x86_64 原生窗口二进制(GTK3 + WebKitGTK,需系统运行库)
AnyDevice_linux_arm64 Linux arm64 原生窗口二进制(GTK3 + WebKitGTK,需系统运行库)
AnyDevice_linux_AppImage Linux AppImage(含 GTK/WebKitGTK/opus 运行库,下载即用,约 79 MB)

发布流程

版本号以 git tag 为唯一源(仓库内不维护版本文件),推 tag 即触发 .github/workflows/release.yml:三平台并行构建 → 自动创建 GitHub Release 并附上全部安装包。

# 1. 确保 main 已同步且 CI 全绿
git checkout main && git pull --ff-only

# 2. 打 annotated tag(SemVer:破坏性升 major、新功能升 minor、修复升 patch)
git tag -a v1.2.0 -m "AnyDevice v1.2.0"

# 3. 逐个推送并确认(禁止 git push --tags:超过 3 个 tag 时 GitHub 不产生事件)
git push origin v1.2.0
gh run watch $(gh run list --workflow=release.yml --limit 1 --json databaseId --jq '.[0].databaseId')

Release 产物:macOS 三架构 zip、Windows 双 exe、Linux AppImage + 裸二进制。 带 -rc / -beta 后缀的 tag 会标记为预发布。

手动演练:gh workflow run release.yml(只构建产物、不创建 Release)。

测试

go test ./...                              # 默认测试:含 Opus 编解码往返保真
                                           #(cgo libopus 已静态链接,无需额外 tag)
go test ./internal/audio -run RoundTrip -v  # 只跑往返保真(TestOpusRoundTripFidelity:
                                           #  断言解出正弦的幅度/频率与输入一致;曾因把
                                           #  float32 缓冲按 int16 传入 opus_encode 而破音)

前端开发

cd frontend
bun install        # 安装依赖(包管理器:bun)
bun run dev        # 启动 Vite 开发服务器(默认 5173)
                   # /api 与 /ws 自动代理到本机 8080 的 AnyDevice 服务
bun run build      # 构建产物到 internal/web/dist(随后 go build 即可)

全新检出后若直接 go build,internal/web/dist 只有占位文件,页面为空白——请先执行前端构建(或使用 scripts/build.sh)。

多显示器 / 高 DPI:窗口按 macOS 逻辑坐标渲染(Retina 自动 2x),无需额外配置;窗口出现在哪块屏幕不影响服务监听、局域网地址与扫码连接。

macOS 权限提示:.app 采用 ad-hoc 签名(codesign -s -),每次重新构建后系统签名身份会变化,「辅助功能」授权可能失效——到 系统设置 → 隐私与安全性 → 辅助功能 重新勾选 AnyDevice.app 即可;麦克风授权首次运行时弹窗。

About

跨端双向设备映射中心:把电脑的系统声音、麦克风、鼠标与键盘实时映射到手机/平板/另一台电脑(Go + Wails + Svelte,Opus 低带宽传输)

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages