blob: 90d1adf7eada9a5f5b30e13b7c722e756f37b0eb [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;
Gaurav Asatid2584b62013-10-09 14:07:46 +053031static jmethodID method_onCheckConnectionPriority;
AnubhavGuptad4b28382013-11-28 20:16:20 +053032static jmethodID method_onAudioFocusRequest;
Matthew Xie6c91bc02012-02-16 18:47:53 -080033
34static const btav_interface_t *sBluetoothA2dpInterface = NULL;
35static jobject mCallbacksObj = NULL;
36static JNIEnv *sCallbackEnv = NULL;
37
38static bool checkCallbackThread() {
Kausik Sinnaswamy93f548f2012-03-21 15:14:32 +053039 // Always fetch the latest callbackEnv from AdapterService.
40 // Caching this could cause this sCallbackEnv to go out-of-sync
41 // with the AdapterService's ENV if an ASSOCIATE/DISASSOCIATE event
42 // is received
43 //if (sCallbackEnv == NULL) {
44 sCallbackEnv = getCallbackEnv();
45 //}
Matthew Xie6c91bc02012-02-16 18:47:53 -080046
47 JNIEnv* env = AndroidRuntime::getJNIEnv();
48 if (sCallbackEnv != env || sCallbackEnv == NULL) return false;
49 return true;
50}
51
52static void bta2dp_connection_state_callback(btav_connection_state_t state, bt_bdaddr_t* bd_addr) {
53 jbyteArray addr;
54
Matthew Xiec55a9832012-04-07 03:44:13 -070055 ALOGI("%s", __FUNCTION__);
Matthew Xie6c91bc02012-02-16 18:47:53 -080056
57 if (!checkCallbackThread()) { \
Matthew Xiec55a9832012-04-07 03:44:13 -070058 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); \
Matthew Xie6c91bc02012-02-16 18:47:53 -080059 return; \
60 }
61 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
62 if (!addr) {
Matthew Xiec55a9832012-04-07 03:44:13 -070063 ALOGE("Fail to new jbyteArray bd addr for connection state");
Matthew Xie6c91bc02012-02-16 18:47:53 -080064 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, (jint) state,
70 addr);
71 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
72 sCallbackEnv->DeleteLocalRef(addr);
73}
74
Kausik Sinnaswamyac234ef2012-04-20 00:24:28 +053075static void bta2dp_audio_state_callback(btav_audio_state_t state, bt_bdaddr_t* bd_addr) {
76 jbyteArray addr;
77
Matthew Xiee469f162012-06-05 23:57:59 -070078 ALOGI("%s", __FUNCTION__);
Kausik Sinnaswamyac234ef2012-04-20 00:24:28 +053079
80 if (!checkCallbackThread()) { \
Matthew Xiee469f162012-06-05 23:57:59 -070081 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); \
Kausik Sinnaswamyac234ef2012-04-20 00:24:28 +053082 return; \
83 }
84 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
85 if (!addr) {
Matthew Xiee469f162012-06-05 23:57:59 -070086 ALOGE("Fail to new jbyteArray bd addr for connection state");
Kausik Sinnaswamyac234ef2012-04-20 00:24:28 +053087 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
88 return;
89 }
90
91 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
92 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAudioStateChanged, (jint) state,
93 addr);
94 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
95 sCallbackEnv->DeleteLocalRef(addr);
96}
97
Gaurav Asatid2584b62013-10-09 14:07:46 +053098static void bta2dp_connection_priority_callback(bt_bdaddr_t* bd_addr) {
99 jbyteArray addr;
100
101 ALOGI("%s", __FUNCTION__);
102
103 if (!checkCallbackThread()) { \
104 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); \
105 return; \
106 }
107 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
108 if (!addr) {
109 ALOGE("Fail to new jbyteArray bd addr for connection state");
110 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
111 return;
112 }
113
114 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
115 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCheckConnectionPriority, addr);
116 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
117 sCallbackEnv->DeleteLocalRef(addr);
118}
119
AnubhavGuptad4b28382013-11-28 20:16:20 +0530120static void bta2dp_audio_focus_request_callback(int enable, bt_bdaddr_t* bd_addr) {
121 jbyteArray addr;
122
123 ALOGI("%s", __FUNCTION__);
124
125 if (!checkCallbackThread()) { \
126 ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); \
127 return; \
128 }
129 addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
130 if (!addr) {
131 ALOGE("Fail to new jbyteArray bd addr for connection state");
132 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
133 return;
134 }
135
136 sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
137 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAudioFocusRequest, (jint) enable, addr);
138 checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
139 sCallbackEnv->DeleteLocalRef(addr);
140}
Matthew Xie6c91bc02012-02-16 18:47:53 -0800141static btav_callbacks_t sBluetoothA2dpCallbacks = {
142 sizeof(sBluetoothA2dpCallbacks),
143 bta2dp_connection_state_callback,
Gaurav Asatid2584b62013-10-09 14:07:46 +0530144 bta2dp_audio_state_callback,
AnubhavGuptad4b28382013-11-28 20:16:20 +0530145 bta2dp_connection_priority_callback,
146 bta2dp_audio_focus_request_callback
Matthew Xie6c91bc02012-02-16 18:47:53 -0800147};
148
149static void classInitNative(JNIEnv* env, jclass clazz) {
150 int err;
151 const bt_interface_t* btInf;
152 bt_status_t status;
153
154 method_onConnectionStateChanged =
155 env->GetMethodID(clazz, "onConnectionStateChanged", "(I[B)V");
156
Kausik Sinnaswamyac234ef2012-04-20 00:24:28 +0530157 method_onAudioStateChanged =
158 env->GetMethodID(clazz, "onAudioStateChanged", "(I[B)V");
Gaurav Asatid2584b62013-10-09 14:07:46 +0530159
160 method_onCheckConnectionPriority =
161 env->GetMethodID(clazz, "onCheckConnectionPriority", "([B)V");
AnubhavGuptad4b28382013-11-28 20:16:20 +0530162
163 method_onAudioFocusRequest =
164 env->GetMethodID(clazz, "onAudioFocusRequest", "(I[B)V");
fredc6654f5c2012-04-12 00:18:52 -0700165 /*
Matthew Xie6c91bc02012-02-16 18:47:53 -0800166 if ( (btInf = getBluetoothInterface()) == NULL) {
Matthew Xiec55a9832012-04-07 03:44:13 -0700167 ALOGE("Bluetooth module is not loaded");
Matthew Xie6c91bc02012-02-16 18:47:53 -0800168 return;
169 }
170
171 if ( (sBluetoothA2dpInterface = (btav_interface_t *)
172 btInf->get_profile_interface(BT_PROFILE_ADVANCED_AUDIO_ID)) == NULL) {
Matthew Xiec55a9832012-04-07 03:44:13 -0700173 ALOGE("Failed to get Bluetooth A2DP Interface");
Matthew Xie6c91bc02012-02-16 18:47:53 -0800174 return;
175 }
fredc6654f5c2012-04-12 00:18:52 -0700176 */
Matthew Xie6c91bc02012-02-16 18:47:53 -0800177
178 // TODO(BT) do this only once or
179 // Do we need to do this every time the BT reenables?
fredc6654f5c2012-04-12 00:18:52 -0700180 /*
181 if ( (status = sBluetoothA2dpInterface->init(&sBluetoothA2dpCallbacks)) != BT_STATUS_SUCCESS) {
Matthew Xiec55a9832012-04-07 03:44:13 -0700182 ALOGE("Failed to initialize Bluetooth A2DP, status: %d", status);
fredc6654f5c2012-04-12 00:18:52 -0700183 sBluetoothA2dpInterface = NULL;
184 return;
185 }*/
186
Matthew Xiec55a9832012-04-07 03:44:13 -0700187 ALOGI("%s: succeeds", __FUNCTION__);
fredc6654f5c2012-04-12 00:18:52 -0700188}
189
190static void initNative(JNIEnv *env, jobject object) {
191 const bt_interface_t* btInf;
192 bt_status_t status;
193
194 if ( (btInf = getBluetoothInterface()) == NULL) {
Matthew Xiee469f162012-06-05 23:57:59 -0700195 ALOGE("Bluetooth module is not loaded");
fredc6654f5c2012-04-12 00:18:52 -0700196 return;
197 }
198
199 if (sBluetoothA2dpInterface !=NULL) {
Matthew Xiee469f162012-06-05 23:57:59 -0700200 ALOGW("Cleaning up A2DP Interface before initializing...");
fredc6654f5c2012-04-12 00:18:52 -0700201 sBluetoothA2dpInterface->cleanup();
202 sBluetoothA2dpInterface = NULL;
203 }
204
205 if (mCallbacksObj != NULL) {
Matthew Xiee469f162012-06-05 23:57:59 -0700206 ALOGW("Cleaning up A2DP callback object");
fredc6654f5c2012-04-12 00:18:52 -0700207 env->DeleteGlobalRef(mCallbacksObj);
208 mCallbacksObj = NULL;
209 }
210
211 if ( (sBluetoothA2dpInterface = (btav_interface_t *)
212 btInf->get_profile_interface(BT_PROFILE_ADVANCED_AUDIO_ID)) == NULL) {
Matthew Xiee469f162012-06-05 23:57:59 -0700213 ALOGE("Failed to get Bluetooth A2DP Interface");
fredc6654f5c2012-04-12 00:18:52 -0700214 return;
215 }
216
Matthew Xie6c91bc02012-02-16 18:47:53 -0800217 if ( (status = sBluetoothA2dpInterface->init(&sBluetoothA2dpCallbacks)) != BT_STATUS_SUCCESS) {
Matthew Xiee469f162012-06-05 23:57:59 -0700218 ALOGE("Failed to initialize Bluetooth A2DP, status: %d", status);
Matthew Xie6c91bc02012-02-16 18:47:53 -0800219 sBluetoothA2dpInterface = NULL;
220 return;
221 }
222
fredc6654f5c2012-04-12 00:18:52 -0700223 mCallbacksObj = env->NewGlobalRef(object);
Matthew Xie6c91bc02012-02-16 18:47:53 -0800224}
225
fredc6654f5c2012-04-12 00:18:52 -0700226static void cleanupNative(JNIEnv *env, jobject object) {
227 const bt_interface_t* btInf;
228 bt_status_t status;
229
230 if ( (btInf = getBluetoothInterface()) == NULL) {
Matthew Xiee469f162012-06-05 23:57:59 -0700231 ALOGE("Bluetooth module is not loaded");
fredc6654f5c2012-04-12 00:18:52 -0700232 return;
233 }
234
235 if (sBluetoothA2dpInterface !=NULL) {
236 sBluetoothA2dpInterface->cleanup();
237 sBluetoothA2dpInterface = NULL;
238 }
239
240 if (mCallbacksObj != NULL) {
241 env->DeleteGlobalRef(mCallbacksObj);
242 mCallbacksObj = NULL;
243 }
Matthew Xie6c91bc02012-02-16 18:47:53 -0800244}
245
246static jboolean connectA2dpNative(JNIEnv *env, jobject object, jbyteArray address) {
247 jbyte *addr;
248 bt_bdaddr_t * btAddr;
249 bt_status_t status;
250
Matthew Xiec55a9832012-04-07 03:44:13 -0700251 ALOGI("%s: sBluetoothA2dpInterface: %p", __FUNCTION__, sBluetoothA2dpInterface);
Matthew Xie6c91bc02012-02-16 18:47:53 -0800252 if (!sBluetoothA2dpInterface) return JNI_FALSE;
253
254 addr = env->GetByteArrayElements(address, NULL);
255 btAddr = (bt_bdaddr_t *) addr;
256 if (!addr) {
257 jniThrowIOException(env, EINVAL);
258 return JNI_FALSE;
259 }
260
261 if ((status = sBluetoothA2dpInterface->connect((bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
Matthew Xiec55a9832012-04-07 03:44:13 -0700262 ALOGE("Failed HF connection, status: %d", status);
Matthew Xie6c91bc02012-02-16 18:47:53 -0800263 }
264 env->ReleaseByteArrayElements(address, addr, 0);
265 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
266}
267
268static jboolean disconnectA2dpNative(JNIEnv *env, jobject object, jbyteArray address) {
269 jbyte *addr;
270 bt_status_t status;
271
272 if (!sBluetoothA2dpInterface) return JNI_FALSE;
273
274 addr = env->GetByteArrayElements(address, NULL);
275 if (!addr) {
276 jniThrowIOException(env, EINVAL);
277 return JNI_FALSE;
278 }
279
280 if ( (status = sBluetoothA2dpInterface->disconnect((bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
Gaurav Asatid2584b62013-10-09 14:07:46 +0530281 ALOGE("Failed A2DP disconnection, status: %d", status);
Matthew Xie6c91bc02012-02-16 18:47:53 -0800282 }
283 env->ReleaseByteArrayElements(address, addr, 0);
284 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
285}
286
Gaurav Asatid2584b62013-10-09 14:07:46 +0530287static void allowConnectionNative(JNIEnv *env, jobject object, int is_valid) {
288
289 if (!sBluetoothA2dpInterface) {
290 ALOGE("sBluetoothA2dpInterface is NULL ");
291 return;
292 }
293
294 sBluetoothA2dpInterface->allow_connection(is_valid);
295
296}
297
Gubbala Venugopal Rao819d65f2014-01-02 16:35:12 +0530298static void informAudioFocusStateNative(JNIEnv *env, jobject object, int state) {
AnubhavGuptad4b28382013-11-28 20:16:20 +0530299
300 if (!sBluetoothA2dpInterface) {
301 ALOGE("sBluetoothA2dpInterface is NULL ");
302 return;
303 }
Gubbala Venugopal Rao819d65f2014-01-02 16:35:12 +0530304 sBluetoothA2dpInterface->audio_focus_status(state);
AnubhavGuptad4b28382013-11-28 20:16:20 +0530305
306}
307
Gaurav Asati00af3b02014-02-27 14:39:20 +0530308static jint isSrcNative(JNIEnv *env, jobject object, jbyteArray address) {
Anubhav Guptade7eb802013-11-08 14:18:37 +0530309 jbyte *addr;
310 bt_status_t status;
311
AnubhavGupta851de922014-03-15 18:39:01 +0530312 if (!sBluetoothA2dpInterface) {
313 ALOGE("sBluetoothA2dpInterface is NULL ");
314 return JNI_FALSE;
315 }
Anubhav Guptade7eb802013-11-08 14:18:37 +0530316
317 addr = env->GetByteArrayElements(address, NULL);
318 if (!addr) {
319 jniThrowIOException(env, EINVAL);
320 return JNI_FALSE;
321 }
322
AnubhavGupta851de922014-03-15 18:39:01 +0530323 status = sBluetoothA2dpInterface->is_src((bt_bdaddr_t *)addr);
Anubhav Guptade7eb802013-11-08 14:18:37 +0530324 env->ReleaseByteArrayElements(address, addr, 0);
Gaurav Asati00af3b02014-02-27 14:39:20 +0530325 return status;
Anubhav Guptade7eb802013-11-08 14:18:37 +0530326}
327
328static void suspendA2dpNative(JNIEnv *env, jobject object) {
329
330 if (!sBluetoothA2dpInterface) {
331 ALOGE("sBluetoothA2dpInterface is NULL ");
332 return;
333 }
334
335 sBluetoothA2dpInterface->suspend_sink();
336}
337
AnubhavGuptad4b28382013-11-28 20:16:20 +0530338static void resumeA2dpNative(JNIEnv *env, jobject object) {
339
340 if (!sBluetoothA2dpInterface) {
341 ALOGE("sBluetoothA2dpInterface is NULL ");
342 return;
343 }
344
345 sBluetoothA2dpInterface->resume_sink();
346}
347
Anubhav Guptade7eb802013-11-08 14:18:37 +0530348
Matthew Xie6c91bc02012-02-16 18:47:53 -0800349static JNINativeMethod sMethods[] = {
350 {"classInitNative", "()V", (void *) classInitNative},
fredc6654f5c2012-04-12 00:18:52 -0700351 {"initNative", "()V", (void *) initNative},
352 {"cleanupNative", "()V", (void *) cleanupNative},
Matthew Xie6c91bc02012-02-16 18:47:53 -0800353 {"connectA2dpNative", "([B)Z", (void *) connectA2dpNative},
354 {"disconnectA2dpNative", "([B)Z", (void *) disconnectA2dpNative},
Gaurav Asatid2584b62013-10-09 14:07:46 +0530355 {"allowConnectionNative", "(I)V", (void *) allowConnectionNative},
Gaurav Asati00af3b02014-02-27 14:39:20 +0530356 {"isSrcNative", "([B)I", (void *) isSrcNative},
Anubhav Guptade7eb802013-11-08 14:18:37 +0530357 {"suspendA2dpNative", "()V", (void *) suspendA2dpNative},
AnubhavGuptad4b28382013-11-28 20:16:20 +0530358 {"resumeA2dpNative", "()V", (void *) resumeA2dpNative},
359 {"informAudioFocusStateNative", "(I)V", (void *) informAudioFocusStateNative},
Matthew Xie6c91bc02012-02-16 18:47:53 -0800360};
361
362int register_com_android_bluetooth_a2dp(JNIEnv* env)
363{
Anubhav Guptade7eb802013-11-08 14:18:37 +0530364 return jniRegisterNativeMethods(env, "com/android/bluetooth/a2dp/A2dpStateMachine",
Matthew Xie6c91bc02012-02-16 18:47:53 -0800365 sMethods, NELEM(sMethods));
366}
367
368}