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