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 "BluetoothA2dpSinkServiceJni" 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 static jmethodID method_onAudioConfigChanged; 32 33 static const btav_interface_t *sBluetoothA2dpInterface = NULL; 34 static jobject mCallbacksObj = NULL; 35 static JNIEnv *sCallbackEnv = NULL; 36 37 static bool checkCallbackThread() { 38 // Always fetch the latest callbackEnv from AdapterService. 39 // Caching this could cause this sCallbackEnv to go out-of-sync 40 // with the AdapterService's ENV if an ASSOCIATE/DISASSOCIATE event 41 // is received 42 //if (sCallbackEnv == NULL) { 43 sCallbackEnv = getCallbackEnv(); 44 //} 45 46 JNIEnv* env = AndroidRuntime::getJNIEnv(); 47 if (sCallbackEnv != env || sCallbackEnv == NULL) return false; 48 return true; 49 } 50 51 static void bta2dp_connection_state_callback(btav_connection_state_t state, bt_bdaddr_t* bd_addr) { 52 jbyteArray addr; 53 54 ALOGI("%s", __FUNCTION__); 55 56 if (!checkCallbackThread()) { \ 57 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); \ 58 return; \ 59 } 60 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)); 61 if (!addr) { 62 ALOGE("Fail to new jbyteArray bd addr for connection state"); 63 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 64 return; 65 } 66 67 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr); 68 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectionStateChanged, (jint) state, 69 addr); 70 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 71 sCallbackEnv->DeleteLocalRef(addr); 72 } 73 74 static void bta2dp_audio_state_callback(btav_audio_state_t state, bt_bdaddr_t* bd_addr) { 75 jbyteArray addr; 76 77 ALOGI("%s", __FUNCTION__); 78 79 if (!checkCallbackThread()) { \ 80 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); \ 81 return; \ 82 } 83 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)); 84 if (!addr) { 85 ALOGE("Fail to new jbyteArray bd addr for connection state"); 86 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 87 return; 88 } 89 90 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr); 91 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAudioStateChanged, (jint) state, 92 addr); 93 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 94 sCallbackEnv->DeleteLocalRef(addr); 95 } 96 97 static void bta2dp_audio_config_callback(bt_bdaddr_t *bd_addr, uint32_t sample_rate, uint8_t channel_count) { 98 jbyteArray addr; 99 100 ALOGI("%s", __FUNCTION__); 101 102 if (!checkCallbackThread()) { \ 103 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); \ 104 return; \ 105 } 106 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)); 107 if (!addr) { 108 ALOGE("Fail to new jbyteArray bd addr for connection state"); 109 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 110 return; 111 } 112 113 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr); 114 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAudioConfigChanged, addr, (jint)sample_rate, (jint)channel_count); 115 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); 116 sCallbackEnv->DeleteLocalRef(addr); 117 } 118 119 static btav_callbacks_t sBluetoothA2dpCallbacks = { 120 sizeof(sBluetoothA2dpCallbacks), 121 bta2dp_connection_state_callback, 122 bta2dp_audio_state_callback, 123 bta2dp_audio_config_callback 124 }; 125 126 static void classInitNative(JNIEnv* env, jclass clazz) { 127 int err; 128 const bt_interface_t* btInf; 129 bt_status_t status; 130 131 method_onConnectionStateChanged = 132 env->GetMethodID(clazz, "onConnectionStateChanged", "(I[B)V"); 133 134 method_onAudioStateChanged = 135 env->GetMethodID(clazz, "onAudioStateChanged", "(I[B)V"); 136 137 method_onAudioConfigChanged = 138 env->GetMethodID(clazz, "onAudioConfigChanged", "([BII)V"); 139 140 ALOGI("%s: succeeds", __FUNCTION__); 141 } 142 143 static void initNative(JNIEnv *env, jobject object) { 144 const bt_interface_t* btInf; 145 bt_status_t status; 146 147 if ( (btInf = getBluetoothInterface()) == NULL) { 148 ALOGE("Bluetooth module is not loaded"); 149 return; 150 } 151 152 if (sBluetoothA2dpInterface !=NULL) { 153 ALOGW("Cleaning up A2DP Interface before initializing..."); 154 sBluetoothA2dpInterface->cleanup(); 155 sBluetoothA2dpInterface = NULL; 156 } 157 158 if (mCallbacksObj != NULL) { 159 ALOGW("Cleaning up A2DP callback object"); 160 env->DeleteGlobalRef(mCallbacksObj); 161 mCallbacksObj = NULL; 162 } 163 164 if ( (sBluetoothA2dpInterface = (btav_interface_t *) 165 btInf->get_profile_interface(BT_PROFILE_ADVANCED_AUDIO_SINK_ID)) == NULL) { 166 ALOGE("Failed to get Bluetooth A2DP Sink Interface"); 167 return; 168 } 169 170 if ( (status = sBluetoothA2dpInterface->init(&sBluetoothA2dpCallbacks)) != BT_STATUS_SUCCESS) { 171 ALOGE("Failed to initialize Bluetooth A2DP Sink, status: %d", status); 172 sBluetoothA2dpInterface = NULL; 173 return; 174 } 175 176 mCallbacksObj = env->NewGlobalRef(object); 177 } 178 179 static void cleanupNative(JNIEnv *env, jobject object) { 180 const bt_interface_t* btInf; 181 bt_status_t status; 182 183 if ( (btInf = getBluetoothInterface()) == NULL) { 184 ALOGE("Bluetooth module is not loaded"); 185 return; 186 } 187 188 if (sBluetoothA2dpInterface !=NULL) { 189 sBluetoothA2dpInterface->cleanup(); 190 sBluetoothA2dpInterface = NULL; 191 } 192 193 if (mCallbacksObj != NULL) { 194 env->DeleteGlobalRef(mCallbacksObj); 195 mCallbacksObj = NULL; 196 } 197 } 198 199 static jboolean connectA2dpNative(JNIEnv *env, jobject object, jbyteArray address) { 200 jbyte *addr; 201 bt_bdaddr_t * btAddr; 202 bt_status_t status; 203 204 ALOGI("%s: sBluetoothA2dpInterface: %p", __FUNCTION__, sBluetoothA2dpInterface); 205 if (!sBluetoothA2dpInterface) return JNI_FALSE; 206 207 addr = env->GetByteArrayElements(address, NULL); 208 btAddr = (bt_bdaddr_t *) addr; 209 if (!addr) { 210 jniThrowIOException(env, EINVAL); 211 return JNI_FALSE; 212 } 213 214 if ((status = sBluetoothA2dpInterface->connect((bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) { 215 ALOGE("Failed HF connection, status: %d", status); 216 } 217 env->ReleaseByteArrayElements(address, addr, 0); 218 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 219 } 220 221 static jboolean disconnectA2dpNative(JNIEnv *env, jobject object, jbyteArray address) { 222 jbyte *addr; 223 bt_status_t status; 224 225 if (!sBluetoothA2dpInterface) return JNI_FALSE; 226 227 addr = env->GetByteArrayElements(address, NULL); 228 if (!addr) { 229 jniThrowIOException(env, EINVAL); 230 return JNI_FALSE; 231 } 232 233 if ( (status = sBluetoothA2dpInterface->disconnect((bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) { 234 ALOGE("Failed HF disconnection, status: %d", status); 235 } 236 env->ReleaseByteArrayElements(address, addr, 0); 237 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 238 } 239 240 static JNINativeMethod sMethods[] = { 241 {"classInitNative", "()V", (void *) classInitNative}, 242 {"initNative", "()V", (void *) initNative}, 243 {"cleanupNative", "()V", (void *) cleanupNative}, 244 {"connectA2dpNative", "([B)Z", (void *) connectA2dpNative}, 245 {"disconnectA2dpNative", "([B)Z", (void *) disconnectA2dpNative}, 246 }; 247 248 int register_com_android_bluetooth_a2dp_sink(JNIEnv* env) 249 { 250 return jniRegisterNativeMethods(env, "com/android/bluetooth/a2dp/A2dpSinkStateMachine", 251 sMethods, NELEM(sMethods)); 252 } 253 254 } 255