协议全景解析)
LibrePods 逆向工程指南AACP 操作码Opcode协议全景解析【免费下载链接】librepodsAirPods liberated from Apples ecosystem.项目地址: https://gitcode.com/gh_mirrors/al/librepodsAACPApple Accessory Communication Protocol苹果配件通信协议是 AirPods 与主机设备之间传输状态与指令的底层协议。本指南以仓库中的 docs/opcodes.md 为核心系统梳理 AACP 全部已知操作码的取值、方向与数据格式并结合 LibrePods 在 AndroidAACPManager.kt与 Linuxairpods_packets.h双端的具体实现进行源码级印证。读完本文你将掌握 AACP 报文的字节结构、各操作码的用途与收发方向以及如何构造/解析一条可用的 AACP 数据包为在非苹果设备上驱动 AirPods 打下协议基础。AACP 操作码协议基础与报文结构AACPApple Accessory Communication Protocol通过一系列**操作码opcode来定义不同类型的动作与命令。每个操作码都是一个16 位整数即两个字节用于指明正在执行的操作类型并以小端序little-endian**嵌入 AACP 报文结构中传输。一条 AACP 报文的基本格式为04 00 04 00 [opcode, little endian] [data]前 4 字节04 00 04 00是固定的报文头header随后 2 字节是操作码小端序即09 00表示 0x0009其余为操作码对应的数据负载。该头结构在 LibrePods 的两端实现中均有直接对应Android 端在 Packets.kt 中定义了PREFIX byteArrayOf(0x04, 0x00, 0x04, 0x00)并在 AACPManager.kt 中定义了HEADER_BYTES byteArrayOf(0x04, 0x00, 0x04, 0x00)Linux 端则在 BasicControlCommand.hpp 中定义了HEADER QByteArray::fromHex(040004000900)含控制命令操作码 0x0009。receivePacket在解析入站数据时也会首先校验04000400前缀不符合的报文会被直接丢弃见 AACPManager.kt。完整操作码表下表完整列出 docs/opcodes.md 中记录的已知操作码。其中Destination一列表示报文的方向Accessory表示由主机发送给 AirPods写入方向Host表示由 AirPods 发送给主机通知/上报方向Both表示双向均可使用。Opcode (Hex)DestinationDescription0x0001AccessoryUnknown0x0004HostBattery report0x0006HostEar detection0x0009BothControl commands0x000DAccessoryAudio source req0x000EHostAudio source resp0x000FAccessoryNotification register0x0010AccessorySmart routing relay0x0011HostSmart routing response0x0014AccessorySend connected device MAC0x0017BothMultiple things - undocumented0x0019HostStem press0x001BAccessoryTimestamp0x001DHostDevice Information0x001EAccessoryRename device0x0022AccessoryUnknown0x0029AccessoryHost capabilities (?)0x002BHostPaired devices (?)0x002DAccessoryList of connected dev. req0x002EHostList of connected devices0x0030AccessoryBLE keys req0x0031HostBLE keys response0x004BHostConversation awareness0x004DAccessoryHost capabilities0x004FBothInformation req/res (doesnt work, even with apples DID)0x0053BothEQ data从表格可以观察到几个明显特征方向不对称多数状态上报类操作码电池、入耳检测、按压、设备信息是Host方向即 AirPods 主动推送给主机而配置类操作码通知注册、密钥请求、能力宣告多为Accessory方向。仍有未知区域0x0001、0x0022用途未知0x0017属于多重用途但未文档化0x0029、0x002B带问号表示尚未完全确认0x004F则被标注为即使使用 Apple 的 DID 也无法工作。专用操作码对应专用功能例如0x0030/0x0031是配对用的 BLE 邻近密钥proximity keys请求/响应0x0053承载 EQ耳机补偿/Headphone Accommodation数据。在 LibrePods 的 Android 实现中绝大多数操作码都能在AACPManager的Opcodes对象中找到一一对应的常量定义例如BATTERY_INFO 0x04、EAR_DETECTION 0x06、CONTROL_COMMAND 0x09、REQUEST_NOTIFICATIONS 0x0F、CONVERSATION_AWARENESS 0x4B、INFORMATION 0x1D、HEADTRACKING 0x17、PROXIMITY_KEYS_REQ/RSP 0x30/0x31、HEADPHONE_ACCOMMODATION 0x53等见 AACPManager.kt并在receivePacket的分发逻辑中按操作码进入不同的解析分支。操作码 0x0009控制命令Control Commands0x0009是 AACP 中最重要、使用最频繁的双向操作码用于读取和修改 AirPods 的各类配置降噪模式、入耳检测、按键行为、助听功能等。它在 docs/control_commands.md 中有完整定义核心要点如下。报文格式固定长度控制命令的长度固定为 7 字节 4 字节报文头因此完整报文为04 00 04 00 09 00 [identifier] [data1] [data2] [data3] [data4]09 00是操作码 0x0009 的小端表示[identifier]是命令标识符1 字节决定操作的是哪个配置项[data1]~[data4]是数据区4 字节未使用的字节一律填0x00。根据 docs/control_commands.md 的观察结论data3和data4从未被使用始终为零data2通常用于双耳配置可以不同的场景例如左右耳的长按模式或者同一功能存在两个状态变量的场景例如助听功能的 enrolled 与 enabled 两个状态。Android 端的构造逻辑与之完全吻合createControlCommandPacket 固定分配 7 字节负载第 2 字节放 identifier第 3~6 字节最多拷贝 4 字节数据而 ControlCommand.fromByteArray 在解析入站控制命令时会先跳过连续的04 00 04 00头再校验操作码是否为 0x09取data[offset2]为 identifier、data[offset3..offset6]为值并去除尾部连续的 0x00空值会归一化为0x00。Linux 端的 createCommand 也按HEADER(040004000900) identifier data1..data4的 7 字节负载构造。命令标识符全集docs/control_commands.md 中列出了完整的命令标识符映射下表全部继承供报文构造与解析时对照Command identifierDescription0x01Mic Mode0x05Button Send Mode0x06Owns connection0x0AEar Detection0x12VoiceTrigger for Siri0x14SingleClickMode0x15DoubleClickMode0x16ClickHoldMode0x17DoubleClickInterval0x18ClickHoldInterval0x1AListeningModeConfigs0x1BOneBudANCMode0x1CCrownRotationDirection0x0DListeningMode0x1EAutoAnswerMode0x1FChime Volume0x20Connect Automatically0x23VolumeSwipeInterval0x24Call Management Config0x25VolumeSwipeMode0x26Adaptive Volume Config0x27Software Mute config0x28Conversation Detect config0x29SSL0x2CHearing Aid Enrolled and Hearing Aid Enabled0x2EAutoANC Strength0x2FHPS Gain Swipe0x30HRM enable/disable state0x31In Case Tone config0x32Siri Multitone config0x33Hearing Assist config0x34Allow Off Option for Listening Mode config0x35Sleep Detection config0x36Allow Auto Connect0x37PPE Toggle config0x38Personal Protective Equipment Cap Level config0x39Raw Gestures config0x3ATemporary Pairing Config0x3BDynamic End of Charge config0x3CSystem Siri message config0x3DHearing Aid Generic config0x3EUplink EQ Bud config0x3FUplink EQ Source config0x40In Case Tone Volume0x41Disable Button Input configAndroid 端将其中大部分定义成了枚举ControlCommandIdentifiers见 AACPManager.kt并提供了MIC_MODE(0x01)、CLICK_HOLD_MODE(0x16)、LISTENING_MODE(0x0D)、HEARING_AID(0x2C)、STEM_CONFIG(0x39)等常量与文档表格一一对应。常用命令的取值说明control_commands.md 对部分命令给出了已确认的取值区间以下是使用频率最高的几组0x0D - ListeningMode聆听模式单字节。1 Off2 Noise Cancellation3 Transparency4 Adaptive。这也是 LibrePods 两端都深度实现的一个命令Android 端Packets.kt的Enums定义了NOISE_CANCELLATION(byteArrayOf(0x0d))Linux 端 airpods_packets.h 用ControlCommand::createCommand(0x0D, 0x01..0x04)构造 Off / Noise Cancellation / Transparency / Adaptive 四种模式报文并提供了parseMode反向解析。0x1A - ListeningModeConfigs单字节位掩码Off 0x01ANC 0x02Transparency 0x04Adaptive 0x08。因为是从当前状态增量切换docs/AAP Definitions.md 记录了大量基于前一状态的切换包例如04 00 04 00 09 00 1A 0F 00 00 00从 Off/ANC/透明三态全开基础上切换等说明该配置是读旧值、算新值式的。0x16 - ClickHoldMode长按模式两字节第一个字节为右耳、第二个字节为左耳。0x01 Noise control0x05 Siri。0x17 / 0x18 - DoubleClickInterval / ClickHoldInterval0x00 Default0x01 Slower0x02 Slowest。0x2C - Hearing Aid助听功能两字节第一个字节 enrolled是否已注册听力档案第二个字节 enabled是否启用。0x01表示启用、0x02表示禁用。Linux 端 HearingAid 用createCommand(0x2C, 0x01, 0x01)/createCommand(0x2C, 0x02, 0x02)构造启用/禁用报文并实现了同时判断两个字节的状态解析。0x2E - AutoANC Strength0 到 100 的连续取值见 docs/AAP Definitions.md 中 Adaptive Audio Noise 一节0 表示放行最多噪声100 表示过滤最多噪声。Linux 端 AdaptiveNoise 用HEADER(0400040009002E) level 000000构造报文。0x2F / 0x23 / 0x25 - 音量滑动相关0x23VolumeSwipeInterval 取值0x00Default、0x01Longer、0x02Longest0x25VolumeSwipeMode 与0x26Adaptive Volume Config 均为0x01enabled、0x02disabled。0x39 - Raw Gestures config单字节位掩码单击 0x01双击 0x02三击 0x04长按 0x08。Android 端sendStemConfigPacket正是按这一位掩码把四个布尔参数拼成一个字节后发送见 AACPManager.kt。0x3A - Temporary Pairing Config0x01 Temporary0x02 Permanent。0x1F Chime Volume / 0x40 In Case Tone Volume / 0x2E AutoANC Strength取值范围 0~100。其余命令如0x05Button Send Mode、0x06Owns connection、0x29SSL、0x30HRM 状态等取值区间尚未完全确认原文档明确建议可以自行构造报文发送实验来探测未知取值。状态上报类操作码AirPods → Host以下操作码由 AirPods 主动上报是 LibrePods 驱动 UI 刷新的数据来源。0x0004 - 电池报告Battery report电池报文在 docs/AAP Definitions.md 中格式如下04 00 04 00 04 00 [battery count] ([component] 01 [level] [status] 01) × battery count组件字节值Case 08Left 04Right 02状态字节值Charging 01Discharging 02Disconnected 04。实测示例AirPods Pro 204 00 04 00 04 00 03 02 01 64 02 01 04 01 63 01 01 08 01 11 02 01对应含义3 个电池组件左耳 100%、Discharging右耳 99%、Charging充电盒 17%、Discharging。Android 端 Packets.kt 的BatteryNotification用040004000400前缀与 22 字节长度来识别电池报文并按data[7]组件、data[9]电量、data[10]状态的三元组解析左耳、右耳与充电盒数据组件/状态枚举BatteryComponent.LEFT 4、RIGHT 2、CASE 8CHARGING 1、NOT_CHARGING 2、DISCONNECTED 4与协议定义完全一致。0x0006 - 入耳检测Ear detection格式04 00 04 00 06 00 [primary pod] [secondary pod]两个字节分别表示主、副耳机的佩戴状态In Ear 00Out of Ear 01In Case 02。注意主耳机被取出后麦克风归属会切换副耳机成为新主耳机并再次发送报文。Android 端AirPodsNotifications.EarDetection用PREFIX 0x06作为前缀、8 字节长度判定该报文并把data[6]、data[7]作为左右耳状态保存见 Packets.kt。0x0017 - 头部追踪未文档化多重用途0x0017在操作码表中被标注为多重用途 - 未文档化但在 LibrePods 中它承担了**头部追踪Head Tracking**的启停与传感器数据流Android 端HEADTRACKING 0x17createStartHeadTrackingPacket/createStopHeadTrackingPacket分别构造启动与停止报文见 AACPManager.ktisHeadTrackingData则用04 00 04 00 17 00 ...前缀及第 10 字节0x44/0x45识别追踪数据帧见 Packets.kt。启动报文示例docs/AAP Definitions.md04 00 04 00 17 00 00 00 10 00 10 00 08 A1 02 42 0B 08 0E 10 02 1A 05 01 40 9C 00 000x0019 - 按压反馈Stem pressAirPods 通过0x0019上报杆部按压事件。Android 端定义了StemPressTypeSINGLE_PRESS 0x05、DOUBLE_PRESS 0x06、TRIPLE_PRESS 0x07、LONG_PRESS 0x08与StemPressBudTypeLEFT 0x01、RIGHT 0x02parseStemPressResponse要求报文第 4 字节必须是 0x19并从第 6、7 字节分别解析按压类型与耳别见 AACPManager.kt。0x001D - 设备信息Device Information设备信息报文由 AirPods 在连接建立后主动发送给主机无法由主机请求。数据是一串以0x00null分隔的 UTF-8 字符串字段顺序为详见 docs/device-info.mdName设备名Model number型号Manufacturer制造商恒为 Apple Inc.Serial number序列号Version 1Version 2Hardware revision硬件修订实测为1.0.0Updater app version升级器应用版本实测为com.apple.accessory.updater.app.71Serial number (Left Bud)左耳序列号Serial number (Right Bud)右耳序列号Version一个数值型版本实测为8454371其余少量未知字节Android 端parseInformationPacket正是按跳过 0x00、提取下一个非空串的方式逐个解析这些字段并映射到AirPodsInformation数据类name、modelNumber、manufacturer、serialNumber、version1/2、hardwareRevision、updaterIdentifier、leftSerialNumber、rightSerialNumber、version3见 AACPManager.kt 与 AACPManager.kt。0x002B / 0x002E - 已配对设备 / 已连接设备列表0x002BPaired devices带问号未完全确认与0x002EList of connected devices用于多设备TiPi即To iPhone/other device场景。0x002E的响应由parseConnectedDevicesResponse解析第 8 字节是设备数量其后每 8 字节一组6 字节 MAC 2 字节附加信息见 AACPManager.kt。0x0031 - BLE 密钥响应BLE keys response0x0031响应0x0030的密钥请求用于取回邻近配对所需的加密密钥。parseProximityKeysResponse按 TLV 结构解析第 6 字节为密钥数量随后每组为类型 2 字节长度 保留位 密钥体类型IRK 0x01、ENC_KEY 0x04见 AACPManager.kt。Linux 端MagicPairing命名空间也实现了magicAccIRK16 字节与magicAccEncKey16 字节两个 TLV 块的解析见 airpods_packets.h这些密钥与 BluetoothCryptography.kt 配合用于无苹果设备的邻近配对流程。0x004B - 对话感知Conversation awareness对话感知状态上报格式docs/AAP Definitions.md04 00 04 00 4B 00 02 00 01 [level]level 字节含义01/02 佩戴者开始说话大幅降低音量03 停止说话恢复音量08/09 正常音量中间值表示中间音量级别。另外在请求通知后 AirPods 会只发送一次当前对话感知状态格式为控制命令04 00 04 00 09 00 28 [status] 00 00 00其中0x01为启用、0x02为禁用。Android 端ConversationalAwarenessNotification用前缀04 00 04 00 4B 00 02 00识别并取data[9]为状态见 Packets.ktLinux 端 ConversationalAwareness 也定义了对应的 DATA_HEADER。0x0053 - EQ 数据Headphone Accommodation0x0053双向承载耳机补偿 EQ 数据。Android 端receivePacket中要求报文长度为 140 字节、第 6 字节为0x84随后以 32 字节为单位连续放置 4 组 EQ每组 8 个 little-endian float当前实现只取第一组 8 个浮点作为eqData并读取第 10、11 字节分别表示 media / phone 上的启用状态见 AACPManager.kt。发送方向由sendPhoneMediaEQ实现04 00 04 00 53 00 84 00 02 02 [phone] [media] 4 组共 128 字节 float见 AACPManager.kt。配置下发类操作码Host → Accessory0x000F - 通知注册Notification register此报文是接收 AirPods 各类通知入耳检测、降噪模式、对话感知、电池等的前提。格式04 00 04 00 0F 00 FF FF FF FF实测04 00 04 00 0F 00 FF FF FE FF同样有效。Android 端createRequestNotificationPacket构造的正是0F 00 FF FF FF FF并注释说明第三个字节在入耳检测被禁用时为0xFD且该报文可在 AACP 连接建立后的任意时刻发送不限于握手阶段见 AACPManager.kt。0x0010 / 0x0011 - 智能路由Smart routing0x0010用于主机向 AirPods 发送智能路由中继数据0x0011接收路由响应。Android 端通过0x0010实现了完整的设备间路由控制createMediaInformationPacket上报播放应用、流媒体状态、蓝牙地址与设备名、createHijackRequestPacket抢占音频路由含Hijackv2原因字段、createSmartRoutingShowUIPacket、createAddTiPiDevicePacket等见 AACPManager.kt。响应侧0x0011的解析会从 payload 中提取发送方 MAC并根据btName、iPad、Mac、iPhone、Linux、Android等关键字识别对端设备类型同时识别SetOwnershipToFalse、ShowNearbyUI、ReverseBannerTapped等控制语义见 AACPManager.kt。0x0014 - 发送已连接设备 MAC0x0014由主机发给 AirPods告知其当前连接的设备 MAC 地址。在 docs/opcodes.md 中该操作码方向为 Accessory主机 → 配件与主机宣告自身身份的语义一致。0x001B - 时间戳Timestamp0x001B用于主机向 AirPods 下发时间戳信息具体字段结构在原文档中未展开。0x001E - 重命名设备Rename device操作码表将0x001E标注为重命名设备。值得注意的是当前仓库的实现中重命名使用的是0x1AAndroid 端RENAME 0x1AcreateRenamePacket构造04 00 04 00 1A 00 01 [size] 00 [name]见 AACPManager.ktLinux 端Rename::getPacket同样使用040004001A0001头见 airpods_packets.hdocs/AAP Definitions.md 也记录重命名报文为04 00 04 00 1A 00 01 [size] 00 [name]。这里存在文档表格与实际实现不一致的情况0x001Evs0x1A从源码结构看二者可能对应不同固件版本或不同功能语义具体以实际抓包为准。0x004D - 主机能力Host capabilities0x004D由主机宣告能力。0x0029同样被标注为 Host capabilities?原文档推测二者相关。Android 端SET_FEATURE_FLAGS 0x4DcreateSetFeatureFlagsPacket构造04 00 04 00 4D 00 D7 00 00 00 00 00 00 00见 AACPManager.kt。docs/AAP Definitions.md 指出这类报文用于解锁被苹果按 OS 版本 / Apple Silicon 设备墙掉的功能例如播放音频时的对话感知以及**自适应通透Adaptive Transparency**能力。0x004F - 信息请求/响应不可用0x004F被明确标注为信息请求/响应但不工作——即使使用 Apple 的 DID设备标识也不行。这是文档记录的一个已知失效路径说明并非所有操作码都能在任意设备上生效也提示协议逆向中存在大量探测失败的暗区。0x0053 - EQ 数据发送方向与上文的0x0053上报方向对应主机也可通过该操作码下发 EQ 配置即sendPhoneMediaEQ所实现的Phone / Media 双通道 4 组 8 频段 float结构见 AACPManager.kt。LibrePods 中的协议落地双端实现对照整个操作码体系在 LibrePods 仓库中被落地为可直接复用的模块AndroidKotlin侧操作码常量集中在 AACPManager.kt 的Opcodes对象入站分发在receivePacket按 opcode 走when分支出站构造散落在create*Packet系列函数中最终统一经sendPacket写入 L2CAP socket见 AACPManager.kt控制命令的读写与监听由 ControlCommandRepository.kt 封装setValue发送、getValue/getMap读取当前状态缓存、observe注册回调界面层据此订阅配置变化报文常量头部、设置前缀、降噪前缀等集中在 Packets.kt。LinuxC/Qt侧BasicControlCommand.hpp 提供ControlCommand::createCommand模板化构造函数与parseActive/parseState解析器airpods_packets.h 按功能命名空间NoiseControl、OneBudANCMode、VolumeSwipe、AdaptiveVolume、ConversationalAwareness、HearingAssist、HearingAid、AllowOffOption、AdaptiveNoise、Rename、MagicPairing、Parse等组织各操作码的报文常量与解析函数与操作码表一一对应。此外与 AACP 操作码配套的还有连接层的握手报文00 00 04 00 01 00 02 00 ...不发送则 AirPods 不响应任何数据包与特性宣告04 00 04 00 4D 00 FF 00 00 00 00 00 00 00这两步在 docs/AAP Definitions.md 中有完整记录Android 端createHandshakePacket/createSetFeatureFlagsPacket均有对应实现见 AACPManager.kt。实验与扩展指南原文档特别强调两点见 docs/control_commands.md 末尾注释数据来源控制命令标识符全集是从iOS 19.1 Betabuild 23B5044l的蓝牙协议栈中提取的未确认取值可自行探测文档已给出了已知命令的取值区间对于未给出取值的命令如0x05Button Send Mode、0x29SSL、0x30HRM 状态、0x37/0x38PPE 相关、0x3C/0x3DSiri/助听通用配置等可以通过向设备发送构造报文来实验确认。进行实验时的基本方法报文一律以04 00 04 00开头后接小端序 16 位操作码控制命令负载固定 7 字节09 00 identifier 4 字节数据未用字节补0x00需要接收 AirPods 主动上报电池、入耳检测、对话感知等时先发送0x000F通知注册报文若目标功能被墙如播放音频时的对话感知、自适应通透先发送0x004D特性宣告报文解锁每次实验的收发报文建议像 docs/AAP Definitions.md 那样记录下原始 hex 逐字节注释沉淀为可验证的协议证据。小结AACP 操作码体系是 LibrePods 驱动 AirPods 的协议基石16 位小端操作码 04 00 04 00报文头构成统一封装0x0009控制命令承载了绝大多数配置读写聆听模式、按键行为、助听、音量滑动等其标识符全集已在 docs/control_commands.md 中详细列出0x0004/0x0006/0x0017/0x0019/0x001D/0x004B/0x0053等 Host 方向操作码提供状态上报0x000F/0x0010/0x0030/0x004D等 Accessory 方向操作码完成注册、路由、配对与能力宣告。仓库内 docs/AAP Definitions.md 提供了大量带逐字节注释的实测报文AACPManager.kt、Packets.kt 与 airpods_packets.h、BasicControlCommand.hpp 则给出了可直接对照阅读的双端实现——研究者在理解本指南后可据此继续深入任意操作码的报文细节与功能逻辑。【免费下载链接】librepodsAirPods liberated from Apples ecosystem.项目地址: https://gitcode.com/gh_mirrors/al/librepods创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考