com_android_bluetooth_a2dp.cpp revision e469f16e5a7d99471d7db1b216d422e8d12cc4cf
1/* 2 * Copyright (C) 2012 Google Inc. 3 */ 4#define LOG_TAG "BluetoothA2dpServiceJni" 5 6#define LOG_NDEBUG 0 7 8#include "com_android_bluetooth.h" 9#include "hardware/bt_av.h" 10#include "utils/Log.h" 11#include "android_runtime/AndroidRuntime.h" 12 13#include <string.h> 14 15namespace android { 16static jmethodID method_onConnectionStateChanged; 17static jmethodID method_onAudioStateChanged; 18 19static const btav_interface_t *sBluetoothA2dpInterface = NULL; 20static jobject mCallbacksObj = NULL; 21static JNIEnv *sCallbackEnv = NULL; 22 23static bool checkCallbackThread() { 24 // Always fetch the latest callbackEnv from AdapterService. 25 // Caching this could cause this sCallbackEnv to go out-of-sync 26 // with the AdapterService's ENV if an ASSOCIATE/DISASSOCIATE event 27 // is received 28 //if (sCallbackEnv == NULL) { 29 sCallbackEnv = getCallbackEnv(); 30 //} 31 32 JNIEnv* env = AndroidRuntime::getJNIEnv(); 33 if (sCallbackEnv != env || sCallbackEnv == NULL) return false; 34 return true; 35} 36 37static void bta2dp_connection_state_callback(btav_connection_state_t state, bt_bdaddr_t* bd_addr) { 38 jbyteArray addr; 39 40 LOGI("%s", __FUNCTION__); 41 42 if (!checkCallbackThread()) { \ 43 LOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); \ 44 return; \ 45 } 46 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)); 47 if (!addr) { 48 LOGE("Fail to new jbyteArray bd addr for connection state"); 49 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 50 return; 51 } 52 53 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr); 54 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectionStateChanged, (jint) state, 55 addr); 56 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 57 sCallbackEnv->DeleteLocalRef(addr); 58} 59 60static void bta2dp_audio_state_callback(btav_audio_state_t state, bt_bdaddr_t* bd_addr) { 61 jbyteArray addr; 62 63 ALOGI("%s", __FUNCTION__); 64 65 if (!checkCallbackThread()) { \ 66 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); \ 67 return; \ 68 } 69 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)); 70 if (!addr) { 71 ALOGE("Fail to new jbyteArray bd addr for connection state"); 72 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 73 return; 74 } 75 76 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr); 77 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAudioStateChanged, (jint) state, 78 addr); 79 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 80 sCallbackEnv->DeleteLocalRef(addr); 81} 82 83static btav_callbacks_t sBluetoothA2dpCallbacks = { 84 sizeof(sBluetoothA2dpCallbacks), 85 bta2dp_connection_state_callback, 86 bta2dp_audio_state_callback 87}; 88 89static void classInitNative(JNIEnv* env, jclass clazz) { 90 int err; 91 const bt_interface_t* btInf; 92 bt_status_t status; 93 94 method_onConnectionStateChanged = 95 env->GetMethodID(clazz, "onConnectionStateChanged", "(I[B)V"); 96 97 method_onAudioStateChanged = 98 env->GetMethodID(clazz, "onAudioStateChanged", "(I[B)V"); 99 /* 100 if ( (btInf = getBluetoothInterface()) == NULL) { 101 LOGE("Bluetooth module is not loaded"); 102 return; 103 } 104 105 if ( (sBluetoothA2dpInterface = (btav_interface_t *) 106 btInf->get_profile_interface(BT_PROFILE_ADVANCED_AUDIO_ID)) == NULL) { 107 LOGE("Failed to get Bluetooth A2DP Interface"); 108 return; 109 } 110 */ 111 112 // TODO(BT) do this only once or 113 // Do we need to do this every time the BT reenables? 114 /* 115 if ( (status = sBluetoothA2dpInterface->init(&sBluetoothA2dpCallbacks)) != BT_STATUS_SUCCESS) { 116 LOGE("Failed to initialize Bluetooth A2DP, status: %d", status); 117 sBluetoothA2dpInterface = NULL; 118 return; 119 }*/ 120 121 LOGI("%s: succeeds", __FUNCTION__); 122} 123 124static void initNative(JNIEnv *env, jobject object) { 125 const bt_interface_t* btInf; 126 bt_status_t status; 127 128 if ( (btInf = getBluetoothInterface()) == NULL) { 129 ALOGE("Bluetooth module is not loaded"); 130 return; 131 } 132 133 if (sBluetoothA2dpInterface !=NULL) { 134 ALOGW("Cleaning up A2DP Interface before initializing..."); 135 sBluetoothA2dpInterface->cleanup(); 136 sBluetoothA2dpInterface = NULL; 137 } 138 139 if (mCallbacksObj != NULL) { 140 ALOGW("Cleaning up A2DP callback object"); 141 env->DeleteGlobalRef(mCallbacksObj); 142 mCallbacksObj = NULL; 143 } 144 145 if ( (sBluetoothA2dpInterface = (btav_interface_t *) 146 btInf->get_profile_interface(BT_PROFILE_ADVANCED_AUDIO_ID)) == NULL) { 147 ALOGE("Failed to get Bluetooth A2DP Interface"); 148 return; 149 } 150 151 if ( (status = sBluetoothA2dpInterface->init(&sBluetoothA2dpCallbacks)) != BT_STATUS_SUCCESS) { 152 ALOGE("Failed to initialize Bluetooth A2DP, status: %d", status); 153 sBluetoothA2dpInterface = NULL; 154 return; 155 } 156 157 mCallbacksObj = env->NewGlobalRef(object); 158} 159 160static void cleanupNative(JNIEnv *env, jobject object) { 161 const bt_interface_t* btInf; 162 bt_status_t status; 163 164 if ( (btInf = getBluetoothInterface()) == NULL) { 165 ALOGE("Bluetooth module is not loaded"); 166 return; 167 } 168 169 if (sBluetoothA2dpInterface !=NULL) { 170 sBluetoothA2dpInterface->cleanup(); 171 sBluetoothA2dpInterface = NULL; 172 } 173 174 if (mCallbacksObj != NULL) { 175 env->DeleteGlobalRef(mCallbacksObj); 176 mCallbacksObj = NULL; 177 } 178} 179 180static jboolean connectA2dpNative(JNIEnv *env, jobject object, jbyteArray address) { 181 jbyte *addr; 182 bt_bdaddr_t * btAddr; 183 bt_status_t status; 184 185 LOGI("%s: sBluetoothA2dpInterface: %p", __FUNCTION__, sBluetoothA2dpInterface); 186 if (!sBluetoothA2dpInterface) return JNI_FALSE; 187 188 addr = env->GetByteArrayElements(address, NULL); 189 btAddr = (bt_bdaddr_t *) addr; 190 if (!addr) { 191 jniThrowIOException(env, EINVAL); 192 return JNI_FALSE; 193 } 194 195 if ((status = sBluetoothA2dpInterface->connect((bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) { 196 LOGE("Failed HF connection, status: %d", status); 197 } 198 env->ReleaseByteArrayElements(address, addr, 0); 199 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 200} 201 202static jboolean disconnectA2dpNative(JNIEnv *env, jobject object, jbyteArray address) { 203 jbyte *addr; 204 bt_status_t status; 205 206 if (!sBluetoothA2dpInterface) return JNI_FALSE; 207 208 addr = env->GetByteArrayElements(address, NULL); 209 if (!addr) { 210 jniThrowIOException(env, EINVAL); 211 return JNI_FALSE; 212 } 213 214 if ( (status = sBluetoothA2dpInterface->disconnect((bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) { 215 LOGE("Failed HF disconnection, status: %d", status); 216 } 217 env->ReleaseByteArrayElements(address, addr, 0); 218 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 219} 220 221static JNINativeMethod sMethods[] = { 222 {"classInitNative", "()V", (void *) classInitNative}, 223 {"initNative", "()V", (void *) initNative}, 224 {"cleanupNative", "()V", (void *) cleanupNative}, 225 {"connectA2dpNative", "([B)Z", (void *) connectA2dpNative}, 226 {"disconnectA2dpNative", "([B)Z", (void *) disconnectA2dpNative}, 227}; 228 229int register_com_android_bluetooth_a2dp(JNIEnv* env) 230{ 231 return jniRegisterNativeMethods(env, "com/android/bluetooth/a2dp/A2dpStateMachine", 232 sMethods, NELEM(sMethods)); 233} 234 235} 236