Merge "Dynamic Audio Buffer (2/3)"
diff --git a/jni/com_android_bluetooth_btservice_AdapterService.cpp b/jni/com_android_bluetooth_btservice_AdapterService.cpp
index 42d0ce7..38969dd 100644
--- a/jni/com_android_bluetooth_btservice_AdapterService.cpp
+++ b/jni/com_android_bluetooth_btservice_AdapterService.cpp
@@ -1239,6 +1239,16 @@
return output_bytes;
}
+static jboolean setBufferMillisNative(JNIEnv* env, jobject obj, jint codec,
+ jint size) {
+ ALOGV("%s", __func__);
+
+ if (!sBluetoothInterface) return JNI_FALSE;
+
+ int ret = sBluetoothInterface->set_dynamic_audio_buffer_size(codec, size);
+ return (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
+}
+
static jint connectSocketNative(JNIEnv* env, jobject obj, jbyteArray address,
jint type, jbyteArray uuid, jint port,
jint flag, jint callingUid) {
@@ -1365,6 +1375,7 @@
{"interopDatabaseClearNative", "()V", (void*)interopDatabaseClearNative},
{"interopDatabaseAddNative", "(I[BI)V", (void*)interopDatabaseAddNative},
{"obfuscateAddressNative", "([B)[B", (void*)obfuscateAddressNative},
+ {"setBufferMillisNative", "(II)Z", (void*)setBufferMillisNative},
{"getMetricIdNative", "([B)I", (void*)getMetricIdNative},
{"connectSocketNative", "([BI[BIII)I", (void*)connectSocketNative},
{"createSocketChannelNative", "(ILjava/lang/String;[BIII)I",
diff --git a/src/com/android/bluetooth/a2dp/A2dpService.java b/src/com/android/bluetooth/a2dp/A2dpService.java
index 5e5c68a..d68e68d 100644
--- a/src/com/android/bluetooth/a2dp/A2dpService.java
+++ b/src/com/android/bluetooth/a2dp/A2dpService.java
@@ -27,6 +27,7 @@
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
+import android.bluetooth.BufferConstraints;
import android.bluetooth.IBluetoothA2dp;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -873,6 +874,44 @@
mDatabaseManager.setA2dpOptionalCodecsEnabled(device, value);
}
+ /**
+ * Get dynamic audio buffer size supported type
+ *
+ * @return support <p>Possible values are
+ * {@link BluetoothA2dp#DYNAMIC_BUFFER_SUPPORT_NONE},
+ * {@link BluetoothA2dp#DYNAMIC_BUFFER_SUPPORT_A2DP_OFFLOAD},
+ * {@link BluetoothA2dp#DYNAMIC_BUFFER_SUPPORT_A2DP_SOFTWARE_ENCODING}.
+ */
+ public int getDynamicBufferSupport() {
+ enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED,
+ "Need BLUETOOTH_PRIVILEGED permission");
+ return mAdapterService.getDynamicBufferSupport();
+ }
+
+ /**
+ * Get dynamic audio buffer size
+ *
+ * @return BufferConstraints
+ */
+ public BufferConstraints getBufferConstraints() {
+ enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED,
+ "Need BLUETOOTH_PRIVILEGED permission");
+ return mAdapterService.getBufferConstraints();
+ }
+
+ /**
+ * Set dynamic audio buffer size
+ *
+ * @param codec Audio codec
+ * @param value buffer millis
+ * @return true if the settings is successful, false otherwise
+ */
+ public boolean setBufferMillis(int codec, int value) {
+ enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED,
+ "Need BLUETOOTH_PRIVILEGED permission");
+ return mAdapterService.setBufferMillis(codec, value);
+ }
+
// Handle messages from native (JNI) to Java
void messageFromNative(A2dpStackEvent stackEvent) {
Objects.requireNonNull(stackEvent.device,
@@ -1385,6 +1424,30 @@
}
service.setOptionalCodecsEnabled(device, value);
}
+
+ public int getDynamicBufferSupport() {
+ A2dpService service = getService();
+ if (service == null) {
+ return BluetoothA2dp.DYNAMIC_BUFFER_SUPPORT_NONE;
+ }
+ return service.getDynamicBufferSupport();
+ }
+
+ public BufferConstraints getBufferConstraints() {
+ A2dpService service = getService();
+ if (service == null) {
+ return null;
+ }
+ return service.getBufferConstraints();
+ }
+
+ public boolean setBufferMillis(int codec, int value) {
+ A2dpService service = getService();
+ if (service == null) {
+ return false;
+ }
+ return service.setBufferMillis(codec, value);
+ }
}
@Override
diff --git a/src/com/android/bluetooth/btservice/AbstractionLayer.java b/src/com/android/bluetooth/btservice/AbstractionLayer.java
index e15104d..203d3b0 100644
--- a/src/com/android/bluetooth/btservice/AbstractionLayer.java
+++ b/src/com/android/bluetooth/btservice/AbstractionLayer.java
@@ -48,6 +48,8 @@
static final int BT_PROPERTY_REMOTE_VERSION_INFO = 0x0C;
static final int BT_PROPERTY_LOCAL_LE_FEATURES = 0x0D;
+ static final int BT_PROPERTY_DYNAMIC_AUDIO_BUFFER = 0x10;
+
public static final int BT_DEVICE_TYPE_BREDR = 0x01;
public static final int BT_DEVICE_TYPE_BLE = 0x02;
public static final int BT_DEVICE_TYPE_DUAL = 0x03;
diff --git a/src/com/android/bluetooth/btservice/AdapterProperties.java b/src/com/android/bluetooth/btservice/AdapterProperties.java
index 2737082..f2a8c2a 100644
--- a/src/com/android/bluetooth/btservice/AdapterProperties.java
+++ b/src/com/android/bluetooth/btservice/AdapterProperties.java
@@ -34,6 +34,8 @@
import android.bluetooth.BluetoothPbapClient;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothSap;
+import android.bluetooth.BufferConstraint;
+import android.bluetooth.BufferConstraints;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -52,7 +54,9 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
class AdapterProperties {
@@ -115,6 +119,11 @@
private boolean mIsLePeriodicAdvertisingSupported;
private int mLeMaximumAdvertisingDataLength;
+ private int mIsDynamicAudioBufferSizeSupported;
+ private int mDynamicAudioBufferSizeSupportedCodecsGroup1;
+ private int mDynamicAudioBufferSizeSupportedCodecsGroup2;
+ private List<BufferConstraint> mBufferConstraintList;
+
private boolean mReceiverRegistered;
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
@@ -513,6 +522,44 @@
}
/**
+ * @return Dynamic Audio Buffer support
+ */
+ int getDynamicBufferSupport() {
+ if (!mA2dpOffloadEnabled) {
+ // TODO: Enable Dynamic Audio Buffer for A2DP software encoding when ready.
+ mIsDynamicAudioBufferSizeSupported =
+ BluetoothA2dp.DYNAMIC_BUFFER_SUPPORT_NONE;
+ } else {
+ if ((mDynamicAudioBufferSizeSupportedCodecsGroup1 != 0)
+ || (mDynamicAudioBufferSizeSupportedCodecsGroup2 != 0)) {
+ mIsDynamicAudioBufferSizeSupported =
+ BluetoothA2dp.DYNAMIC_BUFFER_SUPPORT_A2DP_OFFLOAD;
+ } else {
+ mIsDynamicAudioBufferSizeSupported =
+ BluetoothA2dp.DYNAMIC_BUFFER_SUPPORT_NONE;
+ }
+ }
+ return mIsDynamicAudioBufferSizeSupported;
+ }
+
+ /**
+ * @return Dynamic Audio Buffer Capability
+ */
+ BufferConstraints getBufferConstraints() {
+ return new BufferConstraints(mBufferConstraintList);
+ }
+
+ /**
+ * Set the dynamic audio buffer size
+ *
+ * @param codec the codecs to set
+ * @param size the size to set
+ */
+ boolean setBufferMillis(int codec, int value) {
+ return mService.setBufferMillisNative(codec, value);
+ }
+
+ /**
* @return the mBondedDevices
*/
BluetoothDevice[] getBondedDevices() {
@@ -860,6 +907,10 @@
updateFeatureSupport(val);
break;
+ case AbstractionLayer.BT_PROPERTY_DYNAMIC_AUDIO_BUFFER:
+ updateDynamicAudioBufferSupport(val);
+ break;
+
case AbstractionLayer.BT_PROPERTY_LOCAL_IO_CAPS:
mLocalIOCapability = Utils.byteArrayToInt(val);
debugLog("mLocalIOCapability set to " + mLocalIOCapability);
@@ -894,6 +945,10 @@
mIsLePeriodicAdvertisingSupported = ((0xFF & ((int) val[17])) != 0);
mLeMaximumAdvertisingDataLength =
(0xFF & ((int) val[18])) + ((0xFF & ((int) val[19])) << 8);
+ mDynamicAudioBufferSizeSupportedCodecsGroup1 =
+ ((0xFF & ((int) val[21])) << 8) + (0xFF & ((int) val[20]));
+ mDynamicAudioBufferSizeSupportedCodecsGroup2 =
+ ((0xFF & ((int) val[23])) << 8) + (0xFF & ((int) val[22]));
Log.d(TAG, "BT_PROPERTY_LOCAL_LE_FEATURES: update from BT controller"
+ " mNumOfAdvertisementInstancesSupported = "
@@ -909,10 +964,36 @@
+ mIsLe2MPhySupported + " mIsLeCodedPhySupported = " + mIsLeCodedPhySupported
+ " mIsLeExtendedAdvertisingSupported = " + mIsLeExtendedAdvertisingSupported
+ " mIsLePeriodicAdvertisingSupported = " + mIsLePeriodicAdvertisingSupported
- + " mLeMaximumAdvertisingDataLength = " + mLeMaximumAdvertisingDataLength);
+ + " mLeMaximumAdvertisingDataLength = " + mLeMaximumAdvertisingDataLength
+ + " mDynamicAudioBufferSizeSupportedCodecsGroup1 = "
+ + mDynamicAudioBufferSizeSupportedCodecsGroup1
+ + " mDynamicAudioBufferSizeSupportedCodecsGroup2 = "
+ + mDynamicAudioBufferSizeSupportedCodecsGroup2);
invalidateIsOffloadedFilteringSupportedCache();
}
+ private void updateDynamicAudioBufferSupport(byte[] val) {
+ // bufferConstraints is the table indicates the capability of all the codecs
+ // with buffer time. The raw is codec number, and the column is buffer type. There are 3
+ // buffer types - default/maximum/minimum.
+ // The maximum number of raw is BUFFER_CODEC_MAX_NUM(32).
+ // The maximum number of column is BUFFER_TYPE_MAX(3).
+ // The array element indicates the buffer time, the size is two octet.
+ mBufferConstraintList = new ArrayList<BufferConstraint>();
+
+ for (int i = 0; i < BufferConstraints.BUFFER_CODEC_MAX_NUM; i++) {
+ int defaultBufferTime = ((0xFF & ((int) val[i * 6 + 1])) << 8)
+ + (0xFF & ((int) val[i * 6]));
+ int maximumBufferTime = ((0xFF & ((int) val[i * 6 + 3])) << 8)
+ + (0xFF & ((int) val[i * 6 + 2]));
+ int minimumBufferTime = ((0xFF & ((int) val[i * 6 + 5])) << 8)
+ + (0xFF & ((int) val[i * 6 + 4]));
+ BufferConstraint bufferConstraint = new BufferConstraint(defaultBufferTime,
+ maximumBufferTime, minimumBufferTime);
+ mBufferConstraintList.add(bufferConstraint);
+ }
+ }
+
void onBluetoothReady() {
debugLog("onBluetoothReady, state=" + BluetoothAdapter.nameForState(getState())
+ ", ScanMode=" + mScanMode);
diff --git a/src/com/android/bluetooth/btservice/AdapterService.java b/src/com/android/bluetooth/btservice/AdapterService.java
index dbcfd58..05fb852 100644
--- a/src/com/android/bluetooth/btservice/AdapterService.java
+++ b/src/com/android/bluetooth/btservice/AdapterService.java
@@ -32,6 +32,7 @@
import android.app.PendingIntent;
import android.app.Service;
import android.app.admin.DevicePolicyManager;
+import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothActivityEnergyInfo;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothAdapter.ActiveDeviceUse;
@@ -40,6 +41,7 @@
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothProtoEnums;
import android.bluetooth.BluetoothUuid;
+import android.bluetooth.BufferConstraints;
import android.bluetooth.IBluetooth;
import android.bluetooth.IBluetoothCallback;
import android.bluetooth.IBluetoothConnectionCallback;
@@ -3194,6 +3196,38 @@
}
/**
+ * Get dynamic audio buffer size supported type
+ *
+ * @return support <p>Possible values are
+ * {@link BluetoothA2dp#DYNAMIC_BUFFER_SUPPORT_NONE},
+ * {@link BluetoothA2dp#DYNAMIC_BUFFER_SUPPORT_A2DP_OFFLOAD},
+ * {@link BluetoothA2dp#DYNAMIC_BUFFER_SUPPORT_A2DP_SOFTWARE_ENCODING}.
+ */
+ public int getDynamicBufferSupport() {
+ return mAdapterProperties.getDynamicBufferSupport();
+ }
+
+ /**
+ * Get dynamic audio buffer size
+ *
+ * @return BufferConstraints
+ */
+ public BufferConstraints getBufferConstraints() {
+ return mAdapterProperties.getBufferConstraints();
+ }
+
+ /**
+ * Set dynamic audio buffer size
+ *
+ * @param codec Audio codec
+ * @param value buffer millis
+ * @return true if the settings is successful, false otherwise
+ */
+ public boolean setBufferMillis(int codec, int value) {
+ return mAdapterProperties.setBufferMillis(codec, value);
+ }
+
+ /**
* Get an incremental id of Bluetooth metrics and log
*
* @param device Bluetooth device
@@ -3286,6 +3320,8 @@
private native byte[] obfuscateAddressNative(byte[] address);
+ native boolean setBufferMillisNative(int codec, int value);
+
private native int getMetricIdNative(byte[] address);
/*package*/ native int connectSocketNative(