Skip to content

Conversation

kavishdevar
Copy link
Owner

@kavishdevar kavishdevar commented Sep 10, 2025

The app now supports

  • Accessibility Features
    • customizing transparency mode
    • enabling loud sound reduction
    • eq settings for transparency mode
    • eq settings for media and phone
    • hearing aid customization (Help needed from users in supported regions 🙏)
  • Multi-device connectivity
    • connect your AirPods with up to two devices simultaneously (more devices can be connected in Apple's ecosystem probably by iCloud)
    • shows popups on phone when other device takes control
    • asks the other device to show popups the same way iDevices do (will show up as an iphone because unfortunately apple's OSes don't actually pick up the names other than Mac, iPad, and iPhone specifically.
    • replicates most of the behavior for multi-device pairing such as hijack requests, reverse connection on banner tap, etc.
    • quirk: connect your apple device before connecting your non-apple device.

(Accessibility features needs writing a ATTManager because I'd love to have more direct control over the connection, WIP) done

How?

After hours of digging, I finally found that these things require the vendorId of the Device Identification Profile to be set to Apple's.

  • On Linux, this can be easily done by editing the /etc/bluetooth/main.conf file and setting the DeviceID parameter.
  • And for Android, we again fall back to xposed, where the function that adds this DID record to SDP (Service Display Protocol is hijacked). the hooks need to be reset to find the offset for the said function (and no, i'm not going for heuristics any time soon, this is just much more reliable, one-time setup).
    • add some indication for new features/updates for existing users so that they don't need to turn to the README and/or the release notes every update

oh, and i tried android studio's code inspection and cleaned up the code a little

@kavishdevar kavishdevar self-assigned this Sep 10, 2025
@kavishdevar kavishdevar added enhancement New feature or request help wanted Extra attention is needed android Android app related issues labels Sep 10, 2025
@kavishdevar

This comment was marked as outdated.

@Leclowndu93150
Copy link

the work done here is amazing, i hope the pros 3 keep the same packet format

@kavishdevar
Copy link
Owner Author

the work done here is amazing

thanks!

i hope the pros 3 keep the same packet format

Hopefully, Apple will not go all the way to change their entire protocol that they've been using over so many years

Have you been able to try this build out, @Leclowndu93150? The accessibility fetures and stuff?

I'm waiting for a few more days just to test it out myself before merging it.

@Leclowndu93150
Copy link

Leclowndu93150 commented Sep 17, 2025

Have you been able to try this build out, @Leclowndu93150? The accessibility fetures and stuff?

not yet not yet ! i was looking for this kind of apps cuz i'm getting my first ever airpods (pros 3) on the 19th, i never had an apple product before so i'll see how it goes. but i'd be happy to help !

@Leclowndu93150
Copy link

Leclowndu93150 commented Sep 19, 2025

pfft the store is late, tomorow for sure

@kavishdevar kavishdevar force-pushed the multi-device-and-accessibility branch from e42db82 to b43e5f7 Compare September 28, 2025 20:15
@randshell
Copy link

  1. That's probably because you haven't installed the app as a system app. this permission is needed for setting the battery status and icons for the BluetoothDevice. The only place the icons and battery ever show up is the Settings app. In hindsight, I should've probably not printed the stacktrace.
  2. Again, just a permission error. Needed to disable HFP/HSP.

Hmm, I've followed the Readme and there was no mention of installing as system. Also, if this is a requirement, I'd suggest to create a Magisk module for installing the app systemlessly. I don't remember if https://github.com/james34602/JamesDSPManager is privileged, but either way it could be an example of what I mean and how to achieve that (not sure I have the time myself to contribute).


  1. [...] And, AirPods cache the data, so probably a few restarts (a repair doesn't do) should get AirPods to refresh the info.

Oh, this must be it, as I had the "Act as Apple device" enabled.

1.1. Could you share a screenshot for that? On my iPad it's only the amplification and balance which adjusts the left and right accordingly.
Also, the media assist features under hearing aid aren't implemented

Then what I've mentioned is a Media Assist feature I think. Anyway, to me it looks like this:

image image

So the Hearing Aid is on top, and lower there is this option of using Hearing Test results. This test can only be done with the AirPods Pro 2 and Pro 3. Then, the audio is adjusted accordingly to compensate for this I assume.

  1. The app sends the exact same thing that my iDevice sends. Could you tell which AirPods' firmware version you are on?

Perhaps it's just the environment I was in when I tested this feature. Also using iPhone I couldn't recognize a noticeable difference.

  1. Needs the act as apple device hook.

I had this enabled.

  1. Weird, could you tell exactly when that happens, or is it always the case?

Somehow I've never seen it when moving from Android to iPhone, so I'd say to me it's always the case.

5.1 [...] But, the app can tell if the other device is playing audio or is on call. Based on that, a workaround is possible.

That's cool, then! Glad it's something that can be fixed.
Btw, I don't know how you do this in Java, but when it comes to ADB, you can run adb shell dumpsys media_session on recent versions of Android to check if any media is playing. I'd still prioritize an ongoing call imho, unless it's worth to make it a customizable option?

I am unfortunately not maintaining the Linux app right now, and the linux maintainer is currently busy with other things. I'll see if I can implement basic stuff for multi-device connectivity-- mainly, giving up, taking ownership of the control connect.

Thanks in advance! I'd be grateful for that. However, I'd understand if it'll take longer to implement since you're all doing this in the free time, so I think the Linux app as-is is already good enough.

@kavishdevar
Copy link
Owner Author

kavishdevar commented Sep 29, 2025

I've followed the Readme and there was no mention of installing as system. Also, if this is a requirement, I'd suggest to create a Magisk module for installing the app systemlessly.

The zip in the release is a root module for that (in v1.0.0-rc.4). I had forgotten to add this to the readme. Sorry 'bout that. I'm gonna improve the README when I release with this merged.

Then what I've mentioned is a Media Assist feature I think. Anyway, to me it looks like this:

Ah, I don't think that's the Media Assist feature (correct me if i'm wrong). The amplification and balance would should up under Adjustments once you enable Hearing Aid. What you're seeing is from the hearing test (I can't be bothered to be deal with accurate testing using AirPods, instead I'll just provide adding audiogram results and using it for hearing aid like Apple already provides).

So the Hearing Aid is on top, and lower there is this option of using Hearing Test results. This test can only be done with the AirPods Pro 2 and Pro 3. Then, the audio is adjusted accordingly to compensate for this I assume.

The EQ that's customizable from the Accessibility settings is the same as what's going to be sent when using media assist. I assumed that hearing test results would be used but it apparently doesn't.

From the screenshots I got from someone (I am in a region where the feature is not supported), Here's a list of things I know:

  • hearing test results: either from the hearing test that's taken using AirPods, or adding it manually via the Health app.
  • hearing aid:
    • hearing test results: the hearing loss data (raw dBHL values) from the hearing test. this is not customizable.
    • adjustments: once hearing aid is enabled, there are a few things that are customizable, like the amplification and balance (which do not alter the loss data in any way, these are different fields in the data sent), tone ambient noise etc..
    • if enabled, the "customize transparency mode" and "headphone accommodation" (EQ) are disabled.
  • media assist (when hearing aid is enabled): not sure if it's the same as "hearing assist" (a control command identifier). This is supposed to use the hearing loss data for phone and media EQ. This phone and media EQ is the same as the EQ that's available in Accessibility. From what I've seen the hearing test result isn't actually used though, and sometimes the EQ data sent is just zero.

Somehow I've never seen it when moving from Android to iPhone, so I'd say to me it's always the case.

I've put up a very quickly made demo video in the README. Currently the LibrePods presents itself as "Android" which is unfortunately not used by iOS/macOS. It just checks for "Mac" or "iPad" and defaults to iPhone. I guess that iOS doesn't show the UI unless it's specifically Mac/iPad.

[...] you can run adb shell dumpsys media_session on recent versions of Android to check if any media is playing.

Interesting, maybe I can use that. Apparently there are attributes to the media that's played too. I didn't know that. It is indeed possible tell interaction sounds and media apart.

I'd still prioritize an ongoing call imho, unless it's worth to make it a customizable option?

It's not much effort to make it customizable, so why not!

@kavishdevar
Copy link
Owner Author

added camera control (got lazy the last time to figure out how to listen to app changes, too lazy to fix merge conflicts later, so adding it with this PR). (or maybe idk how to use git ¯\_(ツ)_/¯)

i hope it's the same across all skins
@kavishdevar
Copy link
Owner Author

just gonna update the "control center" with the new design, and add the hearing aid amplification control and probably going to be ready for the next release.

@randshell
Copy link

I could give this MR another go this week perhaps. I'll use the root module from the nightly build you published yesterday.

@kavishdevar kavishdevar force-pushed the multi-device-and-accessibility branch from b6fb58e to 0e0af35 Compare October 1, 2025 14:34
@kavishdevar kavishdevar closed this Oct 2, 2025
@kavishdevar kavishdevar deleted the multi-device-and-accessibility branch October 2, 2025 05:22
@kavishdevar kavishdevar restored the multi-device-and-accessibility branch October 2, 2025 05:24
@kavishdevar kavishdevar reopened this Oct 2, 2025
@randshell
Copy link

I've realised that the latest nightly is not packaged as a magisk module, so I've used the zip from v0.1.0-rc.4 and replaced the APK binary with the nightly.

For starters, there's bootloop when flashing the magisk module on my A16 device:

java.lang.IllegalStateException: Signature|privileged permissions not in privileged permission allowlist: {me.kavishdevar.librep
ods (/system/priv-app/LibrePods): android.permission.LOCAL_MAC_ADDRESS}

So I've changed the XML permission as follows which fixes it:

<?xml version="1.0" encoding="utf-8"?>
<permissions>
    <privapp-permissions package="me.kavishdevar.librepods">
        <permission name="android.permission.BLUETOOTH_PRIVILEGED"/>
        <permission name="android.permission.INTERACT_ACROSS_USERS"/>
        <permission name="android.permission.LOCAL_MAC_ADDRESS"/>
        <permission name="android.permission.READ_PHONE_STATE"/>
    </privapp-permissions>
</permissions>

The READ_PHONE_STATE doesn't bootloop when it's missing, but it still creates some errors in the logcat. I didn't find that it's a privileged permission, so perhaps it's missing the permission prompt at runtime, rather than editing the XML file?

Ah, I don't think that's the Media Assist feature (correct me if i'm wrong). The amplification and balance would should up under Adjustments once you enable Hearing Aid. What you're seeing is from the hearing test (I can't be bothered to be deal with accurate testing using AirPods, instead I'll just provide adding audiogram results and using it for hearing aid like Apple already provides).

I think this should be correct afaik.

From the screenshots I got from someone (I am in a region where the feature is not supported), Here's a list of things I know:

hearing test results: either from the hearing test that's taken using AirPods, or adding it manually via the Health app.
hearing aid:
hearing test results: the hearing loss data (raw dBHL values) from the hearing test. this is not customizable.
adjustments: once hearing aid is enabled, there are a few things that are customizable, like the amplification and balance (which do not alter the loss data in any way, these are different fields in the data sent), tone ambient noise etc..
if enabled, the "customize transparency mode" and "headphone accommodation" (EQ) are disabled.

I think this is also correct.

I've put up a very quickly made demo video in the README. Currently the LibrePods presents itself as "Android" which is unfortunately not used by iOS/macOS. It just checks for "Mac" or "iPad" and defaults to iPhone. I guess that iOS doesn't show the UI unless it's specifically Mac/iPad.

I've enabled the iPhone feature. Anyway, what I meant is that LibrePods doesn't show the popup when the control goes to the iPhone. The iPhone correctly shows the popup when the control goes to LibrePods and Android. This was before. Now with the nightly and with the correct permissions set by the root module, I see the popup of LibrePods. However, I'm experiencing a new issue. The switch happens Android -> iPhone, but then it doesn't come back iPhone -> Android anymore. I can still change the settings on LibrePods, e.g., enable noise cancellation, but there's no audio. It's worth noting that the system bluetooth widget shows no connected device, while LibrePods shows in-app the AirPods but does send a notification for disconnected AirPods.

Lastly, I can enable now Hearing Aid without crashing, but the settings don't work at all, for example amplification. When I switch to iPhone I can see that hearing aid was enabled, so something did happen (I couldn't tell the difference just by listening, perhaps cause it was on default amplification settings).

Recap:

  1. needed new xml privapp perms
  2. seamless transition works Android to iPhone but not the other way around
  3. Hearing Aid settings, e.g., Amplification, don't work.
  4. I experience random disconnects, perhaps related to point 2?

I haven't retested the transparency and EQs.

@randshell
Copy link

I'll attach a logcat here to help narrow down other remaining issues.

logcat_2025-10-04_15-20-08.txt


A few things to note:

  • Caused by: java.lang.SecurityException: Neither user 10050 nor current process has android.permission.MODIFY_PHONE_STATE I didn't see this one before 🤔
  • Received HEADTRACKING packet too short: for me the "Use alternate packets for headtracking" works, which I forgot to enable after reinstalling LibrePods. Perhaps in the future the app could listen for packets for a while and if it doesn't receive any data it could automatically try the alternate packets and save this setting for next time AirPods are connected? Anyway, this is beyond the scope of this MR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
android Android app related issues enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants