From 069277747cead99f33c9273c3693ff926330df07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Rebelo?= Date: Sat, 2 May 2026 19:09:11 +0100 Subject: [PATCH] CMF Buds 2a: Add low latency mode --- .../DeviceSettingsPreferenceConst.java | 1 + .../DeviceSpecificSettingsFragment.java | 1 + .../devices/nothing/AbstractEarCoordinator.java | 7 +++++++ .../devices/nothing/CmfBuds2aCoordinator.java | 16 +++++++++++++--- .../service/devices/nothing/Ear1Support.java | 13 +++++++++++++ .../devicesettings_headphones_low_latency.xml | 10 ++++++++++ 6 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 app/src/main/res/xml/devicesettings_headphones_low_latency.xml diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSettingsPreferenceConst.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSettingsPreferenceConst.java index 3376b414d9..0505e4e66c 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSettingsPreferenceConst.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSettingsPreferenceConst.java @@ -374,6 +374,7 @@ public class DeviceSettingsPreferenceConst { public static final String PREF_NOTHING_EAR1_INEAR = "pref_nothing_inear_detection"; public static final String PREF_NOTHING_EAR1_AUDIOMODE = "pref_nothing_audiomode"; + public static final String PREF_HEADPHONES_LOW_LATENCY = "pref_headphones_low_latency"; public static final String PREF_HUAWEI_FREEBUDS_INEAR = "pref_freebuds_inear_detection"; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSpecificSettingsFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSpecificSettingsFragment.java index 3cf1f7ec39..eadb648871 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSpecificSettingsFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSpecificSettingsFragment.java @@ -730,6 +730,7 @@ public class DeviceSpecificSettingsFragment extends AbstractPreferenceFragment i addPreferenceHandlerFor(PREF_NOTHING_EAR1_INEAR); addPreferenceHandlerFor(PREF_NOTHING_EAR1_AUDIOMODE); + addPreferenceHandlerFor(PREF_HEADPHONES_LOW_LATENCY); addPreferenceHandlerFor(PREF_HUAWEI_FREEBUDS_INEAR); addPreferenceHandlerFor(PREF_HUAWEI_FREEBUDS_AUDIOMODE); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/nothing/AbstractEarCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/nothing/AbstractEarCoordinator.java index bcb45492e3..449ff140ec 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/nothing/AbstractEarCoordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/nothing/AbstractEarCoordinator.java @@ -66,6 +66,9 @@ public abstract class AbstractEarCoordinator extends AbstractBLClassicDeviceCoor public DeviceSpecificSettings getDeviceSpecificSettings(final GBDevice device) { final DeviceSpecificSettings deviceSpecificSettings = new DeviceSpecificSettings(); deviceSpecificSettings.addRootScreen(R.xml.devicesettings_nothing_ear1); + if (supportsLowLatency()) { + deviceSpecificSettings.addRootScreen(R.xml.devicesettings_headphones_low_latency); + } deviceSpecificSettings.addRootScreen(R.xml.devicesettings_headphones); return deviceSpecificSettings; } @@ -93,4 +96,8 @@ public abstract class AbstractEarCoordinator extends AbstractBLClassicDeviceCoor public abstract boolean supportsAdaptiveAnc(); public abstract boolean supportsMediumAnc(); + + public boolean supportsLowLatency() { + return false; + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/nothing/CmfBuds2aCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/nothing/CmfBuds2aCoordinator.java index 369811e810..7617c27551 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/nothing/CmfBuds2aCoordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/nothing/CmfBuds2aCoordinator.java @@ -55,9 +55,19 @@ public class CmfBuds2aCoordinator extends AbstractEarCoordinator { public boolean supportsTransparency() { return true; } - @Override - public boolean supportsMediumAnc() { return false; } @Override - public boolean supportsAdaptiveAnc() { return false; } + public boolean supportsMediumAnc() { + return false; + } + + @Override + public boolean supportsAdaptiveAnc() { + return false; + } + + @Override + public boolean supportsLowLatency() { + return true; + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/nothing/Ear1Support.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/nothing/Ear1Support.java index 64a9d06396..c8b6d88df9 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/nothing/Ear1Support.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/nothing/Ear1Support.java @@ -128,6 +128,13 @@ public class Ear1Support extends AbstractHeadphoneBTBRDeviceSupport { sendCommand("set audio mode", nothingProtocol.encodeAudioMode(prefs.getString(DeviceSettingsPreferenceConst.PREF_NOTHING_EAR1_AUDIOMODE, "off"))); // response: 55 20 01 0F 70 00 00 00 break; + case DeviceSettingsPreferenceConst.PREF_HEADPHONES_LOW_LATENCY: + sendCommand("set low latency", nothingProtocol.encodeLowLatency(prefs.getBoolean(DeviceSettingsPreferenceConst.PREF_HEADPHONES_LOW_LATENCY, false))); + // ON: 55 6001 40F0 0100 34 01 47 0253 + // ON Response: 55 6001 4070 0000 34 FF FF95 + // OFF: 55 6001 40F0 0100 5C 02 28 9353 + // OFF Response: 55 6001 4070 0000 5C FF FF95 + break; default: LOG.debug("CONFIG: " + config); break; @@ -158,6 +165,7 @@ public class Ear1Support extends AbstractHeadphoneBTBRDeviceSupport { private static final short firmware_version = (short) 0xc042; private static final short audio_mode_status = (short) 0xc01e; private static final short audio_mode_status2 = (short) 0xe003; + private static final short low_latency = (short) 0xf040; private static final short unk_maybe_ack = (short) 0xf002; private static final short unk_close_case = (short) 0xe002; //sent twice when the case is closed with earphones in @@ -359,6 +367,11 @@ public class Ear1Support extends AbstractHeadphoneBTBRDeviceSupport { return encodeMessage((short) 0x120, audio_mode, payload); } + byte[] encodeLowLatency(boolean enabled) { + final byte payload = (byte) (enabled ? 0x01 : 0x02); + return encodeMessage((short) 0x120, low_latency, new byte[]{payload}); + } + public byte[] encodeFindDevice(boolean start) { byte payload = (byte) (start ? 0x01 : 0x00); return encodeMessage((short) 0x120, find_device, new byte[]{payload}); diff --git a/app/src/main/res/xml/devicesettings_headphones_low_latency.xml b/app/src/main/res/xml/devicesettings_headphones_low_latency.xml new file mode 100644 index 0000000000..b3de6b30c9 --- /dev/null +++ b/app/src/main/res/xml/devicesettings_headphones_low_latency.xml @@ -0,0 +1,10 @@ + + + +