# sync-trans-client **Repository Path**: panshangqi/sync-trans-client ## Basic Information - **Project Name**: sync-trans-client - **Description**: 同生传译客户端 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-06-13 - **Last Updated**: 2026-07-02 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # sync-trans-client 同声传译-客户端,基于 Electron + Vue,支持腾讯云和火山引擎两种翻译引擎。 ## 架构概览 ``` renderer (Vue) main (Electron) SettingsDrawer ──IPC──> ipc/app.ts │ translator.ts ┌────┴────┐ TencentEngine VolcanoEngine │ │ getAudioArgs (audioDevice.ts) │ ffmpeg (dshow/avfoundation) ``` ## 异常处理与重连机制 翻译引擎在运行时面临三类异常:网络断开、ffmpeg 异常退出、音频输入设备断开。以下是各场景的处理逻辑。 ### 1. 网络断开 **检测方式:** 每 5 秒 (`NET_CHECK_INTERVAL_MS`) 向 `http://www.baidu.com` 发送 HTTP 请求,超时 3 秒判定为网络不可用。 **触发流程:** ``` checkNetwork() 返回 false → handleDisconnect() → cleanup() # 杀掉 ffmpeg,关闭 ws → scheduleReconnect() # 1s 后重连 ``` **日志示例:** ``` [tencent] network check failed, connection lost [tencent] cleaning up [tencent] reconnecting in 1s... ``` ### 2. WebSocket 连接异常 包括:服务端主动断开、DNS 解析失败、TLS 握手失败、会话超时等。 **检测方式:** 监听 `ws.on('close')` 和 `ws.on('error')` 事件。 **触发流程:** ``` ws close/error 事件 → handleDisconnect() → cleanup() → scheduleReconnect() # 1s 后重连 ``` **race condition 防护:** `cleanup()` 中立即调用 `ws.removeAllListeners()` 移除旧 ws 的事件监听,防止旧 ws 延迟关闭时触发二次 cleanup 把新连接的资源清掉。 **未捕获 Promise 防护:** `scheduleReconnect()` 中对 `start()` 调用添加了 `.catch()`,确保 ws 连接失败(如 DNS ENOTFOUND)时 promise 不会 unhandled,并正确触发 cleanup 杀掉已启动的 ffmpeg。 **日志示例:** ``` [volcano] ws closed [volcano] cleaning up [volcano] reconnecting in 1s... ``` ### 3. ffmpeg 异常退出 包括:ffmpeg 进程崩溃、被系统杀死、音频格式不兼容等。 **检测方式:** 监听 `ffmpeg.on('close')` 事件,检查退出码非 0。 **触发流程:** ``` ffmpeg close 事件 (code !== 0) → handleDisconnect() → cleanup() → scheduleReconnect() # 1s 后重连 ``` **日志示例:** ``` [tencent] ffmpeg exited with code 4294967291 [tencent] cleaning up [tencent] reconnecting in 1s... ``` ### 4. ffmpeg 音频超时(无数据) **检测方式:** 每 3 秒检查 `lastAudioTime`,如果超过 10 秒 (`AUDIO_TIMEOUT_MS`) 没有收到 ffmpeg 的音频数据,判定为异常。 **触发流程:** ``` audioTimer 检测到 10s 无数据 → handleDisconnect() → cleanup() → scheduleReconnect() ``` **日志示例:** ``` [tencent] ffmpeg audio timeout (no data for 10s) ``` ### 5. 音频输入设备断开(麦克风拔掉) **检测方式:** 重连时调用 `getAudioArgs()` → `findDshowDevice()` 列举 dshow 设备,如果返回空列表则判定设备不可用。 **触发流程:** ``` 设备拔掉 → ffmpeg 退出 → handleDisconnect() → scheduleReconnect() → start() → getAudioArgs() → findDshowDevice() 返回 null → 抛出 Error("No audio input device found") → catch: deviceMissing = true → handleDisconnect() → scheduleReconnect() 使用 DEVICE_RETRY_DELAY (2s) 重试 ... 循环直到设备插回 ... → findDshowDevice() 找到设备 → 连接成功 → deviceMissing = false ``` **重连策略:** - 正常断连(网络/ws/ffmpeg):固定 **1 秒** 重连 - 设备找不到:固定 **2 秒** 重试检测设备 - 设备恢复后:自动连接成功,重置为 1 秒重连 **日志示例:** ``` [audio] dshow audio devices: [] [audio] no dshow audio device found, microphone may be disconnected [tencent] reconnect failed: No audio input device found, please check microphone connection [tencent] reconnecting in 2s... ... 设备插回 ... [audio] dshow audio devices: ["麦克风 (USB2.0 Device)"] [audio] matched dshow device: 麦克风 (USB2.0 Device) (from label: ...) [tencent] ws connected, waiting handshake [tencent] handshake OK, streaming audio ``` ## 音频设备适配 ### 跨平台设备识别 | 平台 | 采集格式 | 设备检测方式 | 设备名格式 | |------|---------|-------------|-----------| | Windows | dshow | `ffmpeg -f dshow -list_devices true -i dummy` | `麦克风 (USB2.0 Device)` | | macOS | avfoundation | `ffmpeg -f avfoundation -list_devices true -i ""` | `[0] MacBook Pro Microphone` | | Linux | pulse | - | `default` | ### Windows dshow 设备匹配 Electron 渲染进程通过 `navigator.mediaDevices.enumerateDevices()` 获取的设备信息与 ffmpeg dshow 使用的设备名格式不同: - **Chromium deviceId:** `a8f3e2b1c4d5...`(hash) - **Chromium label:** `Default - 麦克风 (USB2.0 Device) (0112:0200)` - **dshow 设备名:** `麦克风 (USB2.0 Device)` 设置中同时保存 `selectedAudioDeviceId`(Chromium hash)和 `selectedAudioDeviceLabel`(Chromium label)。Windows 上始终通过 ffmpeg 列举 dshow 设备列表,用 Chromium label 做模糊匹配(`label.includes(dshowName)`)找到正确的 dshow 设备名。 ## cleanup 时序安全 ### 问题 `cleanup()` 中使用 `setTimeout` 延迟 1 秒关闭旧 ws。重连定时器也是 1 秒。两者时间重叠时: 1. 新 `start()` 执行,重置 `cleaning = false`,创建新 ffmpeg 2. 旧 ws 延迟关闭触发 `close` 事件 → `handleDisconnect()` → `cleanup()` 3. `cleaning` 已被重置为 `false`,cleanup 再次执行,把新 ffmpeg 清掉 ### 解决 `cleanup()` 中立即调用 `ws.removeAllListeners()` 移除旧 ws 的所有事件监听。旧 ws 延迟关闭时不再触发 `handleDisconnect()`,新连接资源不受影响。 ## 常量说明 | 常量 | 值 | 说明 | |------|------|------| | `RECONNECT_DELAY` | 1000ms | 正常断连后重连延迟 | | `DEVICE_RETRY_DELAY` | 2000ms | 设备找不到时重试延迟 | | `AUDIO_TIMEOUT_MS` | 10000ms | ffmpeg 无音频数据超时阈值 | | `NET_CHECK_INTERVAL_MS` | 5000ms | 网络连通性检测间隔 | | `CHUNK_SIZE` | 3200/6400 bytes | 发送给 API 的音频块大小 | ## 默认配置 | 设置项 | 默认值 | 范围 | 说明 | |--------|--------|------|------| | `backgroundColor` | `#00b050` | hex / transparent | 背景色 | | `subtitleWidthPercent` | `85` | 30-100 | 字幕宽度百分比 | | `fontColor` | `#ffffff` | hex | 字体颜色 | | `strokeColor` | `#000000` | hex | 描边颜色 | | `strokeWidth` | `2` | 1-10 | 描边粗细 (px) | | `fontSize` | `36` | 10-200 | 字体大小 (px) | | `zhMaxLines` | `2` | 1-3 | 中文最大行数 | | `enMaxLines` | `2` | 1-3 | 英文最大行数 | | `alwaysOnTop` | `true` | - | 窗口置顶 | | `translationEngine` | `volcano` | tencent / volcano | 翻译引擎 | | `subtitlePositionX` | `50` | 0-100 | 字幕水平位置 (%) | | `subtitlePositionY` | `80` | 0-100 | 字幕垂直位置 (%) | | `subtitleMode` | `realtime` | stable / streaming / realtime | 字幕模式 | | `fontFamilyZh` | (系统默认) | - | 中文字体 | | `fontFamilyEn` | (系统默认) | - | 英文字体 | 配置文件位于 `userData/settings.json`,删除后重启会按以上默认值重新生成。 ## 测试脚本 ```bash # 列出音频设备 node scripts/test-audio.js # 录制 WAV(可直接播放) node scripts/test-audio.js --wav # 录制 raw PCM node scripts/test-audio.js --record # 流式读取(模拟引擎行为) node scripts/test-audio.js --stream # 指定设备和时长 node scripts/test-audio.js --wav --device "麦克风 (USB2.0 Device)" --duration 10 ``` ## Mac安装损坏,因为mac传输文件有签名校验 ``` xattr -cr /Applications/SyncTrans.app ``` ## 版本记录 ### v0.1.24 - 修复 Windows 10 启动后菜单无法点击的问题(透明窗口激活修复) - 修复 Windows 上可重复打开多个客户端实例的问题(单实例锁) - 固定 userData 目录为 sync-trans,避免 dev/打包路径不一致导致激活数据丢失 - Windows 上鼠标靠近屏幕右边缘自动激活菜单并聚焦窗口 ### v0.1.23 - 非全屏时窗口边缘显示绿色边框 - 新增字幕拉伸配置(20%~300%),适配投屏不同分辨率 ### v0.1.22 - 修复置顶层级不够,字幕被其他窗口遮挡的问题(使用 screen-saver 级别) - 修复 Windows 上透明无边框窗口全屏/退出全屏不生效的问题 - Windows 全屏覆盖系统任务栏,退出全屏后窗口居中占屏幕 90% - 默认不全屏启动,点击按钮才全屏 ### v0.1.21 - 支持背景透明模式,macOS 鼠标穿透 - 无边框窗口,启动全屏 - 右侧工具栏始终显示,空闲时半透明(透明度可设置) - 退出按钮及自定义确认弹窗 - 字幕 10s 无更新自动消失 ### v0.1.19 - 热词配置(腾讯云 / 火山引擎) - 火山引擎支持热词、替换词、术语三种配置 - 支持 TXT 文件批量导入 - 腾讯云热词上限 120,火山引擎每类上限 200 ### v0.1.18 - 初版发布 - 支持腾讯云、火山引擎两种翻译引擎 - 流式 / 逐句 / 低延迟三种字幕模式 - 字幕样式配置(颜色、描边、字体、位置) - 断网 / 设备断开自动重连