Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 16f2a5b0 authored by Phaneendra Reddy's avatar Phaneendra Reddy Committed by Jakub Rotkiewicz
Browse files

AptX Voice SWB power management

Handle SWB codec selection based on network type
and codecs selected over network during call
initiation.

Bug: 308497929
Bug: 293574035
Test: atest HeadsetServiceAndStateMachineTest
Test: atest bt_host_test_bta
Change-Id: If97ab81c3f7e00ac8f38d41c3f0e2e3d438f34be
parent d30b94bd
Loading
Loading
Loading
Loading
+27 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include <mutex>
#include <shared_mutex>

#include "btif/include/btif_hf.h"
#include "com_android_bluetooth.h"
#include "hardware/bluetooth_headset_callbacks.h"
#include "hardware/bluetooth_headset_interface.h"
@@ -954,6 +955,31 @@ static jboolean setActiveDeviceNative(JNIEnv* env, jobject /* object */,
  return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}

static jboolean enableSwbNative(JNIEnv* env, jobject /* object */,
                                jint swbCodec, jboolean enable,
                                jbyteArray address) {
  std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
  if (!sBluetoothHfpInterface) {
    ALOGW("%s: sBluetoothHfpInterface is null", __func__);
    return JNI_FALSE;
  }
  jbyte* addr = env->GetByteArrayElements(address, NULL);
  if (!addr) {
    ALOGE("%s: failed to get device address", __func__);
    jniThrowIOException(env, EINVAL);
    return JNI_FALSE;
  }
  bt_status_t ret = sBluetoothHfpInterface->EnableSwb(
      (bluetooth::headset::bthf_swb_codec_t)swbCodec, (bool)enable,
      (RawAddress*)addr);
  if (ret != BT_STATUS_SUCCESS) {
    ALOGE("%s: Failed to %s", __func__, (enable ? "enable" : "disable"));
    return JNI_FALSE;
  }
  ALOGV("%s: Successfully %s", __func__, (enable ? "enabled" : "disabled"));
  return JNI_TRUE;
}

int register_com_android_bluetooth_hfp(JNIEnv* env) {
  const JNINativeMethod methods[] = {
      {"initializeNative", "(IZ)V", (void*)initializeNative},
@@ -987,6 +1013,7 @@ int register_com_android_bluetooth_hfp(JNIEnv* env) {
      {"setScoAllowedNative", "(Z)Z", (void*)setScoAllowedNative},
      {"sendBsirNative", "(Z[B)Z", (void*)sendBsirNative},
      {"setActiveDeviceNative", "([B)Z", (void*)setActiveDeviceNative},
      {"enableSwbNative", "(IZ[B)Z", (void*)enableSwbNative},
  };
  const int result = REGISTER_NATIVE_METHODS(
      env, "com/android/bluetooth/hfp/HeadsetNativeInterface", methods);
+15 −0
Original line number Diff line number Diff line
@@ -512,6 +512,19 @@ public class HeadsetNativeInterface {
        return setActiveDeviceNative(getByteAddress(device));
    }

    /**
     * Enable Super Wide Band
     *
     * @param swbCodec SWB Codec
     * @param enable True to enable, False to disable
     * @param device current active SCO device
     * @return True on success, False on failure
     */
    @VisibleForTesting
    public boolean enableSwb(int swbCodec, boolean enable, BluetoothDevice device) {
        return enableSwbNative(swbCodec, enable, getByteAddress(device));
    }

    /* Native methods */
    private native boolean atResponseCodeNative(int responseCode, int errorCode, byte[] address);

@@ -558,4 +571,6 @@ public class HeadsetNativeInterface {
    private native boolean sendBsirNative(boolean value, byte[] address);

    private native boolean setActiveDeviceNative(byte[] address);

    private native boolean enableSwbNative(int swbCodec, boolean enable, byte[] address);
}
+49 −1
Original line number Diff line number Diff line
@@ -154,12 +154,14 @@ public class HeadsetService extends ProfileService {
    private boolean mStarted;
    private static HeadsetService sHeadsetService;

    @VisibleForTesting boolean mIsAptXSwbEnabled = false;
    @VisibleForTesting boolean mIsAptXSwbPmEnabled = false;

    private final ServiceFactory mFactory = new ServiceFactory();

    public HeadsetService(Context ctx) {
        super(ctx);
    }

    public static boolean isEnabled() {
        return BluetoothProperties.isProfileHfpAgEnabled().orElse(false);
    }
@@ -190,11 +192,26 @@ public class HeadsetService extends ProfileService {
        // Step 3: Initialize system interface
        mSystemInterface = HeadsetObjectsFactory.getInstance().makeSystemInterface(this);
        // Step 4: Initialize native interface
        if (Flags.hfpCodecAptxVoice()) {
            mIsAptXSwbEnabled =
                    SystemProperties.getBoolean("bluetooth.hfp.codec_aptx_voice.enabled", false);
            Log.i(TAG, "mIsAptXSwbEnabled: " + mIsAptXSwbEnabled);
            mIsAptXSwbPmEnabled =
                    SystemProperties.getBoolean(
                            "bluetooth.hfp.swb.aptx.power_management.enabled", false);
            Log.i(TAG, "mIsAptXSwbPmEnabled: " + mIsAptXSwbPmEnabled);
        }
        setHeadsetService(this);
        mMaxHeadsetConnections = mAdapterService.getMaxConnectedAudioDevices();
        mNativeInterface = HeadsetObjectsFactory.getInstance().getNativeInterface();
        // Add 1 to allow a pending device to be connecting or disconnecting
        mNativeInterface.init(mMaxHeadsetConnections + 1, isInbandRingingEnabled());
        if (Flags.hfpCodecAptxVoice()) {
            enableSwbCodec(
                    HeadsetHalConstants.BTHF_SWB_CODEC_VENDOR_APTX,
                    mIsAptXSwbEnabled,
                    mActiveDevice);
        }
        // Step 5: Check if state machine table is empty, crash if not
        if (mStateMachines.size() > 0) {
            throw new IllegalStateException(
@@ -1207,6 +1224,9 @@ public class HeadsetService extends ProfileService {
            }
            stateMachine.sendMessage(HeadsetStateMachine.CONNECT_AUDIO, device);
        }
        if (Flags.hfpCodecAptxVoice()) {
            enableSwbCodec(HeadsetHalConstants.BTHF_SWB_CODEC_VENDOR_APTX, true, device);
        }
        return true;
    }

@@ -1241,6 +1261,9 @@ public class HeadsetService extends ProfileService {
            }
            stateMachine.sendMessage(HeadsetStateMachine.DISCONNECT_AUDIO, device);
        }
        if (Flags.hfpCodecAptxVoice()) {
            enableSwbCodec(HeadsetHalConstants.BTHF_SWB_CODEC_VENDOR_APTX, false, device);
        }
        return true;
    }

@@ -1805,6 +1828,9 @@ public class HeadsetService extends ProfileService {
            if (!mSystemInterface.getVoiceRecognitionWakeLock().isHeld()) {
                mSystemInterface.getVoiceRecognitionWakeLock().acquire(sStartVrTimeoutMs);
            }
            if (Flags.hfpCodecAptxVoice()) {
                enableSwbCodec(HeadsetHalConstants.BTHF_SWB_CODEC_VENDOR_APTX, true, fromDevice);
            }
            return true;
        }
    }
@@ -1843,6 +1869,9 @@ public class HeadsetService extends ProfileService {
                Log.w(TAG, "stopVoiceRecognitionByHeadset: failed request from " + fromDevice);
                return false;
            }
            if (Flags.hfpCodecAptxVoice()) {
                enableSwbCodec(HeadsetHalConstants.BTHF_SWB_CODEC_VENDOR_APTX, false, fromDevice);
            }
            return true;
        }
    }
@@ -2363,6 +2392,25 @@ public class HeadsetService extends ProfileService {
        }
    }

    /** Enable SWB Codec. */
    void enableSwbCodec(int swbCodec, boolean enable, BluetoothDevice device) {
        logD("enableSwbCodec: swbCodec: " + swbCodec + " enable: " + enable + " device: " + device);
        boolean result = mNativeInterface.enableSwb(swbCodec, enable, device);
        logD("enableSwbCodec result: " + result);
    }

    /** Check whether AptX SWB Codec is enabled. */
    boolean isAptXSwbEnabled() {
        logD("mIsAptXSwbEnabled: " + mIsAptXSwbEnabled);
        return mIsAptXSwbEnabled;
    }

    /** Check whether AptX SWB Codec Power Management is enabled. */
    boolean isAptXSwbPmEnabled() {
        logD("isAptXSwbPmEnabled: " + mIsAptXSwbPmEnabled);
        return mIsAptXSwbPmEnabled;
    }

    private static void logD(String message) {
        if (DBG) {
            Log.d(TAG, message);
+58 −9
Original line number Diff line number Diff line
@@ -36,7 +36,6 @@ import android.os.Build;
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.telephony.PhoneNumberUtils;
import android.telephony.PhoneStateListener;
@@ -168,10 +167,6 @@ public class HeadsetStateMachine extends StateMachine {

    private BluetoothSinkAudioPolicy mHsClientAudioPolicy;

    static final boolean IS_APTX_SUPPORT_ENABLED =
            Flags.hfpCodecAptxVoice()
                    && SystemProperties.getBoolean("bluetooth.hfp.codec_aptx_voice.enabled", false);

    // Keys are AT commands, and values are the company IDs.
    private static final Map<String, Integer> VENDOR_SPECIFIC_AT_COMMAND_COMPANY_ID;

@@ -494,6 +489,39 @@ public class HeadsetStateMachine extends StateMachine {
         */
        abstract int getAudioStateInt();

        protected void setAptxVoice(HeadsetCallState callState) {
            if (!Flags.hfpCodecAptxVoice()) {
                return;
            }
            if (!mHeadsetService.isAptXSwbEnabled()) {
                return;
            }
            if (!mHeadsetService.isAptXSwbPmEnabled()) {
                return;
            }
            if (mHeadsetService.isVirtualCallStarted()) {
                stateLogD("CALL_STATE_CHANGED: enable AptX SWB for all voip calls ");
                mHeadsetService.enableSwbCodec(
                        HeadsetHalConstants.BTHF_SWB_CODEC_VENDOR_APTX, true, mDevice);
            } else if ((callState.mCallState == HeadsetHalConstants.CALL_STATE_DIALING)
                    || (callState.mCallState == HeadsetHalConstants.CALL_STATE_INCOMING)
                    || ((callState.mCallState == HeadsetHalConstants.CALL_STATE_IDLE)
                            && (callState.mNumActive > 0))) {
                if (!mSystemInterface.isHighDefCallInProgress()) {
                    stateLogD("CALL_STATE_CHANGED: disable AptX SWB for non-HD call ");
                    mHeadsetService.enableSwbCodec(
                            HeadsetHalConstants.BTHF_SWB_CODEC_VENDOR_APTX, false, mDevice);
                    mHasSwbAptXEnabled = false;
                } else {
                    stateLogD("CALL_STATE_CHANGED: enable AptX SWB for HD call ");
                    mHeadsetService.enableSwbCodec(
                            HeadsetHalConstants.BTHF_SWB_CODEC_VENDOR_APTX, true, mDevice);
                    mHasSwbAptXEnabled = true;
                }
            } else {
                stateLogD("CALL_STATE_CHANGED: AptX SWB state unchanged");
            }
        }
    }

    class Disconnected extends HeadsetStateBase {
@@ -696,7 +724,8 @@ public class HeadsetStateMachine extends StateMachine {
                    break;
                }
                case CALL_STATE_CHANGED:
                    stateLogD("ignoring CALL_STATE_CHANGED event");
                    HeadsetCallState callState = (HeadsetCallState) message.obj;
                    setAptxVoice(callState);
                    break;
                case DEVICE_STATE_CHANGED:
                    stateLogD("ignoring DEVICE_STATE_CHANGED event");
@@ -958,14 +987,15 @@ public class HeadsetStateMachine extends StateMachine {
                    }
                    break;
                }
                case CALL_STATE_CHANGED: {
                case CALL_STATE_CHANGED:
                    HeadsetCallState callState = (HeadsetCallState) message.obj;
                    setAptxVoice(callState);

                    if (!mNativeInterface.phoneStateChange(mDevice, callState)) {
                        stateLogW("processCallState: failed to update call state " + callState);
                        break;
                    }
                    break;
                }
                case DEVICE_STATE_CHANGED:
                    if (mDeviceSilenced) {
                        stateLogW("DEVICE_STATE_CHANGED: " + mDevice
@@ -1200,6 +1230,22 @@ public class HeadsetStateMachine extends StateMachine {
                    if (isAtLeastU()) {
                        mSystemInterface.getAudioManager().setLeAudioSuspended(true);
                    }

                    if (Flags.hfpCodecAptxVoice()
                            && mHeadsetService.isAptXSwbEnabled()
                            && mHeadsetService.isAptXSwbPmEnabled()) {
                        if (!mHeadsetService.isVirtualCallStarted()
                                && mSystemInterface.isHighDefCallInProgress()) {
                            stateLogD("CONNECT_AUDIO: enable AptX SWB for HD call ");
                            mHeadsetService.enableSwbCodec(
                                    HeadsetHalConstants.BTHF_SWB_CODEC_VENDOR_APTX, true, mDevice);
                        } else {
                            stateLogD("CONNECT_AUDIO: disable AptX SWB for non-HD or Voip calls");
                            mHeadsetService.enableSwbCodec(
                                    HeadsetHalConstants.BTHF_SWB_CODEC_VENDOR_APTX, false, mDevice);
                        }
                    }

                    if (!mNativeInterface.connectAudio(mDevice)) {
                        mSystemInterface.getAudioManager().setA2dpSuspended(false);
                        if (isAtLeastU()) {
@@ -1703,7 +1749,7 @@ public class HeadsetStateMachine extends StateMachine {
                        + (" hasSwbEnabled=" + mHasSwbLc3Enabled)
                        + (" hasAptXSwbEnabled=" + mHasSwbAptXEnabled));
        am.setParameters("bt_lc3_swb=" + (mHasSwbLc3Enabled ? "on" : "off"));
        if (IS_APTX_SUPPORT_ENABLED) {
        if (Flags.hfpCodecAptxVoice() && mHeadsetService.isAptXSwbEnabled()) {
            /* AptX bt_swb: 0 -> on, 65535 -> off */
            am.setParameters("bt_swb=" + (mHasSwbAptXEnabled ? "0" : "65535"));
        }
@@ -1851,6 +1897,9 @@ public class HeadsetStateMachine extends StateMachine {
        switch (wbsConfig) {
            case HeadsetHalConstants.BTHF_WBS_YES:
                mHasWbsEnabled = true;
                if (Flags.hfpCodecAptxVoice() && mHeadsetService.isAptXSwbEnabled()) {
                    mHasSwbAptXEnabled = false;
                }
                break;
            case HeadsetHalConstants.BTHF_WBS_NO:
            case HeadsetHalConstants.BTHF_WBS_NONE:
+12 −0
Original line number Diff line number Diff line
@@ -240,6 +240,18 @@ public class HeadsetSystemInterface {
        return false;
    }

    /** Check for HD codec for voice call */
    @VisibleForTesting
    public boolean isHighDefCallInProgress() {
        BluetoothInCallService bluetoothInCallService = getBluetoothInCallServiceInstance();
        if (bluetoothInCallService != null) {
            return bluetoothInCallService.isHighDefCallInProgress();
        } else {
            Log.e(TAG, "Handsfree phone proxy null");
        }
        return false;
    }

    /**
     * Get the the alphabetic name of current registered operator.
     *
Loading