com_android_bluetooth_hfp.cpp revision 6c91bc0a163cc7600c40d7fb979777fd911d1ef1
1/* 2 * Copyright (C) 2012 Google Inc. 3 */ 4 5#define LOG_TAG "BluetoothHeadsetServiceJni" 6 7#define LOG_NDEBUG 0 8 9#define CHECK_CALLBACK_ENV \ 10 if (!checkCallbackThread()) { \ 11 LOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);\ 12 return; \ 13 } 14 15#include "com_android_bluetooth.h" 16#include "hardware/bt_hf.h" 17#include "utils/Log.h" 18#include "android_runtime/AndroidRuntime.h" 19 20#include <string.h> 21 22namespace android { 23 24static jmethodID method_onConnectionStateChanged; 25static jmethodID method_onAudioStateChanged; 26static jmethodID method_onVrStateChanged; 27static jmethodID method_onAnswerCall; 28static jmethodID method_onHangupCall; 29static jmethodID method_onVolumeChanged; 30static jmethodID method_onDialCall; 31static jmethodID method_onSendDtmf; 32static jmethodID method_onNoiceReductionEnable; 33static jmethodID method_onAtChld; 34static jmethodID method_onAtCnum; 35static jmethodID method_onAtCind; 36static jmethodID method_onAtCops; 37static jmethodID method_onAtClcc; 38static jmethodID method_onUnknownAt; 39static jmethodID method_onKeyPressed; 40 41static const bthf_interface_t *sBluetoothHfpInterface = NULL; 42static jobject mCallbacksObj = NULL; 43static JNIEnv *sCallbackEnv = NULL; 44 45static bool checkCallbackThread() { 46 if (sCallbackEnv == NULL) { 47 sCallbackEnv = getCallbackEnv(); 48 } 49 50 JNIEnv* env = AndroidRuntime::getJNIEnv(); 51 if (sCallbackEnv != env || sCallbackEnv == NULL) return false; 52 return true; 53} 54 55static void connection_state_callback(bthf_connection_state_t state, bt_bdaddr_t* bd_addr) { 56 jbyteArray addr; 57 58 LOGI("%s", __FUNCTION__); 59 60 CHECK_CALLBACK_ENV 61 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)); 62 if (!addr) { 63 LOGE("Fail to new jbyteArray bd addr for connection state"); 64 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 65 return; 66 } 67 68 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr); 69 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectionStateChanged, 70 (jint) state, addr); 71 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 72 sCallbackEnv->DeleteLocalRef(addr); 73} 74 75static void audio_state_callback(bthf_audio_state_t state, bt_bdaddr_t* bd_addr) { 76 jbyteArray addr; 77 78 CHECK_CALLBACK_ENV 79 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)); 80 if (!addr) { 81 LOGE("Fail to new jbyteArray bd addr for audio state"); 82 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 83 return; 84 } 85 86 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr); 87 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAudioStateChanged, (jint) state, addr); 88 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 89 sCallbackEnv->DeleteLocalRef(addr); 90} 91 92static void voice_recognition_callback(bthf_vr_state_t state) { 93 CHECK_CALLBACK_ENV 94 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onVrStateChanged, (jint) state); 95 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 96} 97 98static void answer_call_callback() { 99 CHECK_CALLBACK_ENV 100 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAnswerCall); 101 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 102} 103 104static void hangup_call_callback() { 105 CHECK_CALLBACK_ENV 106 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onHangupCall); 107 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 108} 109 110static void volume_control_callback(bthf_volume_type_t type, int volume) { 111 CHECK_CALLBACK_ENV 112 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onVolumeChanged, (jint) type, (jint) volume); 113 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 114} 115 116static void dial_call_callback(char *number) { 117 CHECK_CALLBACK_ENV 118 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onDialCall, 119 sCallbackEnv->NewStringUTF(number)); 120 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 121} 122 123static void dtmf_cmd_callback(char dtmf) { 124 CHECK_CALLBACK_ENV 125 // TBD dtmf has changed from int to char 126 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onSendDtmf, dtmf); 127 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 128} 129 130static void noice_reduction_callback(bthf_nrec_t nrec) { 131 CHECK_CALLBACK_ENV 132 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onNoiceReductionEnable, 133 nrec == BTHF_NREC_START); 134 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 135} 136 137static void at_chld_callback(bthf_chld_type_t chld) { 138 CHECK_CALLBACK_ENV 139 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAtChld, chld); 140 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 141} 142 143static void at_cnum_callback() { 144 CHECK_CALLBACK_ENV 145 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAtCnum); 146 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 147} 148 149static void at_cind_callback() { 150 CHECK_CALLBACK_ENV 151 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAtCind); 152 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 153} 154 155static void at_cops_callback() { 156 CHECK_CALLBACK_ENV 157 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAtCops); 158 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 159} 160 161static void at_clcc_callback() { 162 CHECK_CALLBACK_ENV 163 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAtClcc); 164 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 165} 166 167static void unknown_at_callback(char *at_string) { 168 CHECK_CALLBACK_ENV 169 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onUnknownAt, 170 sCallbackEnv->NewStringUTF(at_string)); 171 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 172} 173 174static void key_pressed_callback() { 175 CHECK_CALLBACK_ENV 176 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onKeyPressed); 177 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 178} 179 180static bthf_callbacks_t sBluetoothHfpCallbacks = { 181 sizeof(sBluetoothHfpCallbacks), 182 connection_state_callback, 183 audio_state_callback, 184 voice_recognition_callback, 185 answer_call_callback, 186 hangup_call_callback, 187 volume_control_callback, 188 dial_call_callback, 189 dtmf_cmd_callback, 190 noice_reduction_callback, 191 at_chld_callback, 192 at_cnum_callback, 193 at_cind_callback, 194 at_cops_callback, 195 at_clcc_callback, 196 unknown_at_callback, 197 key_pressed_callback 198}; 199 200static void classInitNative(JNIEnv* env, jclass clazz) { 201 int err; 202 const bt_interface_t* btInf; 203 bt_status_t status; 204 205 method_onConnectionStateChanged = 206 env->GetMethodID(clazz, "onConnectionStateChanged", "(I[B)V"); 207 method_onAudioStateChanged = env->GetMethodID(clazz, "onAudioStateChanged", "(I[B)V"); 208 method_onVrStateChanged = env->GetMethodID(clazz, "onVrStateChanged", "(I)V"); 209 method_onAnswerCall = env->GetMethodID(clazz, "onAnswerCall", "()V"); 210 method_onHangupCall = env->GetMethodID(clazz, "onHangupCall", "()V"); 211 method_onVolumeChanged = env->GetMethodID(clazz, "onVolumeChanged", "(II)V"); 212 method_onDialCall = env->GetMethodID(clazz, "onDialCall", "(Ljava/lang/String;)V"); 213 method_onSendDtmf = env->GetMethodID(clazz, "onSendDtmf", "(I)V"); 214 method_onNoiceReductionEnable = env->GetMethodID(clazz, "onNoiceReductionEnable", "(Z)V"); 215 method_onAtChld = env->GetMethodID(clazz, "onAtChld", "(I)V"); 216 method_onAtCnum = env->GetMethodID(clazz, "onAtCnum", "()V"); 217 method_onAtCind = env->GetMethodID(clazz, "onAtCind", "()V"); 218 method_onAtCops = env->GetMethodID(clazz, "onAtCops", "()V"); 219 method_onAtClcc = env->GetMethodID(clazz, "onAtClcc", "()V"); 220 method_onUnknownAt = env->GetMethodID(clazz, "onUnknownAt", "(Ljava/lang/String;)V"); 221 method_onKeyPressed = env->GetMethodID(clazz, "onKeyPressed", "()V"); 222 223 if ( (btInf = getBluetoothInterface()) == NULL) { 224 LOGE("Bluetooth module is not loaded"); 225 return; 226 } 227 228 if ( (sBluetoothHfpInterface = (bthf_interface_t *) 229 btInf->get_profile_interface(BT_PROFILE_HANDSFREE_ID)) == NULL) { 230 LOGE("Failed to get Bluetooth Handsfree Interface"); 231 return; 232 } 233 234 // TODO(BT) do this only once or 235 // Do we need to do this every time the BT reenables? 236 if ( (status = sBluetoothHfpInterface->init(&sBluetoothHfpCallbacks)) != BT_STATUS_SUCCESS) { 237 LOGE("Failed to initialize Bluetooth HFP, status: %d", status); 238 sBluetoothHfpInterface = NULL; 239 return; 240 } 241 242 LOGI("%s: succeeds", __FUNCTION__); 243} 244 245static void initializeNativeDataNative(JNIEnv *env, jobject object) { 246 // TODO(BT) clean it up when hfp service is stopped 247 // Is there a need to do cleanup since HFP is always present for phone? 248 // We need handle it for tablets. But should that be handle at compile time? 249 mCallbacksObj = env->NewGlobalRef(object); 250} 251 252static jboolean connectHfpNative(JNIEnv *env, jobject object, jbyteArray address) { 253 jbyte *addr; 254 bt_bdaddr_t * btAddr; 255 bt_status_t status; 256 257 LOGI("%s: sBluetoothHfpInterface: %p", __FUNCTION__, sBluetoothHfpInterface); 258 if (!sBluetoothHfpInterface) return JNI_FALSE; 259 260 addr = env->GetByteArrayElements(address, NULL); 261 btAddr = (bt_bdaddr_t *) addr; 262 if (!addr) { 263 jniThrowIOException(env, EINVAL); 264 return JNI_FALSE; 265 } 266 267 if ((status = sBluetoothHfpInterface->connect((bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) { 268 LOGE("Failed HF connection, status: %d", status); 269 } 270 env->ReleaseByteArrayElements(address, addr, 0); 271 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 272} 273 274static jboolean disconnectHfpNative(JNIEnv *env, jobject object, jbyteArray address) { 275 jbyte *addr; 276 bt_status_t status; 277 278 if (!sBluetoothHfpInterface) return JNI_FALSE; 279 280 addr = env->GetByteArrayElements(address, NULL); 281 if (!addr) { 282 jniThrowIOException(env, EINVAL); 283 return JNI_FALSE; 284 } 285 286 if ( (status = sBluetoothHfpInterface->disconnect((bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) { 287 LOGE("Failed HF disconnection, status: %d", status); 288 } 289 env->ReleaseByteArrayElements(address, addr, 0); 290 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 291} 292 293static jboolean connectAudioNative(JNIEnv *env, jobject object, jbyteArray address) { 294 jbyte *addr; 295 bt_status_t status; 296 297 if (!sBluetoothHfpInterface) return JNI_FALSE; 298 299 addr = env->GetByteArrayElements(address, NULL); 300 if (!addr) { 301 jniThrowIOException(env, EINVAL); 302 return JNI_FALSE; 303 } 304 305 if ( (status = sBluetoothHfpInterface->connect_audio((bt_bdaddr_t *)addr)) != 306 BT_STATUS_SUCCESS) { 307 LOGE("Failed HF audio connection, status: %d", status); 308 } 309 env->ReleaseByteArrayElements(address, addr, 0); 310 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 311} 312 313static jboolean disconnectAudioNative(JNIEnv *env, jobject object, jbyteArray address) { 314 jbyte *addr; 315 bt_status_t status; 316 317 if (!sBluetoothHfpInterface) return JNI_FALSE; 318 319 addr = env->GetByteArrayElements(address, NULL); 320 if (!addr) { 321 jniThrowIOException(env, EINVAL); 322 return JNI_FALSE; 323 } 324 325 if ( (status = sBluetoothHfpInterface->disconnect_audio((bt_bdaddr_t *) addr)) != 326 BT_STATUS_SUCCESS) { 327 LOGE("Failed HF audio disconnection, status: %d", status); 328 } 329 env->ReleaseByteArrayElements(address, addr, 0); 330 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 331} 332 333static jboolean startVoiceRecognitionNative(JNIEnv *env, jobject object) { 334 bt_status_t status; 335 if (!sBluetoothHfpInterface) return JNI_FALSE; 336 337 if ( (status = sBluetoothHfpInterface->start_voice_recognition()) != BT_STATUS_SUCCESS) { 338 LOGE("Failed to start voice recognition, status: %d", status); 339 } 340 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 341} 342 343static jboolean stopVoiceRecognitionNative(JNIEnv *env, jobject object) { 344 bt_status_t status; 345 if (!sBluetoothHfpInterface) return JNI_FALSE; 346 347 if ( (status = sBluetoothHfpInterface->stop_voice_recognition()) != BT_STATUS_SUCCESS) { 348 LOGE("Failed to stop voice recognition, status: %d", status); 349 } 350 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 351} 352 353static jboolean setVolumeNative(JNIEnv *env, jobject object, jint volume_type, jint volume) { 354 bt_status_t status; 355 if (!sBluetoothHfpInterface) return JNI_FALSE; 356 357 if ( (status = sBluetoothHfpInterface->volume_control((bthf_volume_type_t) volume_type, 358 volume)) != BT_STATUS_SUCCESS) { 359 LOGE("FAILED to control volume, status: %d", status); 360 } 361 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 362} 363 364static jboolean notifyDeviceStatusNative(JNIEnv *env, jobject object, 365 jint network_state, jint service_type, jint signal, 366 jint battery_charge) { 367 bt_status_t status; 368 if (!sBluetoothHfpInterface) return JNI_FALSE; 369 370 if ( (status = sBluetoothHfpInterface->device_status_notification 371 ((bthf_network_state_t) network_state, (bthf_service_type_t) service_type, 372 signal, battery_charge)) != BT_STATUS_SUCCESS) { 373 LOGE("FAILED to notify device status, status: %d", status); 374 } 375 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 376} 377 378static jboolean copsResponseNative(JNIEnv *env, jobject object, jstring operator_str) { 379 bt_status_t status; 380 const char *operator_name; 381 if (!sBluetoothHfpInterface) return JNI_FALSE; 382 383 operator_name = env->GetStringUTFChars(operator_str, NULL); 384 385 if ( (status = sBluetoothHfpInterface->cops_response(operator_name)) != BT_STATUS_SUCCESS) { 386 LOGE("Failed sending cops response, status: %d", status); 387 } 388 env->ReleaseStringUTFChars(operator_str, operator_name); 389 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 390} 391 392static jboolean cindResponseNative(JNIEnv *env, jobject object, 393 jint service, jint num_active, jint num_held, jint call_state, 394 jint signal, jint roam, jint battery_charge) { 395 bt_status_t status; 396 if (!sBluetoothHfpInterface) return JNI_FALSE; 397 398 if ( (status = sBluetoothHfpInterface->cind_response(service, num_active, num_held, 399 (bthf_call_state_t) call_state, 400 signal, roam, battery_charge)) != BT_STATUS_SUCCESS) { 401 LOGE("Failed cind_response, status: %d", status); 402 } 403 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 404} 405 406 407static jboolean atResponseStringNative(JNIEnv *env, jobject object, jstring response_str) { 408 bt_status_t status; 409 const char *response; 410 if (!sBluetoothHfpInterface) return JNI_FALSE; 411 412 response = env->GetStringUTFChars(response_str, NULL); 413 414 if ( (status = sBluetoothHfpInterface->formatted_at_response(response)) != BT_STATUS_SUCCESS) { 415 LOGE("Failed formatted AT response, status: %d", status); 416 } 417 env->ReleaseStringUTFChars(response_str, response); 418 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 419} 420 421static jboolean atResponseCodeNative(JNIEnv *env, jobject object, jint response_code) { 422 bt_status_t status; 423 if (!sBluetoothHfpInterface) return JNI_FALSE; 424 425 if ( (status = sBluetoothHfpInterface->at_response((bthf_at_response_t) response_code)) != 426 BT_STATUS_SUCCESS) { 427 LOGE("Failed AT response, status: %d", status); 428 } 429 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 430} 431 432static jboolean clccResponseNative(JNIEnv *env, jobject object, jint index, jint dir, 433 jint callStatus, jint mode, jboolean mpty, jstring number_str, 434 jint type) { 435 bt_status_t status; 436 const char *number; 437 if (!sBluetoothHfpInterface) return JNI_FALSE; 438 439 number = env->GetStringUTFChars(number_str, NULL); 440 441 if ( (status = sBluetoothHfpInterface->clcc_response(index, (bthf_call_direction_t) dir, 442 (bthf_call_state_t) callStatus, (bthf_call_mode_t) mode, 443 mpty ? BTHF_CALL_MPTY_TYPE_MULTI : BTHF_CALL_MPTY_TYPE_SINGLE, 444 number, (bthf_call_addrtype_t) type)) != BT_STATUS_SUCCESS) { 445 LOGE("Failed sending CLCC response, status: %d", status); 446 } 447 env->ReleaseStringUTFChars(number_str, number); 448 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 449} 450 451static jboolean phoneStateChangeNative(JNIEnv *env, jobject object, jint num_active, jint num_held, 452 jint call_state, jstring number_str, jint type) { 453 bt_status_t status; 454 const char *number; 455 if (!sBluetoothHfpInterface) return JNI_FALSE; 456 457 number = env->GetStringUTFChars(number_str, NULL); 458 459 if ( (status = sBluetoothHfpInterface->phone_state_change(num_active, num_held, 460 (bthf_call_state_t) call_state, number, 461 (bthf_call_addrtype_t) type)) != BT_STATUS_SUCCESS) { 462 LOGE("Failed report phone state change, status: %d", status); 463 } 464 env->ReleaseStringUTFChars(number_str, number); 465 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 466} 467 468static JNINativeMethod sMethods[] = { 469 {"classInitNative", "()V", (void *) classInitNative}, 470 {"initializeNativeDataNative", "()V", (void *) initializeNativeDataNative}, 471 {"connectHfpNative", "([B)Z", (void *) connectHfpNative}, 472 {"disconnectHfpNative", "([B)Z", (void *) disconnectHfpNative}, 473 {"connectAudioNative", "([B)Z", (void *) connectAudioNative}, 474 {"disconnectAudioNative", "([B)Z", (void *) disconnectAudioNative}, 475 {"startVoiceRecognitionNative", "()Z", (void *) startVoiceRecognitionNative}, 476 {"stopVoiceRecognitionNative", "()Z", (void *) stopVoiceRecognitionNative}, 477 {"setVolumeNative", "(II)Z", (void *) setVolumeNative}, 478 {"notifyDeviceStatusNative", "(IIII)Z", (void *) notifyDeviceStatusNative}, 479 {"copsResponseNative", "(Ljava/lang/String;)Z", (void *) copsResponseNative}, 480 {"cindResponseNative", "(IIIIIII)Z", (void *) cindResponseNative}, 481 {"atResponseStringNative", "(Ljava/lang/String;)Z", (void *) atResponseStringNative}, 482 {"atResponseCodeNative", "(I)Z", (void *)atResponseCodeNative}, 483 {"clccResponseNative", "(IIIIZLjava/lang/String;I)Z", (void *) clccResponseNative}, 484 {"phoneStateChangeNative", "(IIILjava/lang/String;I)Z", (void *) phoneStateChangeNative}, 485 // TODO(BT) clean up 486}; 487 488int register_com_android_bluetooth_hfp(JNIEnv* env) 489{ 490 return jniRegisterNativeMethods(env, "com/android/bluetooth/hfp/HeadsetStateMachine", 491 sMethods, NELEM(sMethods)); 492} 493 494} /* namespace android */ 495