librepods Documentation

AirPods liberated from Apple's ecosystem.

RAW Doc

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)
  • Press speed
  • Press and Hold duration
  • Noise Cancellation with single AirPod
  • Volume control on swipe
  • Volume swipe speed
  • ๐Ÿ”ด โœ…
    Other general configs
  • Press and Hold to cycle between listening modes/invoke digital assistant (invoking digital assistant needs a recent firmware)
  • Configure call controls
  • Personalized volume
  • Loud Sound Reduction (needs VendorID spoofing)
  • Microphone side
  • Pause media when falling asleep (needs a recent firmware)
  • Enable Off 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 mode to switch to Off. 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.

    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

    1. Your phone's Bluetooth MAC address (can be found in Settings > About Device)

    2. 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-devel
    3. OpenSSL 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-devel
    4. Libpulse 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-devel
    5. Cmake

      bash
      # For Arch Linux / EndeavourOS
      sudo pacman -S cmake
      
      # For Debian / Ubuntu
      sudo apt-get install cmake
      
      # For Fedora
      sudo dnf install cmake

    Setup

    1. Build the application:

      bash
      mkdir build
      cd build
      cmake ..
      make -j $(nproc)
    2. 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:

    Create ~/.config/wireplumber/wireplumber.conf.d/51-bluez-avrcp.conf:

    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:

    bash
    systemctl --user restart wireplumber

    [!WARNING]
    Do NOT run mpris-proxy with WirePlumber - it will conflict and break media controls.

    PulseAudio

    If you're using PulseAudio instead of PipeWire, enable and start mpris-proxy:

    bash
    systemctl --user enable --now mpris-proxy

    Usage

    • 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

    bash
    librepods-ctl

    Commands

    Command Description
    noise:off Disable noise control
    noise:anc Enable Active Noise Cancellation
    noise:transparency Enable Transparency mode
    noise:adaptive Enable Adaptive mode

    Example

    bash
    # Enable ANC
    librepods-ctl noise:anc
    
    # Enable Transparency mode
    librepods-ctl noise:transparency

    Hearing 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:

    bash
    python3 hearing_aid.py

    The 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):

    text
    DeviceID = bluetooth:004C:0000:0000

    Then, restart the bluetooth service:

    bash
    sudo systemctl restart bluetooth

    Here, 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.

    plaintext
    00 00 04 00 01 00 02 00 00 00 00 00 00 00 00 00

    Setting 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

    plaintext
    04 00 04 00 4d 00 ff 00 00 00 00 00 00 00

    This 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

    plaintext
    04 00 04 00 0F 00 FF FF FE FF

    This packet also works.

    plaintext
    04 00 04 00 0F 00 FF FF FF FF

    Notifications

    Battery

    AirPods occasionally send battery status packets. The packet format is as follows:

    plaintext
    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

    plaintext
    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:

    plaintext
    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:

    plaintext
    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:

    plaintext
    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:

    plaintext
    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 enabled
      • 0x02 โ€” Conversational Awareness is disabled
      • Any other value โ€” Unknown/undetermined state

    Example:

    plaintext
    04 00 04 00 09 00 28 01 00 00 00

    Here, 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:

    plaintext
    04 00 04 00 1d [strings...]

    The strings are null-terminated UTF-8 strings in the following order:

    1. Bluetooth advertising name (varies in length)
    2. Model number
    3. Manufacturer
    4. Serial number
    5. Firmware version
    6. Firmware version 2 (the exact same as before??)
    7. Software version (1.0.0 why would we need it?)
    8. App identifier (com.apple.accessory.updater.app.71 what?)
    9. Serial number 1
    10. Serial number 2
    11. Unknown numeric value
    12. Encrypted data
    13. Additional encrypted data

    Example packet:

    plaintext
    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:

    plaintext
    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:

    plaintext
    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:

    plaintext
    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:

    plaintext
    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:

    plaintext
    04 00 04 00 09 00 2E [level] 00 00 00

    The 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

    text
    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

    text
    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. */

    plaintext
    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 00

    Stop Tracking

    This packet stops the head tracking data stream.

    plaintext
    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 00

    Received 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

    text
    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)

    Format: Single value (1 byte)

    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 ---