blob: 28c03aed21d1f22cc3b54f987fe628ed1d7b2c04 [file] [log] [blame]
Matthew Xie6c91bc02012-02-16 18:47:53 -08001/*
Zhihai Xuede67c22012-10-23 17:01:01 -07002 * 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.
Matthew Xie6c91bc02012-02-16 18:47:53 -080015 */
Zhihai Xuede67c22012-10-23 17:01:01 -070016
Matthew Xie6c91bc02012-02-16 18:47:53 -080017#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
28namespace android {
29static jmethodID method_onConnectionStateChanged;
Kausik Sinnaswamyac234ef2012-04-20 00:24:28 +053030static jmethodID method_onAudioStateChanged;
broodplank0c589302013-12-29 05:41:41 +010031static jmethodID method_onCheckConnectionPriority;
Matthew Xie6c91bc02012-02-16 18:47:53 -080032
33static const btav_interface_t *sBluetoothA2dpInterface = NULL;
34static jobject mCallbacksObj = NULL;
35static JNIEnv *sCallbackEnv = NULL;
36
37static bool checkCallbackThread() {
Kausik Sinnaswamy93f548f2012-03-21 15:14:32 +053038 // 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 //}
Matthew Xie6c91bc02012-02-16 18:47:53 -080045
46 JNIEnv* env = AndroidRuntime::getJNIEnv();
47 if (sCallbackEnv != env || sCallbackEnv == NULL) return false;
48 return true;
49}
50
51static void bta2dp_connection_state_callback(btav_connection_state_t state, bt_bdaddr_t* bd_addr) {
52 jbyteArray addr;
53
Matthew Xiec55a9832012-04-07 03:44:13 -070054 ALOGI("%s", __FUNCTION__);
Matthew Xie6c91bc02012-02-16 18:47:53 -080055
56 if (!checkCallbackThread()) { \
Matthew Xiec55a9832012-04-07 03:44:13 -070057 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); \
Matthew Xie6c91bc02012-02-16 18:47:53 -080058 return; \
59 }
60 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
61 if (!addr) {
Matthew Xiec55a9832012-04-07 03:44:13 -070062 ALOGE("Fail to new jbyteArray bd addr for connection state");
Matthew Xie6c91bc02012-02-16 18:47:53 -080063 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
Kausik Sinnaswamyac234ef2012-04-20 00:24:28 +053074static void bta2dp_audio_state_callback(btav_audio_state_t state, bt_bdaddr_t* bd_addr) {
75 jbyteArray addr;
76
Matthew Xiee469f162012-06-05 23:57:59 -070077 ALOGI("%s", __FUNCTION__);
Kausik Sinnaswamyac234ef2012-04-20 00:24:28 +053078
79 if (!checkCallbackThread()) { \
Matthew Xiee469f162012-06-05 23:57:59 -070080 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); \
Kausik Sinnaswamyac234ef2012-04-20 00:24:28 +053081 return; \
82 }
83 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
84 if (!addr) {
Matthew Xiee469f162012-06-05 23:57:59 -070085 ALOGE("Fail to new jbyteArray bd addr for connection state");
Kausik Sinnaswamyac234ef2012-04-20 00:24:28 +053086 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
broodplank0c589302013-12-29 05:41:41 +010097static void bta2dp_connection_priority_callback(bt_bdaddr_t* bd_addr) {
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_onCheckConnectionPriority, addr);
115 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
116 sCallbackEnv->DeleteLocalRef(addr);
117}
118
Matthew Xie6c91bc02012-02-16 18:47:53 -0800119static btav_callbacks_t sBluetoothA2dpCallbacks = {
120 sizeof(sBluetoothA2dpCallbacks),
121 bta2dp_connection_state_callback,
broodplank0c589302013-12-29 05:41:41 +0100122 bta2dp_audio_state_callback,
123 bta2dp_connection_priority_callback
Matthew Xie6c91bc02012-02-16 18:47:53 -0800124};
125
126static 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
Kausik Sinnaswamyac234ef2012-04-20 00:24:28 +0530134 method_onAudioStateChanged =
135 env->GetMethodID(clazz, "onAudioStateChanged", "(I[B)V");
broodplank0c589302013-12-29 05:41:41 +0100136
137 method_onCheckConnectionPriority =
138 env->GetMethodID(clazz, "onCheckConnectionPriority", "([B)V");
fredc6654f5c2012-04-12 00:18:52 -0700139 /*
Matthew Xie6c91bc02012-02-16 18:47:53 -0800140 if ( (btInf = getBluetoothInterface()) == NULL) {
Matthew Xiec55a9832012-04-07 03:44:13 -0700141 ALOGE("Bluetooth module is not loaded");
Matthew Xie6c91bc02012-02-16 18:47:53 -0800142 return;
143 }
144
145 if ( (sBluetoothA2dpInterface = (btav_interface_t *)
146 btInf->get_profile_interface(BT_PROFILE_ADVANCED_AUDIO_ID)) == NULL) {
Matthew Xiec55a9832012-04-07 03:44:13 -0700147 ALOGE("Failed to get Bluetooth A2DP Interface");
Matthew Xie6c91bc02012-02-16 18:47:53 -0800148 return;
149 }
fredc6654f5c2012-04-12 00:18:52 -0700150 */
Matthew Xie6c91bc02012-02-16 18:47:53 -0800151
152 // TODO(BT) do this only once or
153 // Do we need to do this every time the BT reenables?
fredc6654f5c2012-04-12 00:18:52 -0700154 /*
155 if ( (status = sBluetoothA2dpInterface->init(&sBluetoothA2dpCallbacks)) != BT_STATUS_SUCCESS) {
Matthew Xiec55a9832012-04-07 03:44:13 -0700156 ALOGE("Failed to initialize Bluetooth A2DP, status: %d", status);
fredc6654f5c2012-04-12 00:18:52 -0700157 sBluetoothA2dpInterface = NULL;
158 return;
159 }*/
160
Matthew Xiec55a9832012-04-07 03:44:13 -0700161 ALOGI("%s: succeeds", __FUNCTION__);
fredc6654f5c2012-04-12 00:18:52 -0700162}
163
164static void initNative(JNIEnv *env, jobject object) {
165 const bt_interface_t* btInf;
166 bt_status_t status;
167
168 if ( (btInf = getBluetoothInterface()) == NULL) {
Matthew Xiee469f162012-06-05 23:57:59 -0700169 ALOGE("Bluetooth module is not loaded");
fredc6654f5c2012-04-12 00:18:52 -0700170 return;
171 }
172
173 if (sBluetoothA2dpInterface !=NULL) {
Matthew Xiee469f162012-06-05 23:57:59 -0700174 ALOGW("Cleaning up A2DP Interface before initializing...");
fredc6654f5c2012-04-12 00:18:52 -0700175 sBluetoothA2dpInterface->cleanup();
176 sBluetoothA2dpInterface = NULL;
177 }
178
179 if (mCallbacksObj != NULL) {
Matthew Xiee469f162012-06-05 23:57:59 -0700180 ALOGW("Cleaning up A2DP callback object");
fredc6654f5c2012-04-12 00:18:52 -0700181 env->DeleteGlobalRef(mCallbacksObj);
182 mCallbacksObj = NULL;
183 }
184
185 if ( (sBluetoothA2dpInterface = (btav_interface_t *)
186 btInf->get_profile_interface(BT_PROFILE_ADVANCED_AUDIO_ID)) == NULL) {
Matthew Xiee469f162012-06-05 23:57:59 -0700187 ALOGE("Failed to get Bluetooth A2DP Interface");
fredc6654f5c2012-04-12 00:18:52 -0700188 return;
189 }
190
Matthew Xie6c91bc02012-02-16 18:47:53 -0800191 if ( (status = sBluetoothA2dpInterface->init(&sBluetoothA2dpCallbacks)) != BT_STATUS_SUCCESS) {
Matthew Xiee469f162012-06-05 23:57:59 -0700192 ALOGE("Failed to initialize Bluetooth A2DP, status: %d", status);
Matthew Xie6c91bc02012-02-16 18:47:53 -0800193 sBluetoothA2dpInterface = NULL;
194 return;
195 }
196
fredc6654f5c2012-04-12 00:18:52 -0700197 mCallbacksObj = env->NewGlobalRef(object);
Matthew Xie6c91bc02012-02-16 18:47:53 -0800198}
199
fredc6654f5c2012-04-12 00:18:52 -0700200static void cleanupNative(JNIEnv *env, jobject object) {
201 const bt_interface_t* btInf;
202 bt_status_t status;
203
204 if ( (btInf = getBluetoothInterface()) == NULL) {
Matthew Xiee469f162012-06-05 23:57:59 -0700205 ALOGE("Bluetooth module is not loaded");
fredc6654f5c2012-04-12 00:18:52 -0700206 return;
207 }
208
209 if (sBluetoothA2dpInterface !=NULL) {
210 sBluetoothA2dpInterface->cleanup();
211 sBluetoothA2dpInterface = NULL;
212 }
213
214 if (mCallbacksObj != NULL) {
215 env->DeleteGlobalRef(mCallbacksObj);
216 mCallbacksObj = NULL;
217 }
Matthew Xie6c91bc02012-02-16 18:47:53 -0800218}
219
220static jboolean connectA2dpNative(JNIEnv *env, jobject object, jbyteArray address) {
221 jbyte *addr;
222 bt_bdaddr_t * btAddr;
223 bt_status_t status;
224
Matthew Xiec55a9832012-04-07 03:44:13 -0700225 ALOGI("%s: sBluetoothA2dpInterface: %p", __FUNCTION__, sBluetoothA2dpInterface);
Matthew Xie6c91bc02012-02-16 18:47:53 -0800226 if (!sBluetoothA2dpInterface) return JNI_FALSE;
227
228 addr = env->GetByteArrayElements(address, NULL);
229 btAddr = (bt_bdaddr_t *) addr;
230 if (!addr) {
231 jniThrowIOException(env, EINVAL);
232 return JNI_FALSE;
233 }
234
235 if ((status = sBluetoothA2dpInterface->connect((bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
Matthew Xiec55a9832012-04-07 03:44:13 -0700236 ALOGE("Failed HF connection, status: %d", status);
Matthew Xie6c91bc02012-02-16 18:47:53 -0800237 }
238 env->ReleaseByteArrayElements(address, addr, 0);
239 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
240}
241
242static jboolean disconnectA2dpNative(JNIEnv *env, jobject object, jbyteArray address) {
243 jbyte *addr;
244 bt_status_t status;
245
246 if (!sBluetoothA2dpInterface) return JNI_FALSE;
247
248 addr = env->GetByteArrayElements(address, NULL);
249 if (!addr) {
250 jniThrowIOException(env, EINVAL);
251 return JNI_FALSE;
252 }
253
254 if ( (status = sBluetoothA2dpInterface->disconnect((bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
broodplank0c589302013-12-29 05:41:41 +0100255 ALOGE("Failed A2DP disconnection, status: %d", status);
Matthew Xie6c91bc02012-02-16 18:47:53 -0800256 }
257 env->ReleaseByteArrayElements(address, addr, 0);
258 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
259}
260
broodplank0c589302013-12-29 05:41:41 +0100261static void allowConnectionNative(JNIEnv *env, jobject object, int is_valid) {
262
263 if (!sBluetoothA2dpInterface) {
264 ALOGE("sBluetoothA2dpInterface is NULL ");
265 return;
266 }
267
268 sBluetoothA2dpInterface->allow_connection(is_valid);
269
270}
271
Matthew Xie6c91bc02012-02-16 18:47:53 -0800272static JNINativeMethod sMethods[] = {
273 {"classInitNative", "()V", (void *) classInitNative},
fredc6654f5c2012-04-12 00:18:52 -0700274 {"initNative", "()V", (void *) initNative},
275 {"cleanupNative", "()V", (void *) cleanupNative},
Matthew Xie6c91bc02012-02-16 18:47:53 -0800276 {"connectA2dpNative", "([B)Z", (void *) connectA2dpNative},
277 {"disconnectA2dpNative", "([B)Z", (void *) disconnectA2dpNative},
broodplank0c589302013-12-29 05:41:41 +0100278 {"allowConnectionNative", "(I)V", (void *) allowConnectionNative},
Matthew Xie6c91bc02012-02-16 18:47:53 -0800279};
280
281int register_com_android_bluetooth_a2dp(JNIEnv* env)
282{
283 return jniRegisterNativeMethods(env, "com/android/bluetooth/a2dp/A2dpStateMachine",
284 sMethods, NELEM(sMethods));
285}
286
287}