Loading android/app/jni/com_android_bluetooth_hfp.cpp +53 −0 Original line number Diff line number Diff line Loading @@ -42,6 +42,7 @@ static jmethodID method_onVolumeChanged; static jmethodID method_onDialCall; static jmethodID method_onSendDtmf; static jmethodID method_onNoiceReductionEnable; static jmethodID method_onWBS; static jmethodID method_onAtChld; static jmethodID method_onAtCnum; static jmethodID method_onAtCind; Loading @@ -67,6 +68,19 @@ static bool checkCallbackThread() { return true; } static jbyteArray marshall_bda(bt_bdaddr_t* bd_addr) { jbyteArray addr; addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)); if (!addr) { ALOGE("Fail to new jbyteArray bd addr"); checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); return NULL; } sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr); return addr; } static void connection_state_callback(bthf_connection_state_t state, bt_bdaddr_t* bd_addr) { jbyteArray addr; Loading Loading @@ -228,6 +242,19 @@ static void noice_reduction_callback(bthf_nrec_t nrec, bt_bdaddr_t* bd_addr) { sCallbackEnv->DeleteLocalRef(addr); } static void wbs_callback(bthf_wbs_config_t wbs_config, bt_bdaddr_t* bd_addr) { jbyteArray addr; CHECK_CALLBACK_ENV if ((addr = marshall_bda(bd_addr)) == NULL) return; sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onWBS, wbs_config, addr); checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); sCallbackEnv->DeleteLocalRef(addr); } static void at_chld_callback(bthf_chld_type_t chld, bt_bdaddr_t* bd_addr) { jbyteArray addr; Loading Loading @@ -361,6 +388,7 @@ static bthf_callbacks_t sBluetoothHfpCallbacks = { dial_call_callback, dtmf_cmd_callback, noice_reduction_callback, wbs_callback, at_chld_callback, at_cnum_callback, at_cind_callback, Loading @@ -387,6 +415,7 @@ static void classInitNative(JNIEnv* env, jclass clazz) { method_onDialCall = env->GetMethodID(clazz, "onDialCall", "(Ljava/lang/String;[B)V"); method_onSendDtmf = env->GetMethodID(clazz, "onSendDtmf", "(I[B)V"); method_onNoiceReductionEnable = env->GetMethodID(clazz, "onNoiceReductionEnable", "(Z[B)V"); method_onWBS = env->GetMethodID(clazz,"onWBS","(I[B)V"); method_onAtChld = env->GetMethodID(clazz, "onAtChld", "(I[B)V"); method_onAtCnum = env->GetMethodID(clazz, "onAtCnum", "([B)V"); method_onAtCind = env->GetMethodID(clazz, "onAtCind", "([B)V"); Loading Loading @@ -768,6 +797,29 @@ static jboolean phoneStateChangeNative(JNIEnv *env, jobject object, jint num_act return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } static jboolean configureWBSNative(JNIEnv *env, jobject object, jbyteArray address, jint codec_config) { jbyte *addr; bt_status_t status; if (!sBluetoothHfpInterface) return JNI_FALSE; addr = env->GetByteArrayElements(address, NULL); if (!addr) { jniThrowIOException(env, EINVAL); return JNI_FALSE; } if ((status = sBluetoothHfpInterface->configure_wbs((bt_bdaddr_t *)addr, (bthf_wbs_config_t)codec_config)) != BT_STATUS_SUCCESS){ ALOGE("Failed HF WBS codec config, status: %d", status); } env->ReleaseByteArrayElements(address, addr, 0); return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } static JNINativeMethod sMethods[] = { {"classInitNative", "()V", (void *) classInitNative}, {"initializeNative", "(I)V", (void *) initializeNative}, Loading @@ -786,6 +838,7 @@ static JNINativeMethod sMethods[] = { {"atResponseCodeNative", "(II[B)Z", (void *)atResponseCodeNative}, {"clccResponseNative", "(IIIIZLjava/lang/String;I[B)Z", (void *) clccResponseNative}, {"phoneStateChangeNative", "(IIILjava/lang/String;I)Z", (void *) phoneStateChangeNative}, {"configureWBSNative", "([BI)Z", (void *) configureWBSNative}, }; int register_com_android_bluetooth_hfp(JNIEnv* env) Loading android/app/src/com/android/bluetooth/hfp/HeadsetService.java +44 −0 Original line number Diff line number Diff line Loading @@ -278,6 +278,18 @@ public class HeadsetService extends ProfileService { } return service.sendVendorSpecificResultCode(device, command, arg); } public boolean enableWBS() { HeadsetService service = getService(); if (service == null) return false; return service.enableWBS(); } public boolean disableWBS() { HeadsetService service = getService(); if (service == null) return false; return service.disableWBS(); } }; //API methods Loading Loading @@ -513,4 +525,36 @@ public class HeadsetService extends ProfileService { return true; } boolean enableWBS() { // TODO(BT) BLUETOOTH or BLUETOOTH_ADMIN permission enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); if (!mStateMachine.isConnected()) { return false; } if (mStateMachine.isAudioOn()) { return false; } for (BluetoothDevice device: getConnectedDevices()) { mStateMachine.sendMessage(HeadsetStateMachine.ENABLE_WBS,device); } return true; } boolean disableWBS() { // TODO(BT) BLUETOOTH or BLUETOOTH_ADMIN permission enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); if (!mStateMachine.isConnected()) { return false; } if (mStateMachine.isAudioOn()) { return false; } for (BluetoothDevice device: getConnectedDevices()) { mStateMachine.sendMessage(HeadsetStateMachine.DISABLE_WBS,device); } return true; } } android/app/src/com/android/bluetooth/hfp/HeadsetStateMachine.java +51 −0 Original line number Diff line number Diff line Loading @@ -76,6 +76,7 @@ final class HeadsetStateMachine extends StateMachine { private static final String HEADSET_NAME = "bt_headset_name"; private static final String HEADSET_NREC = "bt_headset_nrec"; private static final String HEADSET_WBS = "bt_headset_wbs"; static final int CONNECT = 1; static final int DISCONNECT = 2; Loading @@ -97,6 +98,10 @@ final class HeadsetStateMachine extends StateMachine { static final int VIRTUAL_CALL_START = 14; static final int VIRTUAL_CALL_STOP = 15; static final int ENABLE_WBS = 16; static final int DISABLE_WBS = 17; private static final int STACK_EVENT = 101; private static final int DIALING_OUT_TIMEOUT = 102; private static final int START_VR_TIMEOUT = 103; Loading @@ -111,6 +116,9 @@ final class HeadsetStateMachine extends StateMachine { // Max number of HF connections at any time private int max_hf_connections = 2; private static final int NBS_CODEC = 1; private static final int WBS_CODEC = 2; // Keys are AT commands, and values are the company IDs. private static final Map<String, Integer> VENDOR_SPECIFIC_AT_COMMAND_COMPANY_ID; // Hash for storing the Audio Parameters like NREC for connected headsets Loading Loading @@ -528,6 +536,8 @@ final class HeadsetStateMachine extends StateMachine { mCurrentDevice = null; } processWBSEvent(0, device); /* disable WBS audio parameters */ if (mTargetDevice != null) { if (!connectHfpNative(getByteAddress(mTargetDevice))) { broadcastConnectionState(mTargetDevice, Loading Loading @@ -871,6 +881,18 @@ final class HeadsetStateMachine extends StateMachine { case VIRTUAL_CALL_STOP: terminateScoUsingVirtualVoiceCall(); break; case ENABLE_WBS: { BluetoothDevice device = (BluetoothDevice) message.obj; configureWBSNative(getByteAddress(device),WBS_CODEC); } break; case DISABLE_WBS: { BluetoothDevice device = (BluetoothDevice) message.obj; configureWBSNative(getByteAddress(device),NBS_CODEC); } break; case START_VR_TIMEOUT: { BluetoothDevice device = (BluetoothDevice) message.obj; Loading Loading @@ -920,6 +942,10 @@ final class HeadsetStateMachine extends StateMachine { case EVENT_TYPE_NOICE_REDUCTION: processNoiceReductionEvent(event.valueInt, event.device); break; case EVENT_TYPE_WBS: Log.d(TAG, "EVENT_TYPE_WBS codec is "+event.valueInt); processWBSEvent(event.valueInt, event.device); break; case EVENT_TYPE_AT_CHLD: processAtChld(event.valueInt, event.device); break; Loading Loading @@ -961,6 +987,7 @@ final class HeadsetStateMachine extends StateMachine { if (mConnectedDevicesList.contains(device)) { broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.STATE_CONNECTED); processWBSEvent(0, device); /* disable WBS audio parameters */ synchronized (HeadsetStateMachine.this) { mConnectedDevicesList.remove(device); mHeadsetAudioParam.remove(device); Loading Loading @@ -1400,6 +1427,7 @@ final class HeadsetStateMachine extends StateMachine { " is removed in AudioOn state"); broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.STATE_CONNECTED); processWBSEvent(0, device); /* disable WBS audio parameters */ if (mConnectedDevicesList.size() == 0) { transitionTo(mDisconnected); } Loading Loading @@ -2622,6 +2650,20 @@ final class HeadsetStateMachine extends StateMachine { Log.d(TAG, "NREC value for device :" + device + " is: " + AudioParamNrec.get("NREC")); } // 2 - WBS on // 1 - NBS on private void processWBSEvent(int enable, BluetoothDevice device) { if (enable == 2) { Log.d(TAG, "AudioManager.setParameters bt_headset_wbs=on for " + device.getName() + " - " + device.getAddress()); mAudioManager.setParameters(HEADSET_WBS + "=on"); } else { Log.d(TAG, "AudioManager.setParameters bt_headset_wbs=off for " + device.getName() + " - " + device.getAddress()); mAudioManager.setParameters(HEADSET_WBS + "=off"); } } private void processAtChld(int chld, BluetoothDevice device) { if(device == null) { Log.w(TAG, "processAtChld device is null"); Loading Loading @@ -3008,6 +3050,13 @@ final class HeadsetStateMachine extends StateMachine { sendMessage(STACK_EVENT, event); } private void onWBS(int codec, byte[] address) { StackEvent event = new StackEvent(EVENT_TYPE_WBS); event.valueInt = codec; event.device = getDevice(address); sendMessage(STACK_EVENT, event); } private void onAtChld(int chld, byte[] address) { StackEvent event = new StackEvent(EVENT_TYPE_AT_CHLD); event.valueInt = chld; Loading Loading @@ -3209,6 +3258,7 @@ final class HeadsetStateMachine extends StateMachine { final private static int EVENT_TYPE_AT_CLCC = 14; final private static int EVENT_TYPE_UNKNOWN_AT = 15; final private static int EVENT_TYPE_KEY_PRESSED = 16; final private static int EVENT_TYPE_WBS = 17; private class StackEvent { int type = EVENT_TYPE_NONE; Loading Loading @@ -3249,4 +3299,5 @@ final class HeadsetStateMachine extends StateMachine { private native boolean phoneStateChangeNative(int numActive, int numHeld, int callState, String number, int type); private native boolean configureWBSNative(byte[] address,int condec_config); } Loading
android/app/jni/com_android_bluetooth_hfp.cpp +53 −0 Original line number Diff line number Diff line Loading @@ -42,6 +42,7 @@ static jmethodID method_onVolumeChanged; static jmethodID method_onDialCall; static jmethodID method_onSendDtmf; static jmethodID method_onNoiceReductionEnable; static jmethodID method_onWBS; static jmethodID method_onAtChld; static jmethodID method_onAtCnum; static jmethodID method_onAtCind; Loading @@ -67,6 +68,19 @@ static bool checkCallbackThread() { return true; } static jbyteArray marshall_bda(bt_bdaddr_t* bd_addr) { jbyteArray addr; addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)); if (!addr) { ALOGE("Fail to new jbyteArray bd addr"); checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); return NULL; } sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr); return addr; } static void connection_state_callback(bthf_connection_state_t state, bt_bdaddr_t* bd_addr) { jbyteArray addr; Loading Loading @@ -228,6 +242,19 @@ static void noice_reduction_callback(bthf_nrec_t nrec, bt_bdaddr_t* bd_addr) { sCallbackEnv->DeleteLocalRef(addr); } static void wbs_callback(bthf_wbs_config_t wbs_config, bt_bdaddr_t* bd_addr) { jbyteArray addr; CHECK_CALLBACK_ENV if ((addr = marshall_bda(bd_addr)) == NULL) return; sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onWBS, wbs_config, addr); checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); sCallbackEnv->DeleteLocalRef(addr); } static void at_chld_callback(bthf_chld_type_t chld, bt_bdaddr_t* bd_addr) { jbyteArray addr; Loading Loading @@ -361,6 +388,7 @@ static bthf_callbacks_t sBluetoothHfpCallbacks = { dial_call_callback, dtmf_cmd_callback, noice_reduction_callback, wbs_callback, at_chld_callback, at_cnum_callback, at_cind_callback, Loading @@ -387,6 +415,7 @@ static void classInitNative(JNIEnv* env, jclass clazz) { method_onDialCall = env->GetMethodID(clazz, "onDialCall", "(Ljava/lang/String;[B)V"); method_onSendDtmf = env->GetMethodID(clazz, "onSendDtmf", "(I[B)V"); method_onNoiceReductionEnable = env->GetMethodID(clazz, "onNoiceReductionEnable", "(Z[B)V"); method_onWBS = env->GetMethodID(clazz,"onWBS","(I[B)V"); method_onAtChld = env->GetMethodID(clazz, "onAtChld", "(I[B)V"); method_onAtCnum = env->GetMethodID(clazz, "onAtCnum", "([B)V"); method_onAtCind = env->GetMethodID(clazz, "onAtCind", "([B)V"); Loading Loading @@ -768,6 +797,29 @@ static jboolean phoneStateChangeNative(JNIEnv *env, jobject object, jint num_act return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } static jboolean configureWBSNative(JNIEnv *env, jobject object, jbyteArray address, jint codec_config) { jbyte *addr; bt_status_t status; if (!sBluetoothHfpInterface) return JNI_FALSE; addr = env->GetByteArrayElements(address, NULL); if (!addr) { jniThrowIOException(env, EINVAL); return JNI_FALSE; } if ((status = sBluetoothHfpInterface->configure_wbs((bt_bdaddr_t *)addr, (bthf_wbs_config_t)codec_config)) != BT_STATUS_SUCCESS){ ALOGE("Failed HF WBS codec config, status: %d", status); } env->ReleaseByteArrayElements(address, addr, 0); return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; } static JNINativeMethod sMethods[] = { {"classInitNative", "()V", (void *) classInitNative}, {"initializeNative", "(I)V", (void *) initializeNative}, Loading @@ -786,6 +838,7 @@ static JNINativeMethod sMethods[] = { {"atResponseCodeNative", "(II[B)Z", (void *)atResponseCodeNative}, {"clccResponseNative", "(IIIIZLjava/lang/String;I[B)Z", (void *) clccResponseNative}, {"phoneStateChangeNative", "(IIILjava/lang/String;I)Z", (void *) phoneStateChangeNative}, {"configureWBSNative", "([BI)Z", (void *) configureWBSNative}, }; int register_com_android_bluetooth_hfp(JNIEnv* env) Loading
android/app/src/com/android/bluetooth/hfp/HeadsetService.java +44 −0 Original line number Diff line number Diff line Loading @@ -278,6 +278,18 @@ public class HeadsetService extends ProfileService { } return service.sendVendorSpecificResultCode(device, command, arg); } public boolean enableWBS() { HeadsetService service = getService(); if (service == null) return false; return service.enableWBS(); } public boolean disableWBS() { HeadsetService service = getService(); if (service == null) return false; return service.disableWBS(); } }; //API methods Loading Loading @@ -513,4 +525,36 @@ public class HeadsetService extends ProfileService { return true; } boolean enableWBS() { // TODO(BT) BLUETOOTH or BLUETOOTH_ADMIN permission enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); if (!mStateMachine.isConnected()) { return false; } if (mStateMachine.isAudioOn()) { return false; } for (BluetoothDevice device: getConnectedDevices()) { mStateMachine.sendMessage(HeadsetStateMachine.ENABLE_WBS,device); } return true; } boolean disableWBS() { // TODO(BT) BLUETOOTH or BLUETOOTH_ADMIN permission enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); if (!mStateMachine.isConnected()) { return false; } if (mStateMachine.isAudioOn()) { return false; } for (BluetoothDevice device: getConnectedDevices()) { mStateMachine.sendMessage(HeadsetStateMachine.DISABLE_WBS,device); } return true; } }
android/app/src/com/android/bluetooth/hfp/HeadsetStateMachine.java +51 −0 Original line number Diff line number Diff line Loading @@ -76,6 +76,7 @@ final class HeadsetStateMachine extends StateMachine { private static final String HEADSET_NAME = "bt_headset_name"; private static final String HEADSET_NREC = "bt_headset_nrec"; private static final String HEADSET_WBS = "bt_headset_wbs"; static final int CONNECT = 1; static final int DISCONNECT = 2; Loading @@ -97,6 +98,10 @@ final class HeadsetStateMachine extends StateMachine { static final int VIRTUAL_CALL_START = 14; static final int VIRTUAL_CALL_STOP = 15; static final int ENABLE_WBS = 16; static final int DISABLE_WBS = 17; private static final int STACK_EVENT = 101; private static final int DIALING_OUT_TIMEOUT = 102; private static final int START_VR_TIMEOUT = 103; Loading @@ -111,6 +116,9 @@ final class HeadsetStateMachine extends StateMachine { // Max number of HF connections at any time private int max_hf_connections = 2; private static final int NBS_CODEC = 1; private static final int WBS_CODEC = 2; // Keys are AT commands, and values are the company IDs. private static final Map<String, Integer> VENDOR_SPECIFIC_AT_COMMAND_COMPANY_ID; // Hash for storing the Audio Parameters like NREC for connected headsets Loading Loading @@ -528,6 +536,8 @@ final class HeadsetStateMachine extends StateMachine { mCurrentDevice = null; } processWBSEvent(0, device); /* disable WBS audio parameters */ if (mTargetDevice != null) { if (!connectHfpNative(getByteAddress(mTargetDevice))) { broadcastConnectionState(mTargetDevice, Loading Loading @@ -871,6 +881,18 @@ final class HeadsetStateMachine extends StateMachine { case VIRTUAL_CALL_STOP: terminateScoUsingVirtualVoiceCall(); break; case ENABLE_WBS: { BluetoothDevice device = (BluetoothDevice) message.obj; configureWBSNative(getByteAddress(device),WBS_CODEC); } break; case DISABLE_WBS: { BluetoothDevice device = (BluetoothDevice) message.obj; configureWBSNative(getByteAddress(device),NBS_CODEC); } break; case START_VR_TIMEOUT: { BluetoothDevice device = (BluetoothDevice) message.obj; Loading Loading @@ -920,6 +942,10 @@ final class HeadsetStateMachine extends StateMachine { case EVENT_TYPE_NOICE_REDUCTION: processNoiceReductionEvent(event.valueInt, event.device); break; case EVENT_TYPE_WBS: Log.d(TAG, "EVENT_TYPE_WBS codec is "+event.valueInt); processWBSEvent(event.valueInt, event.device); break; case EVENT_TYPE_AT_CHLD: processAtChld(event.valueInt, event.device); break; Loading Loading @@ -961,6 +987,7 @@ final class HeadsetStateMachine extends StateMachine { if (mConnectedDevicesList.contains(device)) { broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.STATE_CONNECTED); processWBSEvent(0, device); /* disable WBS audio parameters */ synchronized (HeadsetStateMachine.this) { mConnectedDevicesList.remove(device); mHeadsetAudioParam.remove(device); Loading Loading @@ -1400,6 +1427,7 @@ final class HeadsetStateMachine extends StateMachine { " is removed in AudioOn state"); broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.STATE_CONNECTED); processWBSEvent(0, device); /* disable WBS audio parameters */ if (mConnectedDevicesList.size() == 0) { transitionTo(mDisconnected); } Loading Loading @@ -2622,6 +2650,20 @@ final class HeadsetStateMachine extends StateMachine { Log.d(TAG, "NREC value for device :" + device + " is: " + AudioParamNrec.get("NREC")); } // 2 - WBS on // 1 - NBS on private void processWBSEvent(int enable, BluetoothDevice device) { if (enable == 2) { Log.d(TAG, "AudioManager.setParameters bt_headset_wbs=on for " + device.getName() + " - " + device.getAddress()); mAudioManager.setParameters(HEADSET_WBS + "=on"); } else { Log.d(TAG, "AudioManager.setParameters bt_headset_wbs=off for " + device.getName() + " - " + device.getAddress()); mAudioManager.setParameters(HEADSET_WBS + "=off"); } } private void processAtChld(int chld, BluetoothDevice device) { if(device == null) { Log.w(TAG, "processAtChld device is null"); Loading Loading @@ -3008,6 +3050,13 @@ final class HeadsetStateMachine extends StateMachine { sendMessage(STACK_EVENT, event); } private void onWBS(int codec, byte[] address) { StackEvent event = new StackEvent(EVENT_TYPE_WBS); event.valueInt = codec; event.device = getDevice(address); sendMessage(STACK_EVENT, event); } private void onAtChld(int chld, byte[] address) { StackEvent event = new StackEvent(EVENT_TYPE_AT_CHLD); event.valueInt = chld; Loading Loading @@ -3209,6 +3258,7 @@ final class HeadsetStateMachine extends StateMachine { final private static int EVENT_TYPE_AT_CLCC = 14; final private static int EVENT_TYPE_UNKNOWN_AT = 15; final private static int EVENT_TYPE_KEY_PRESSED = 16; final private static int EVENT_TYPE_WBS = 17; private class StackEvent { int type = EVENT_TYPE_NONE; Loading Loading @@ -3249,4 +3299,5 @@ final class HeadsetStateMachine extends StateMachine { private native boolean phoneStateChangeNative(int numActive, int numHeld, int callState, String number, int type); private native boolean configureWBSNative(byte[] address,int condec_config); }