skaka/sony-headphones-linux

GitHub: skaka/sony-headphones-linux

通过逆向工程的蓝牙协议,在 Linux 上实现对 Sony WH-CH720N 耳机的无官方应用控制,支持降噪、均衡器和媒体管理。

Stars: 0 | Forks: 0

# 在 Linux 上控制 Sony WH-CH720N 耳机 一个 Python 程序,旨在通过 Bluetooth 完全控制 Linux 上的 **Sony WH-CH720N** 耳机, 无需任何官方应用。该协议是直接在设备上进行 **Reverse Engineering** 得出的。 ## 支持的功能 | 功能 | 状态 | 命令 | |--------|--------|-------| | 🔋 电池电量 | ✅ 已确认 | `battery` | | ℹ️ 固件 + MAC + 设备信息 | ✅ 已确认 | `info` | | 🎚️ 均衡器 Equalizer(6 频段) | ✅ 已确认 | `eq` / `eq-get` / `eq-flat` | | 🔇 降噪 Noise Cancelling | ✅ 已确认 | `nc` | | 🌳 环境声 Ambient Sound | ✅ 已确认 | `ambient` | | 📊 支持的特性表 | ✅ 已确认 | (在 `info` 中) | | ⏯️ 播放/暂停 Firefox & Chrome 媒体 | ✅ 已确认 | `media-*` | | 🖥️ 图形界面 | ✅ | `python3 gui.py` | | 🔗 将耳机按钮绑定到系统命令 | ✅ | `python3 agent.py` | | ⏹️ 完全关闭 ANC (Off) | ⚠️ 协议未暴露 | 使用耳机按钮 | | 🔀 可写入开关 `@0xe6` | ✅ 写入已确认 · 功能未确认 | `raw e8 00 00/01` | | 🔊 DSEE / 自动关闭 (`0x78/0x74/0xe2`) | 🔬 只读(调整功能研究中) | `raw 78 00` | ## 安装 ``` # 无需对耳机的系统要求(仅限 Python 标准库) # 仅用于控制浏览器媒体: sudo apt install python3-dbus # 确保耳机已配对并连接 bluetoothctl devices ``` ## 使用方法 ``` python3 main.py discover # اكتشاف السماعة والقناة python3 main.py info # كل المعلومات python3 main.py battery # البطارية python3 main.py nc # تفعيل إلغاء الضوضاء python3 main.py ambient # الصوت المحيطي python3 main.py status # الوضع الحالي python3 main.py eq-get # قراءة المعادل python3 main.py eq 14 12 10 10 8 6 # 6 باندات (0..20، 10=وسط) python3 main.py eq-flat # تسطيح المعادل python3 main.py media-pause # إيقاف ميديا المتصفحات python3 main.py media-play # تشغيل python3 main.py media-toggle # تبديل python3 main.py media-list # عرض المشغّلات وحالتها python3 main.py raw 22 00 # إرسال أمر خام (hex) للتجربة python3 main.py listen # طباعة الإطارات الواردة (لعكس البروتوكول) ``` ### 图形界面 (GUI) ``` python3 gui.py ``` 使用纯 tkinter 构建的**现代化**界面(扁平暗色主题、卡片、彩色按钮),无需额外依赖: - **默认英语**,带有切换到**阿拉伯语**的按钮(右上角)。 - 完整的阿拉伯语支持:通过 `arabic.py` 实现**字母连接(词形变化)+ RTL(从右向左)布局** — 因为 Tk 不支持这些功能(字母会断开显示),所以我们将文本转换为连写形式, 并在视觉上进行反转,同时使用 Noto Naskh Arabic 字体。 - 显示电池电量,带有当前模式高亮的声音模式按钮,均衡器推子(6 频段)附带 快速预设,以及浏览器媒体控制按钮。 - 在独立线程中保持持久连接 + **实时 ANC 指示器**,在按下耳机按钮时会更新。 ### 将耳机按钮绑定到系统命令 (agent) ``` python3 agent.py ``` 监控耳机通知 (NTFY) 并触发相关操作的服务器。默认行为: - 按下耳机按钮切换到**环境声** → 暂停浏览器媒体播放。 - 切回**降噪**模式 → 恢复媒体播放。 修改 `agent.py` 顶部的 `BINDINGS` 字典,即可将任何事件绑定到任何系统 shell 命令,例如: ``` BINDINGS = { "ncasm:ambient": run_shell("notify-send 'الصوت المحيطي'"), "battery:low": run_shell("notify-send 'بطارية السماعة منخفضة'"), } ``` ### 系统托盘图标 + 自动启动 ``` python3 tray.py # تشغيل الأيقونة يدويًا bash install_autostart.sh --start # تثبيت (تعمل عند كل دخول) + تشغيل الآن bash install_autostart.sh --uninstall # إزالة التشغيل التلقائي وإيقاف الأيقونة ``` 时钟旁边的耳机图标,作为常驻服务运行: - **耳机连接到 Bluetooth 时自动连接**(在尝试前检查 BlueZ 状态 — 避免导致适配器过载的重复尝试)。 - 恢复会话设置(均衡器/模式),并将耳机按钮绑定到浏览器的媒体播放/暂停控制。 - 菜单功能:状态与电池电量、NC/Ambient、媒体控制、**打开设置窗口**(会暂时释放 连接随后恢复)以及退出。菜单显示已保存的设置语言。 ### 在会话之间保存设置 语言、均衡器和模式会自动保存在 `~/.config/sony-ch720n/config.json` 中, 并在下次连接耳机时恢复。 ## 发现的协议(WH-CH720N,固件 1.0.8) ### 传输层 - **Bluetooth Classic RFCOMM**,通道 **18**。 - 通过官方的 Sony MDR 服务 UUID 进行识别: `956c7b26-d49a-4ba8-b03f-b17d393cb6e2` ### 帧格式 ``` [0x3E] [DATA_TYPE] [SEQ] [LEN: 4 bytes BE] [PAYLOAD...] [CHECKSUM] [0x3C] ``` - `0x3E` 帧头,`0x3C` 帧尾,`0x3D` 转义字符 (escape)。 - 命令的 `DATA_TYPE` = **`0x0C`**(已在 CH720N 上确认),ACK 的 = `0x01`。 - `CHECKSUM` = (DATA_TYPE + SEQ + LEN + PAYLOAD) 之和 mod 256。 - 特殊字节 `3E/3C/3D` → 替换为 `0x3D` + `(byte & 0xEF)`。 ### ACK 处理(非常重要) 每个 DATA 帧都必须收到一个带有**反转**序列号的 ACK:`ack_seq = received_seq XOR 1`。 如果没有收到,耳机将会重传并随后断开连接。 ### 命令代码映射(通过探测发现) payload 中的第一个字节 = 命令代码。返回的响应通常 = 命令代码 + 1。 | GET | RET | 功能 | 响应示例 | |-----|-----|--------|---------| | `0x00` | `0x01` | 协议信息 | `01 00 03 00 10 02 00 00` | | `0x02` | `0x03` | MAC 地址(文本) | `03 00 23 11 "AA:BB:CC:..."` | | `0x04` | `0x05` | 固件版本 | `05 02 05 "1.0.8"` | | `0x06` | `0x07` | 支持的特性表(23 项功能) | `07 00 17 ...` | | `0x12` | `0x13` | 设备信息 (JSON) | `{"type":"CS",...}` | | `0x22` | `0x23` | 电池电量 | `23 00 64 00` (=100%) | | `0x50` | `0x51` | EQ 预设列表 | 12 preset | | `0x52` | `0x53` | EQ 状态 | `53 00 00` | | `0x56` | `0x57` | 当前 EQ 频段 | `57 00 00 06 0a×6` | | `0x58` | `0x59` | **设置 EQ** | `58 00 a0 06 <6 bands>` | | `0x5a` | `0x5b` | EQ 频率 (Hz) | 400/1k/2.5k/6.3k | | `0x66` | `0x67` | NC/ASM 状态 | `67 17 01 00 01 00 14` | | `0x68` | — | **设置 NC/ASM** | 见下文 | | `0x78` | `0x79` | 开关 (DSEE?) 值为 1 — 只读 | `79 00 01` | | `0x70/0x74` | — | 多个值(编解码器/设置?) | 🔬 | | `0xe6` | `0xe7` | **可写入开关** (SET=`0xe8`, NTFY=`0xe9`) — 功能未确认(听觉效果微弱;通过对比 Sony 应用命名) | `e7 00 01` | | `0xe2` | `0xe3` | 值为 0 的只读开关 | `e3 00 00` | | `0x69` | — | **按下 NC/Ambient 按钮时的 NTFY** (agent 使用) | `69 17 ...` | ### NC/ASM (subtype 0x17 — 唯一支持的子类型) ``` Noise Cancelling : 68 17 01 01 00 00 14 Ambient Sound : 68 17 01 00 01 00 14 ``` 结构:`[effect, ncSel, asmSel, voice, level]`。第二个字节(选择器)最重要: `01` = NC,`00` = Ambient。级别固定为 `0x14`(CH720N 没有环境声音量滑块)。 通过此子类型**无法完全关闭 (OFF)** — 耳机始终返回 `effect=01`。 ### EQ ``` 58 00 06 ``` 每个频段范围为 0..20(10=中性)。频段:Clear Bass, 400Hz, 1kHz, 2.5kHz, 6.3kHz, 16kHz。 专用的插槽 `0xA0`/`0xA1`/`0xA2` 可以存储任意值。 ## 项目结构 ``` main.py واجهة سطر الأوامر (CLI) gui.py الواجهة الرسومية (tkinter) — ثنائية اللغة + حفظ الإعدادات agent.py خادم ربط أزرار السماعة بأوامر النظام tray.py أيقونة شريط المهام (AppIndicator) + اتصال تلقائي install_autostart.sh تثبيت/إزالة تشغيل الأيقونة تلقائيًا عند الدخول sony_headset/ protocol.py بناء/فك الإطارات + checksum + escape (مغطّى باختبارات) transport.py اكتشاف + اتصال RFCOMM مع retry + فحص حالة البلوتوث commands.py أكواد الأوامر + بناء/فك الـ payloads client.py عميل عالي المستوى (handshake/ACK/الميزات) media.py تحكم ميديا المتصفحات عبر MPRIS/D-Bus arabic.py تشكيل عربي + RTL خالص بـ Python (لعرض العربية في tkinter) config.py حفظ/تحميل إعدادات الجلسة (~/.config/sony-ch720n/config.json) tools/ probe_features.py أداة جس أكواد الأوامر (لاكتشاف خصائص جديدة) probe_toggles.py أداة اختبار كتابة المفاتيح (toggles) tests/ test_protocol.py اختبارات طبقة البروتوكول (9 اختبارات) ``` ## 扩展新功能 ``` # 1) 发现返回的 codes: python3 tools/probe_features.py # 2) 发送 raw command 并读取响应: python3 main.py raw 78 00 # 3) 监控耳机的 frames(例如按下其按钮时): python3 main.py listen --seconds 20 ``` ## 注意事项与限制 - 耳机同一时间仅允许**一个** MDR 连接。如果提示 `Device or resource busy` 请等待一秒钟后重试(已内置自动重试机制)。 - 每次仅运行一个命令;过快地连续运行命令可能会与通道释放发生冲突。 - 这些代码仅在 CH720N 型号 / 固件 1.0.8 上验证过;其他型号可能会有所不同 (对于较新的型号,请尝试 `DATA_TYPE = 0x0E`)。
标签:Linux工具, Python, 云资产清单, 无后门, 硬件适配, 端口探测, 系统工具, 蓝牙控制, 逆向工具, 逆向工程, 音频控制