1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-12-25 10:05:49 +01:00

Sony WH-1000XM4: Add speak-to-chat

This commit is contained in:
José Rebelo 2023-03-23 21:50:40 +00:00
parent da001544c5
commit d7ecfcb16b
8 changed files with 128 additions and 2 deletions

View File

@ -23,6 +23,7 @@ public enum SonyHeadphonesCapabilities {
PowerOffFromPhone,
AmbientSoundControl,
WindNoiseReduction,
SpeakToChat,
AncOptimizer,
AudioSettingsOnlyOnSbcCodec,
AudioUpsampling,

View File

@ -178,6 +178,10 @@ public abstract class SonyHeadphonesCoordinator extends AbstractBLClassicDeviceC
settings.add(R.xml.devicesettings_sony_headphones_ambient_sound_control);
}
if (supports(SonyHeadphonesCapabilities.SpeakToChat)) {
settings.add(R.xml.devicesettings_sony_headphones_speak_to_chat_simple);
}
if (supports(SonyHeadphonesCapabilities.AncOptimizer)) {
settings.add(R.xml.devicesettings_sony_headphones_anc_optimizer);
}

View File

@ -51,6 +51,7 @@ public class SonyWH1000XM4Coordinator extends SonyHeadphonesCoordinator {
SonyHeadphonesCapabilities.BatterySingle,
SonyHeadphonesCapabilities.AmbientSoundControl,
SonyHeadphonesCapabilities.WindNoiseReduction,
SonyHeadphonesCapabilities.SpeakToChat,
SonyHeadphonesCapabilities.AncOptimizer,
SonyHeadphonesCapabilities.EqualizerWithCustomBands,
SonyHeadphonesCapabilities.AudioUpsampling,

View File

@ -0,0 +1,53 @@
/* Copyright (C) 2023 José Rebelo
This file is part of Gadgetbridge.
Gadgetbridge is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Gadgetbridge 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs;
import android.content.SharedPreferences;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst;
public class SpeakToChat {
private final boolean enabled;
public SpeakToChat(final boolean enabled) {
this.enabled = enabled;
}
public String toString() {
return String.format(Locale.getDefault(), "SpeakToChat{enabled=%s}", enabled);
}
public boolean isEnabled() {
return enabled;
}
public Map<String, Object> toPreferences() {
return new HashMap<String, Object>() {{
put(DeviceSettingsPreferenceConst.PREF_SONY_SPEAK_TO_CHAT, enabled);
}};
}
public static SpeakToChat fromPreferences(final SharedPreferences prefs) {
final boolean enabled = prefs.getBoolean(DeviceSettingsPreferenceConst.PREF_SONY_SPEAK_TO_CHAT, false);
return new SpeakToChat(enabled);
}
}

View File

@ -40,6 +40,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.Equali
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.EqualizerPreset;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.PauseWhenTakenOff;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.QuickAccess;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.SpeakToChat;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.VoiceNotifications;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.SoundPosition;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.SurroundMode;
@ -223,8 +224,8 @@ public class SonyHeadphonesProtocol extends GBDeviceProtocol {
case DeviceSettingsPreferenceConst.PREF_SONY_SPEAK_TO_CHAT_SENSITIVITY:
case DeviceSettingsPreferenceConst.PREF_SONY_SPEAK_TO_CHAT_FOCUS_ON_VOICE:
case DeviceSettingsPreferenceConst.PREF_SONY_SPEAK_TO_CHAT_TIMEOUT:
LOG.warn("Speak-to-chat is not implemented ('{}')", config);
return super.encodeSendConfiguration(config);
configRequest = protocolImpl.setSpeakToChat(SpeakToChat.fromPreferences(prefs));
break;
default:
LOG.warn("Unknown config '{}'", config);
return super.encodeSendConfiguration(config);

View File

@ -30,6 +30,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.Equali
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.PauseWhenTakenOff;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.QuickAccess;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.SoundPosition;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.SpeakToChat;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.SurroundMode;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.TouchSensor;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.VoiceNotifications;
@ -58,6 +59,10 @@ public abstract class AbstractSonyProtocolImpl {
public abstract Request setAmbientSoundControl(final AmbientSoundControl config);
public abstract Request setSpeakToChat(final SpeakToChat config);
public abstract Request getSpeakToChat();
public abstract Request getNoiseCancellingOptimizerState();
public abstract Request getAudioCodec();

View File

@ -50,6 +50,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.Equali
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.PauseWhenTakenOff;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.QuickAccess;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.SoundPosition;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.SpeakToChat;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.SurroundMode;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.TouchSensor;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.VoiceNotifications;
@ -139,6 +140,30 @@ public class SonyProtocolImplV1 extends AbstractSonyProtocolImpl {
return new Request(PayloadTypeV1.AMBIENT_SOUND_CONTROL_SET.getMessageType(), buf.array());
}
@Override
public Request setSpeakToChat(final SpeakToChat config) {
return new Request(
PayloadTypeV1.AUTOMATIC_POWER_OFF_BUTTON_MODE_SET.getMessageType(),
new byte[]{
PayloadTypeV1.AUTOMATIC_POWER_OFF_BUTTON_MODE_SET.getCode(),
(byte) 0x05,
(byte) 0x01,
(byte) (config.isEnabled() ? 0x01 : 0x00)
}
);
}
@Override
public Request getSpeakToChat() {
return new Request(
PayloadTypeV1.AUTOMATIC_POWER_OFF_BUTTON_MODE_GET.getMessageType(),
new byte[]{
PayloadTypeV1.AUTOMATIC_POWER_OFF_BUTTON_MODE_GET.getCode(),
(byte) 0x05
}
);
}
@Override
public Request getNoiseCancellingOptimizerState() {
return new Request(
@ -542,6 +567,7 @@ public class SonyProtocolImplV1 extends AbstractSonyProtocolImpl {
put(SonyHeadphonesCapabilities.EqualizerWithCustomBands, getEqualizer());
put(SonyHeadphonesCapabilities.SoundPosition, getSoundPosition());
put(SonyHeadphonesCapabilities.SurroundMode, getSurroundMode());
put(SonyHeadphonesCapabilities.SpeakToChat, getSpeakToChat());
put(SonyHeadphonesCapabilities.PauseWhenTakenOff, getPauseWhenTakenOff());
put(SonyHeadphonesCapabilities.AmbientSoundControlButtonMode, getAmbientSoundControlButtonMode());
put(SonyHeadphonesCapabilities.QuickAccess, getQuickAccess());
@ -707,6 +733,26 @@ public class SonyProtocolImplV1 extends AbstractSonyProtocolImpl {
return Collections.singletonList(event);
}
public List<? extends GBDeviceEvent> handleSpeakToChat(final byte[] payload) {
if (payload.length != 4) {
LOG.warn("Unexpected payload length {}", payload.length);
return Collections.emptyList();
}
final Boolean enabled = booleanFromByte(payload[3]);
if (enabled == null) {
LOG.warn("Unknown speak to chat code {}", String.format("%02x", payload[3]));
return Collections.emptyList();
}
LOG.debug("Speak to chat: {}", enabled);
final GBDeviceEventUpdatePreferences event = new GBDeviceEventUpdatePreferences()
.withPreferences(new SpeakToChat(enabled).toPreferences());
return Collections.singletonList(event);
}
public List<? extends GBDeviceEvent> handleButtonModes(final byte[] payload) {
if (payload.length != 5) {
LOG.warn("Unexpected payload length {}", payload.length);
@ -907,6 +953,8 @@ public class SonyProtocolImplV1 extends AbstractSonyProtocolImpl {
return handleAutomaticPowerOff(payload);
case 0x03:
return handlePauseWhenTakenOff(payload);
case 0x05:
return handleSpeakToChat(payload);
case 0x06:
return handleButtonModes(payload);
}

View File

@ -41,6 +41,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.Equali
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.PauseWhenTakenOff;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.QuickAccess;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.SoundPosition;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.SpeakToChat;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.SurroundMode;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.TouchSensor;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.prefs.VoiceNotifications;
@ -104,6 +105,18 @@ public class SonyProtocolImplV2 extends SonyProtocolImplV1 {
return new Request(PayloadTypeV1.AMBIENT_SOUND_CONTROL_SET.getMessageType(), buf.array());
}
@Override
public Request setSpeakToChat(SpeakToChat config) {
LOG.warn("Speak-to-chat not implemented for V2");
return null;
}
@Override
public Request getSpeakToChat() {
LOG.warn("Speak-to-chat not implemented for V2");
return null;
}
@Override
public Request getNoiseCancellingOptimizerState() {
LOG.warn("Noise cancelling optimizer not implemented for V2");