Technical Documentation: librepods-org/librepods
โน๏ธ Provenance: Multi-Tier Ingestion ยท CodeWiki Reference
Overview (`README.md`)
[!WARNING]
librepods.org is not an official website of the LibrePods project. It inaccurately claims to be the official website of the project by claiming copyrights and using the LibrePods logo in the footer. And at the same time, they say that the project is not affiliated with the LibrePods project or its developers.Please report any other such websites to [email protected]
What is LibrePods?
LibrePods allows you to use AirPods features that are exclusive to Apple devices. It implements the proprietary protocol used to exchange data between AirPods and Apple devices, enabling features like changing noise control modes, fast ear detection, accurate battery status, head gestures, conversational awareness, and more on non-Apple platforms.
Feature availability
| Feature | Linux | Android |
|---|---|---|
| Changing Listening Mode | โ | โ |
| Ear detection | โ | โ |
| Battery status | โ | โ |
| Renaming AirPods Note for AndroidOn Android, you need to re-pair your AirPods after renaming them because Android might not use the latest name. | โ | โ |
| Loud Sound Reduction | ๐ด | โช |
| Head Gestures | โ | โ |
| Conversational Awareness | โ | โ |
| Automatically connect to AirPods | โ | โ |
| Hearing Aid | ๐ด | โช |
| Transparency Mode customization | ๐ด | โช |
| Multi-device connectivity (Bluetooth Multipoint; 2 devices only) | โช | โช |
| Other accessibility configs (click to expand) |
๐ด | โ |
Other general configsOff listening mode to switch to Off |
๐ด | โ |
| Head-tracked Spatial Audio | โ | โ |
| Heart Rate Monitoring | ๐ด | ๐ก |
| Find My | โ | โ |
| High quality two-way audio | ๐ก | ๐ก |
| Symbol | Meaning |
|---|---|
| โ | Implemented and works well |
| โช | Needs VendorID spoofing; use at your own risk |
| ๐ก | Experimental/Work in progress |
| ๐ด | Not implemented yet; planned |
| โ | Will not be implemented |
| โ | Unknown |
Find My
The following features related to Find My are planned, but require further RE and might need root on Android:
- Add your AirPods to the Find My network
- Play sound through charging case to find it
- Notify when leaving behind
- Toggle case charging sounds
Spatial Audio
The app does not currently provide head tracking information to Android for the OS to perform HRTF. This has not been explored completely, and it might need root.
Spatializing stereo sound is beyond this project's scope and will never be available. Many OEMs have an implementation of their own for this.
Heart Rate Monitoring
Android
Available in the android/rewrite branch. builds
Linux
Not available yet (doesn't seem like something that would be useful on a computer anyway. If you have any suggestions, create a discussion.)
High quality two-way audio
On iOS/iPadOS, you can continue using A2DP while AirPods send the hi-res (AAC-ELD mono 64kHz?) audio stream from its microphone over AACP.
Android
Record audio within the app using the AirPods' microphone without switching to Headset/Handsfree profile degrading the playback quality. But, making this available to other apps/telephony might need root, if possible at all.
Recorder is work in progress; available in the android/rewrite branch. builds
Linux
Check out PR #655.
Installation
VendorID Spoofing
Turns out, if you change the VendorID in DID Profile to that of Apple, you get access to several special features!
You can do this on Linux by editing the DeviceID in /etc/bluetooth/main.conf. Add this line to the config file DeviceID = bluetooth:004C:0000:0000. For android you can enable the act as Apple device setting in the app's settings (shown only when Xposed is available and LibrePods module is enabled).
Multi-device Connectivity
Upto two devices can be simultaneously connected to AirPods, for audio and control both. Seamless connection switching. The same notification shows up on Apple device when Android takes over the AirPods as if it were an Apple device ("Move to iPhone"). Android also shows a popup when the other device takes over.
Accessibility Settings and Hearing Aid
Accessibility settings like customizing transparency mode (amplification, balance, tone, conversation boost, and ambient noise reduction), and loud sound reduction can be configured.
All hearing aid customizations can be done from Android (linux soon), including setting the audiogram result. The app doesn't provide a way to take a hearing test because it requires much more precision. It is much better to use an already available audiogram result.
Protocol and Reverse Engineering
Please refer to the Wireshark dissector plugin by Nojus (@pabloaul) for more information on the protocols used: pabloaul/apple-wireshark
The dissector had not been used in LibrePods for most of the implementation; I had reverse engineered the protocol myself before this dissector was made. But many (future) features including two-way high quality audio and spatial audio would not have been possible without their RE efforts!
Use of AI
Android app
These parts of the app were completely AI-generated:
- Head Gestures - all of it, including logic and the UI
- The offset setup with r2+the xposed module (both versions)
- Troubleshooter and LogCollector
Rest everything- the background service, the Bluetooth manager classes (AACP and ATT), the entire UI, even the smallest components were written manually.
Some parts of the UI components were borrowed from Kyant0's demo app, which is licensed under Apache License 2.0.
Linux (rewrite)
The aacp.rs and the att.rs files were translated from Kotlin to Rust with AI. Some parts of the media_controller.rs file, mainly the pulse integration, was also AI-generated.
Supporters
A huge thank you to everyone supporting the project!
| @davdroman | @tedsalmon | @wiless |
|---|---|---|
| @SmartMsg | @lunaroyster | @ressiwage |
| @kkjdroid | @CitrusJoules | @DanielReyesDev |
| @sumitduster | @GrifTheDev |
Special Thanks
- @tyalie for making the first documentation on the protocol! (tyalie/AAP-Protocol-Definition)
- @rithvikvibhu and folks over at lagrangepoint for helping with the hearing aid feature (gist)
- @devnoname120 for helping with the first root patch
- @timgromeyer for making the first version of the linux app
- @hackclub for hosting High Seas and Low Skies!
- Of course, everyone who has contributed to the project in any way, including by testing, sharing feedback, or just showing interest!
Alternates for other platforms:
- CAPod - A companion app for AirPods on Android. (play store | source code). Use this if you're using Android version 16 QPR3 or below and are not rooted.
- MagicPods for Steam Deck (website)
- MagicPods - if you're looking for "LibrePods for Windows" (ms store installer | website)
Star History
License
LibrePods - AirPods liberated from Appleโs ecosystem
Copyright (C) 2025 LibrePods contributors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see https://www.gnu.org/licenses/.
Trademark Notice
The GPL does not grant any rights to use the LibrePods name, logo, or branding. The LibrePods name and logo may not be used for software, websites, domains, products, services, or other projects in a manner that suggests affiliation with, endorsement by, or association with the official LibrePods project without prior permission.
If you see any misuse of the LibrePods name or logo, please report it to [email protected].
The SF Pro font used in the Android app is the property of Apple Inc.. This will be removed in future versions of the app and replaced with an open alternative soon.
AirPods, AirPods Pro, AirPods Max, and the AirPods logo are trademarks of Apple Inc. The LibrePods project is not affiliated with or endorsed by Apple Inc. in any way.
Overview (`android/README.md`)
Root Requirement
LibrePods may require root depending on your device/OS and what features you want access to:
- Features requiring the VendorID hook (the features marked with an asterisk here) will always require root regardless of your device/OS.
- On ColorOS/OxygenOS 16 and realme UI 7.0 and Pixel devices on Android 16 QPR3 (with the latest Google Play system update), LibrePods does not need root for most features.
- On other devices, LibrePods needs root because of a bug in the Android Bluetooth stack Fluoride/non-compliance of Apple with Bluetooth standards. You must have Xposed installed for the app to workaround this bug and connect to AirPods. This issue is being tracked here. Please do not comment on the issue thread. The issue has already been resolved and should be available in Android 17 for all devices.
[!IMPORTANT]
This workaround with Xposed is not guaranteed to work on all devices.
Installation
Google Play Store
If you are using a supported device/OS combination, you can install LibrePods from the Google Play Store. You can use the VendorID hook features with root even from the Play Store version.
GitHub Releases
If you need xposed because of the root requirement, you will have to use the apk/zip from the GitHub releases.
As a system app (root module)
If you want LibrePods to have privileged Bluetooth permissions to
- show battery status in the system settings and widgets
- show AirPods icon in the system settings (xposed is also currently required for this)
- switch audio to phone speakers when you are not wearing your AirPods
you can install the root module. This is optional and only provides extra features, but it is not required for the app to work.
[!IMPORTANT]
When using the root module, do not install the Play Store version. There might be issues because of the signature mismatch between the Play Store version and the root module.
Nightly/Development Builds
Want to try the latest features before they're officially released? You can grab nightly builds from the latest nightly release.
[!WARNING]
These builds are automatically generated from the latest code and may contain new features and bug fixes that haven't been included in a stable release yet. However, please note that they may also be less stable than official releases, so use them at your own risk.
Screenshots
here's a very unprofessional demo video
https://github.com/user-attachments/assets/43911243-0576-4093-8c55-89c1db5ea533
Troubleshooting steps for common errors
- Ensure the correct scope is set in LSPosed/Vector.
- Ensure there is no root-hiding module preventing the hook from loading on the Bluetooth app.
- Restart your phone after confirming the scope.
A few notes
Due to recent AirPods' firmware upgrades, you must enable
Off listening modeto switch toOff. This is because in this mode, loud sounds are not reduced.When renaming your AirPods through the app, you'll need to re-pair them with your phone for the name change to take effect. This is a limitation of how Bluetooth device naming works on Android.
Overview (`linux/README.md`)
LibrePods on Linux
A new rewrite is being worked upon. Please look at the list of features in the root README to see what's supported in the new version.
The rewrite can be found in the linux/rust branch here. Follow the development in PR #241.
Installation
GitHub Releases
The app is ready to download as an AppImage or an executable. You can download the latest pre-release from the GitHub releases.
Nightly Builds (recommended)
You can also try the latest build of the new version from the GitHub Actions artifacts. On the latest successful workflow run, download the librepods-x86_64.AppImage or librepods binary from Artifacts.
README for the old version
LibrePods Linux
A native Linux application to control your AirPods, with support for:
- Noise Control modes (Off, Transparency, Adaptive, Noise Cancellation)
- Conversational Awareness
- Battery monitoring
- Auto play/pause on ear detection
- Hearing Aid features
- Supports adjusting hearing aid- amplification, balance, tone, ambient noise reduction, own voice amplification, and conversation boost
- Supports setting the values for left and right hearing aids (this is not a hearing test! you need to have an audiogram to set the values)
- Seamless handoff between Android and Linux
Prerequisites
Your phone's Bluetooth MAC address (can be found in Settings > About Device)
Qt6 packages
bash# For Arch Linux / EndeavourOS sudo pacman -S qt6-base qt6-connectivity qt6-multimedia-ffmpeg qt6-multimedia # For Debian sudo apt-get install qt6-base-dev qt6-declarative-dev qt6-connectivity-dev qt6-multimedia-dev \ qml6-module-qtquick-controls qml6-module-qtqml-workerscript qml6-module-qtquick-templates \ qml6-module-qtquick-window qml6-module-qtquick-layouts # For Fedora sudo dnf install qt6-qtbase-devel qt6-qtconnectivity-devel \ qt6-qtmultimedia-devel qt6-qtdeclarative-develOpenSSL development headers
bash# On Arch Linux / EndevaourOS, these are included in the OpenSSL package, so you might already have them installed. sudo pacman -S openssl # For Debian / Ubuntu sudo apt-get install libssl-dev # For Fedora sudo dnf install openssl-develLibpulse development headers
bash# On Arch Linux / EndevaourOS, these are included in the libpulse package, so you might already have them installed. sudo pacman -S libpulse # For Debian / Ubuntu sudo apt-get install libpulse-dev # For Fedora sudo dnf install pulseaudio-libs-develCmake
bash# For Arch Linux / EndeavourOS sudo pacman -S cmake # For Debian / Ubuntu sudo apt-get install cmake # For Fedora sudo dnf install cmake
Setup
Build the application:
bashmkdir build cd build cmake .. make -j $(nproc)Run the application:
bash./librepods
Troubleshooting
Media Controls (Play/Pause/Skip) Not Working
If tap gestures on your AirPods aren't working for media control, you need to enable AVRCP support. The solution depends on your audio stack:
PipeWire/WirePlumber (Recommended)
Create ~/.config/wireplumber/wireplumber.conf.d/51-bluez-avrcp.conf:
monitor.bluez.properties = {
# Enable dummy AVRCP player for proper media control support
# This is required for AirPods and other devices to send play/pause/skip commands
bluez5.dummy-avrcp-player = true
}Then restart WirePlumber:
systemctl --user restart wireplumber[!WARNING]
Do NOT runmpris-proxywith WirePlumber - it will conflict and break media controls.
PulseAudio
If you're using PulseAudio instead of PipeWire, enable and start mpris-proxy:
systemctl --user enable --now mpris-proxyUsage
- Left-click the tray icon to view battery status
- Right-click to access the control menu:
- Toggle Conversational Awareness
- Switch between noise control modes
- View battery levels
- Control playback
CLI Control
librepods-ctl is a small command-line tool that lets you access LibrePods from the terminal or via scripts, as long as the main application is running.
Usage
librepods-ctlCommands
| Command | Description |
|---|---|
noise:off |
Disable noise control |
noise:anc |
Enable Active Noise Cancellation |
noise:transparency |
Enable Transparency mode |
noise:adaptive |
Enable Adaptive mode |
Example
# Enable ANC
librepods-ctl noise:anc
# Enable Transparency mode
librepods-ctl noise:transparencyHearing Aid
To use hearing aid features, you need to have an audiogram. To enable/disable hearing aid, you can use the toggle in the main app. But, to adjust the settings and set the audiogram, you need to use a different script which is located in this folder as hearing_aid.py. You can run it with:
python3 hearing_aid.pyThe script will load the current settings from the AirPods and allow you to adjust them. You can set the audiogram by providing the values for 8 frequencies (250Hz, 500Hz, 1kHz, 2kHz, 3kHz, 4kHz, 6kHz, 8kHz) for both left and right ears. There are also options to adjust amplification, balance, tone, ambient noise reduction, own voice amplification, and conversation boost.
AirPods check for the DeviceID characteristic to see if the connected device is an Apple device and only then allow hearing aid features. To set the DeviceID characteristic, you need to add this line to your bluetooth configuration file (usually located at /etc/bluetooth/main.conf):
DeviceID = bluetooth:004C:0000:0000Then, restart the bluetooth service:
sudo systemctl restart bluetoothHere, you might need to re-pair your AirPods because they seem to cache this info.
Troubleshooting
It is possible that the AirPods disconnect after a short period of time and play the disconnect sound. This is likely due to the AirPods expecting some information from an Apple device. Since I have not implemented everything that an Apple device does, the AirPods may disconnect. You don't need to reconnect them manually; the script will handle reconnection automatically for hearing aid features. So, once you are done setting the hearing aid features, change back the DeviceID to whatever it was before.
Why a separate script?
Because I discovered that QBluetooth doesn't support connecting to a socket with its PSM, only a UUID can be used. I could add a dependency on BlueZ, but then having two bluetooth interfaces seems unnecessary. So, I decided to use a separate script for hearing aid features. In the future, QBluetooth will be replaced with BlueZ native calls, and then everything will be in one application.
AAP Definitions (`docs/AAP Definitions.md`)
AAP Definitions (As per AirPods Pro 2 (USB-C) Firmware 7A305)
AAP runs on top of L2CAP, with a PSM of 0x1001 or 4097.
Handshake
This packet is necessary to establish a connection with the AirPods. Or else, the AirPods will not respond to any packets.
00 00 04 00 01 00 02 00 00 00 00 00 00 00 00 00Setting specific features for AirPods Pro 2
may work for airpods 4 anc also, not tested
Since apple likes to wall off some features behind specific OS versions, and apple silicon devices, some packets are necessary to enable these features.
I captured the following packet only accidentally, because Apple being Apple decided to hide this and the handshake from packetlogger, but sometimes it shows up.
Captured using PacketLogger on an Intel Mac running macOS Sequoia 15.0.1
04 00 04 00 4d 00 ff 00 00 00 00 00 00 00This packet enables conversational awareness when playing audio. (CA works without this packet only when no audio is playing)
It also enables the Adaptive Transparency feature. (We can set Adaptive Transparency, but it doesn't respond with the same packet See Noise Cancellation)
Requesting notifications
This packet is necessary to receive notifications from the AirPods like ear detection, noise control mode, conversational awareness, battery status, etc.
Captured using PacketLogger on an Intel Mac running macOS Sequoia 15.0.1
04 00 04 00 0F 00 FF FF FE FFThis packet also works.
04 00 04 00 0F 00 FF FF FF FFNotifications
Battery
AirPods occasionally send battery status packets. The packet format is as follows:
04 00 04 00 04 00 [battery count] ([component] 01 [level] [status] 01) times the battery count| Components | Byte value |
|---|---|
| Case | 08 |
| Left | 04 |
| Right | 02 |
| Status | Byte value |
|---|---|
| Unknown | 00 |
| Charging | 01 |
| Discharging | 02 |
| Disconnected | 04 |
Example packet from AirPods Pro 2
04 00 04 00 04 00 03 02 01 64 02 01 04 01 63 01 01 08 01 11 02 01| Byte | Interpretation |
|---|---|
| 7th byte | Battery Count - 3 |
| 8th byte | Battery type - Left |
| 9th byte | Spacer, value = 0x01 |
| 10th byte | Battery level 100% |
| 11th byte | Battery status - Discharging |
| 12th byte | Battery component end value = 0x01 |
| 13th byte | Battery type - Right |
| 14th byte | Spacer, value = 0x01 |
| 15th byte | Battery level 99% |
| 16th byte | Battery status - Charging |
| 17th byte | Battery component end value = 0x01 |
| 18th byte | Battery type - Case |
| 19th byte | Spacer, value = 0x01 |
| 20th byte | Battery level 17% |
| 21st byte | Battery status - Discharging |
| 22nd byte | Battery component end value = 0x01 |
Noise Control
The AirPods Pro 2 send noise control packets when the noise control mode is changed (either by a stem long press or by the connected device, see Changing noise control). The packet format is as follows:
04 00 04 00 09 00 0D [mode] 00 00 00| Noise Control Mode | Byte value |
|---|---|
| Off | 01 |
| Noise Cancellation | 02 |
| Transparency | 03 |
| Adaptive Transparency | 04 |
Ear Detection
AirPods send ear detection packets when the ear detection status changes. The packet format is as follows:
04 00 04 00 06 00 [primary pod] [secondary pod]If primary is removed, mic will be changed and the secondary will be the new primary, so the primary will be the one in the ear, and the packet will be sent again.
| Pod Status | Byte value |
|---|---|
| In Ear | 00 |
| Out of Ear | 01 |
| In Case | 02 |
Conversational Awareness
AirPods send conversational awareness packets when the person wearing them starts speaking. The packet format is as follows:
04 00 04 00 4B 00 02 00 01 [level]| Level Byte Value | Meaning |
|---|---|
| 01/02 | Person Started Speaking; greatly reduce volume |
| 03 | Person Stopped Speaking; increase volume back to normal |
| Intermediate values | Intermediate volume levels |
| 08/09 | Normal Volume |
Reading Conversational Awareness State
After requesting notifications, the AirPods send a packet indicating the current state of Conversational Awareness (CA). This packet is only sent once after notifications are requested, not when the CA state is changed.
The packet format is:
04 00 04 00 09 00 28 [status] 00 00 00[status]is a single byte at offset 7 (zero-based), immediately after the header.0x01โ Conversational Awareness is enabled0x02โ Conversational Awareness is disabled- Any other value โ Unknown/undetermined state
Example:
04 00 04 00 09 00 28 01 00 00 00Here, 01 at the 8th byte (offset 7) means CA is enabled.
Metadata
This packet contains device information like name, model number, etc. The packet format is:
04 00 04 00 1d [strings...]The strings are null-terminated UTF-8 strings in the following order:
- Bluetooth advertising name (varies in length)
- Model number
- Manufacturer
- Serial number
- Firmware version
- Firmware version 2 (the exact same as before??)
- Software version (1.0.0 why would we need it?)
- App identifier (com.apple.accessory.updater.app.71 what?)
- Serial number 1
- Serial number 2
- Unknown numeric value
- Encrypted data
- Additional encrypted data
Example packet:
040004001d0002d5000400416972506f64732050726f004133303438004170706c6520496e632e0051584e524848595850360036312e313836383034303030323030303030302e323731330036312e313836383034303030323030303030302e3237313300312e302e3000636f6d2e6170706c652e6163636573736f72792e757064617465722e6170702e3731004859394c5432454632364a59004833504c5748444a32364b3000363335373533360089312a6567a5400f84a3ca234947efd40b90d78436ae5946748d70273e66066a2589300035333935303630363400```
The packet contains device identification and version information followed by some encrypted data whose format is not known.Writing to the AirPods
Changing Noise Control
We can send a packet to change the noise control mode. The packet format is as follows:
04 00 04 00 09 00 0D [mode] 00 00 00| Noise Control Mode | Byte value |
|---|---|
| Off | 01 |
| Noise Cancellation | 02 |
| Transparency | 03 |
| Adaptive Transparency | 04 |
The airpods will respond with the same packet after the mode has been changed.
But if your airpods support Adaptive Transparency, and you haven't sent that special packet to enable it, the airpods will respond with the same packet but with a different mode (like 0x02).
Renaming AirPods
We can send a packet to rename the AirPods. The packet format is as follows:
04 00 04 00 1A 00 01 [size] 00 [name]Toggle case charging sounds
This feature is only for cases with a speaker, i.e. the AirPods Pro 2 and the new AirPods 4. Tested only on AirPods Pro 2
We can send a packet to toggle if sounds should be played when the case is connected to a charger. The packet format is as follows:
12 3A 00 01 00 08 [setting]| Byte Value | Sound |
|---|---|
| 00 | On |
| 01 | Off |
Toggle Conversational Awareness
This feature is only for AirPods Pro 2 and the new AirPods 4 with ANC. Tested only on AirPods Pro 2
We can send a packet to toggle Conversational Awareness. If enabled, the AirPods will switch to Transparency mode when the person wearing them starts speaking (and sends packet for notifying the device to reduce volume). The packet format is as follows:
04 00 04 00 09 00 28 [setting] 00 00 00| Byte Value | C.A. |
|---|---|
| 01 | On |
| 02 | Off |
Adaptive Audio Noise
This feature is only for AirPods Pro 2 and the new AirPods 4 with ANC. Tested only on AirPods Pro 2
The new firmware 7A305 for app2 has a new feature called Adaptive Audio Noise. This allows us to control how much noise is passed through the AirPods when the noise control mode is set to Adaptive. The packet format is as follows:
04 00 04 00 09 00 2E [level] 00 00 00The level can be any value between 0 and 100, 0 to allow maximum noise (i.e. minimum noise filtering), and 100 to filter out more noise.
This feature is only effective when the noise control mode is set to Adaptive.
I find it quite funny how I have greater control over the noise control on the AirPods on non-Apple devices than on Apple devices, becuase on Apple Devices, there are just 3 options More Noise (0), Midway through (50), and Less Noise (100), but here I can set any value between 0 and 100.
Accessiblity Settings
Headphone Accomodation
04 00 04 00 53 00 84 00 02 02 [Phone] [Media]
[EQ1][EQ2][EQ3][EQ4][EQ5][EQ6][EQ7][EQ8]
duplicated thrice for some reason| Data | Type | Value range |
|---|---|---|
| Phone | Decimal | 1 (Enabled) or 2 (Disabled) |
| Media | Decimal | 1 (Enabled) or 2 (Disabled) |
| EQ | Little Endian | 0 to 100 |
Customize Transparency mode
12 18 00 [enabled]
<left bud>
[EQ1][EQ2][EQ3][EQ4][EQ5][EQ6][EQ7][EQ8]
[Amplification]
[Tone]
[Conversation Boost]
[Ambient Noise Reduction]
<repeat for right bud>/* Detailed source-code truncated for AI context efficiency. */
04 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 00Stop Tracking
This packet stops the head tracking data stream.
04 00 04 00 17 00 00 00 10 00 11 00 08 7E 10 02 42 0B 08 4E 10 02 1A 05 01 00 00 00 00Received Head Tracking Sensor Data
Once tracking is active, the AirPods stream sensor packets with the following common structure:
| Field | Offset | Length (bytes) |
|---|---|---|
| orientation 1 | 43 | 2 |
| orientation 2 | 45 | 2 |
| orientation 3 | 47 | 2 |
| Horizontal Acceleration | 51 | 2 |
| Vertical Acceleration | 53 | 2 |
Control Commands (`docs/control_commands.md`)
Control Commands
AACP uses opcode 9 for control commands. opcodes are 16 bit integers that specify the kind of action being done. The length of a control command is fixed to 7 bytes + 4 bytes header (04 00 04 00)
An AACP packet is formated as:
04 00 04 00 [opcode, little endian] [data]
So, our control commands becomes
04 00 04 00 09 00 [identifier] [data1] [data2] [data3] [data4]Bytes that are not used are set to 0x00. From what I've observed, the data3 and data4 are never used, and hence always zero. And, the data2 is usually used when the configuration can be different for the two buds: like, to change the long press mode. Or, if there can be two "state" variables for the same feature: like the Hearing Aid feature.
Identifiers and details
| Command identifier | Description |
|---|---|
| 0x01 | Mic Mode |
| 0x05 | Button Send Mode |
| 0x06 | Owns connection |
| 0x0A | Ear Detection |
| 0x12 | VoiceTrigger for Siri |
| 0x14 | SingleClickMode |
| 0x15 | DoubleClickMode |
| 0x16 | ClickHoldMode |
| 0x17 | DoubleClickInterval |
| 0x18 | ClickHoldInterval |
| 0x1A | ListeningModeConfigs |
| 0x1B | OneBudANCMode |
| 0x1C | CrownRotationDirection |
| 0x0D | ListeningMode |
| 0x1E | AutoAnswerMode |
| 0x1F | Chime Volume |
| 0x20 | Connect Automatically |
| 0x23 | VolumeSwipeInterval |
| 0x24 | Call Management Config |
| 0x25 | VolumeSwipeMode |
| 0x26 | Adaptive Volume Config |
| 0x27 | Software Mute config |
| 0x28 | Conversation Detect config |
| 0x29 | SSL |
| 0x2C | Hearing Aid Enrolled and Hearing Aid Enabled |
| 0x2E | AutoANC Strength |
| 0x2F | HPS Gain Swipe |
| 0x30 | HRM enable/disable state |
| 0x31 | In Case Tone config |
| 0x32 | Siri Multitone config |
| 0x33 | Hearing Assist config |
| 0x34 | Allow Off Option for Listening Mode config |
| 0x35 | Sleep Detection config |
| 0x36 | Allow Auto Connect |
| 0x37 | PPE Toggle config |
| 0x38 | Personal Protective Equipment Cap Level config |
| 0x39 | Raw Gestures config |
| 0x3A | Temporary Pairing Config |
| 0x3B | Dynamic End of Charge config |
| 0x3C | System Siri message config |
| 0x3D | Hearing Aid Generic config |
| 0x3E | Uplink EQ Bud config |
| 0x3F | Uplink EQ Source config |
| 0x40 | In Case Tone Volume |
| 0x41 | Disable Button Input config |
Command Details
0x01 - Mic Mode
Format: Single value (1 byte)
Values: 0x00 = Automatic, 0x01 = Right, 0x02 = Left.
0x05 - Button Send Mode
Format: Single value (1 byte)
Additional notes: Logged as "Set Button Send Mode: %d". May involve context updates for button handling.
0x06 - Owns connection
Format: Single value (1 byte)
Values: 0x01 = own, 0x00 = doesn't own.
0x0A - Ear Detection
Format: Single value (1 byte)
Values: 0x01 = enabled, 0x02 = disabled.
0x12 - VoiceTrigger for Siri
Format: Single value (1 byte)
Values: 0x01 = enabled, 0x02 = disabled.
0x14 - SingleClickMode
Format: Single value (1 byte)
0x15 - DoubleClickMode
Format: Single value (1 byte)
0x16 - ClickHoldMode
Format: Two values (2 bytes; First byte = right bud, Second byte = left bud).
Values: 0x01 = Noise control, 0x05 = Siri.
0x17 - DoubleClickInterval
Format: Single value (1 byte)
Values: 0x00 = Default, 0x01 = Slower, 0x02 = Slowest.
0x18 - ClickHoldInterval
Format: Single value (1 byte)
Values: 0x00 = Default, 0x01 = Slower, 0x02 = Slowest.
0x1A - ListeningModeConfigs
Format: Single value (1 byte)
Values: Bitmask, Off mode = 0x01, ANC=0x02, Transparency = 0x04, Adaptive = 0x08.
0x1B - OneBudANCMode
Format: Single value (1 byte)
Values: 0x01 = enabled, 0x02 = disabled
0x1C - CrownRotationDirection
Format: Single value (1 byte)
Values: 0x01 = reversed, 0x02 = default.
0x0D - ListeningMode
Format: Single value (1 byte)
Values: 1 = Off, 2 = noise cancellation, 3 = transparency, 4 = adaptive.
0x1E - AutoAnswerMode
Format: Single value (1 byte)
0x1F - Chime Volume
Format: Single value (1 byte)
Values: 0 to 100.
0x20 - Connect Automatically
Format: Single value (1 byte)
Values: 0x01 = enabled, 0x02 = disabled.
0x23 - VolumeSwipeInterval
Format: Single value (1 byte)
Values: 0x00 = Default, 0x01 = Longer, 0x02 = Longest.
0x24 - Call Management Config
Format: Single value (1 byte)
0x25 - VolumeSwipeMode
Format: Single value (1 byte)
Values: 0x01 = enabled, 0x02 = disabled
0x26 - Adaptive Volume Config
Format: Single value (1 byte)
Values: 0x01 = enabled, 0x02 = disabled
0x27 - Software Mute config
Format: Single value (1 byte)
0x28 - Conversation Detect config
Format: Single value (1 byte)
Values: 0x01 = enabled, 0x02 = disabled
0x29 - SSL
Format: Single value (1 byte)
0x2C - Hearing Aid Enrolled and Hearing Aid Enabled
Format: Two values (2 bytes; First byte - enrolled, Second byte = enabled)
Values: 0x01 = enabled, 0x02 = disabled
0x2E - AutoANC Strength
Format: Single value (1 byte)
Values: 0 to 100.
0x2F - HPS Gain Swipe (swipe to adjust amplification)
Format: Single value (1 byte)
0x30 - HRM enable/disable state
Format: Single value (1 byte)
0x31 - In Case Tone config
Format: Single value (1 byte)
Values: 0x01 = enabled, 0x02 = disabled
0x32 - Siri Multitone config
Format: Single value (1 byte)
0x33 - Hearing Assist config
Format: Single value (1 byte)
Values: 0x01 = enabled, 0x02 = disabled
0x34 - Allow Off Option for Listening Mode config
Format: Single value (1 byte)
Values: 0x01 = enabled, 0x02 = disabled
0x35 - Sleep Detection config
Format: Single value (1 byte)
Values: 0x01 = enabled, 0x02 = disabled
0x36 - Allow Auto Connect
Format: Single value (1 byte)
Values: 0x01 = allow, 0x02 = disallow
0x37 - PPE Toggle config
Format: Single value (1 byte)
0x38 - Personal Protective Equipment Cap Level config
Format: Single value (1 byte)
0x39 - Raw Gestures config
Format: Single value (1 byte)
Values: Bitmask, single press = 0x01, double press = 0x02, triple press = 0x04, long press = 0x08.
0x3A - Temporary Pairing Config
Format: Single value (1 byte)
Values: 0x01 = Temporary, 0x02 = Permanent
0x3B - Dynamic End of Charge config
Format: Single value (1 byte)
0x3C - System Siri message config
Format: Single value (1 byte)
0x3D - Hearing Aid Generic config
Format: Single value (1 byte)
0x3E - Uplink EQ Bud config
Format: Single value (1 byte)
0x3F - Uplink EQ Source config
Format: Single value (1 byte)
0x40 - In Case Tone Volume
Format: Single value (1 byte)
Values: 0 to 100.
0x41 - Disable Button Input config
Format: Single value (1 byte)
[!NOTE]
- These identifiers have been extracted from the iOS 19.1 Beta (23B5044l)'s bluetooth stack.
- I have already added the ranges of values a command takes that I know of. Feel free to experiment by sending the packets for which the range/values are not given here.
Device Info (`docs/device-info.md`)
opcode: 0x001D title: Device Information
Device information
The device information packet is sent by the accessory to the host upon connection. It contains various details about the AirPods, including model number, software version, and serial number.
Each null indicates the start of a new string field.
The data is in this order:
- Name
- Model number
- Manufacturer (always "Apple Inc.")
- Serial number
- Version 1
- Version 2
- Hardware revision (?) (I have
1.0.0) - Updater app version (?) (I have
com.apple.accessory.updater.app.71) - Serial number (Left Bud)
- Serial number (Right Bud)
- Version (?) (I have
8454371) - A few more bytes, I don't know what they are
Opcodes (`docs/opcodes.md`)
AACP opcodes
AACP (Apple Accessory Communication Protocol) uses various opcodes to define different types of actions and commands. Each opcode is a 16-bit integer that specifies the kind of operation being performed. The opcode is sent in little-endian format as part of the AACP packet structure.
| Opcode (Hex) | Destination | Description |
|---|---|---|
| 0x0001 | Accessory | Unknown |
| 0x0004 | Host | Battery report |
| 0x0006 | Host | Ear detection |
| 0x0009 | Both | Control commands |
| 0x000D | Accessory | Audio source req |
| 0x000E | Host | Audio source resp |
| 0x000F | Accessory | Notification register |
| 0x0010 | Accessory | Smart routing relay |
| 0x0011 | Host | Smart routing response |
| 0x0014 | Accessory | Send connected device MAC |
| 0x0017 | Both | Multiple things - undocumented |
| 0x0019 | Host | Stem press |
| 0x001B | Accessory | Timestamp |
| 0x001D | Host | Device Information |
| 0x001E | Accessory | Rename device |
| 0x0022 | Accessory | Unknown |
| 0x0029 | Accessory | Host capabilities (?) |
| 0x002B | Host | Paired devices (?) |
| 0x002D | Accessory | List of connected dev. req |
| 0x002E | Host | List of connected devices |
| 0x0030 | Accessory | BLE keys req |
| 0x0031 | Host | BLE keys response |
| 0x004B | Host | Conversation awareness |
| 0x004D | Accessory | Host capabilities |
| 0x004F | Both | Information req/res (doesn't work, even with apple's DID) |
| 0x0053 | Both | EQ data |
--- METRICS ---
- Files Extracted: 7
- Estimated Token Budget: ~12952 tokens
- Canonical Reference: https://codewiki.google/github.com/librepods-org/librepods