• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "BluetoothAvrcpServiceJni"
18 
19 #define LOG_NDEBUG 0
20 
21 #include "com_android_bluetooth.h"
22 #include "hardware/bt_rc.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_getRcFeatures;
30 static jmethodID method_getPlayStatus;
31 static jmethodID method_getElementAttr;
32 static jmethodID method_registerNotification;
33 static jmethodID method_volumeChangeCallback;
34 static jmethodID method_handlePassthroughCmd;
35 
36 static const btrc_interface_t *sBluetoothAvrcpInterface = NULL;
37 static jobject mCallbacksObj = NULL;
38 static JNIEnv *sCallbackEnv = NULL;
39 
checkCallbackThread()40 static bool checkCallbackThread() {
41     // Always fetch the latest callbackEnv from AdapterService.
42     // Caching this could cause this sCallbackEnv to go out-of-sync
43     // with the AdapterService's ENV if an ASSOCIATE/DISASSOCIATE event
44     // is received
45     sCallbackEnv = getCallbackEnv();
46 
47     JNIEnv* env = AndroidRuntime::getJNIEnv();
48     if (sCallbackEnv != env || sCallbackEnv == NULL) return false;
49     return true;
50 }
51 
btavrcp_remote_features_callback(bt_bdaddr_t * bd_addr,btrc_remote_features_t features)52 static void btavrcp_remote_features_callback(bt_bdaddr_t* bd_addr, btrc_remote_features_t features) {
53     ALOGI("%s", __FUNCTION__);
54     jbyteArray addr;
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_getRcFeatures, addr, (jint)features);
69     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
70     sCallbackEnv->DeleteLocalRef(addr);
71 }
72 
btavrcp_get_play_status_callback()73 static void btavrcp_get_play_status_callback() {
74     ALOGI("%s", __FUNCTION__);
75 
76     if (!checkCallbackThread()) {
77         ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
78         return;
79     }
80 
81     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getPlayStatus);
82     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
83 }
84 
btavrcp_get_element_attr_callback(uint8_t num_attr,btrc_media_attr_t * p_attrs)85 static void btavrcp_get_element_attr_callback(uint8_t num_attr, btrc_media_attr_t *p_attrs) {
86     jintArray attrs;
87 
88     ALOGI("%s", __FUNCTION__);
89 
90     if (!checkCallbackThread()) {
91         ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
92         return;
93     }
94     attrs = (jintArray)sCallbackEnv->NewIntArray(num_attr);
95     if (!attrs) {
96         ALOGE("Fail to new jintArray for attrs");
97         checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
98         return;
99     }
100     sCallbackEnv->SetIntArrayRegion(attrs, 0, num_attr, (jint *)p_attrs);
101     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getElementAttr, (jbyte)num_attr, attrs);
102     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
103     sCallbackEnv->DeleteLocalRef(attrs);
104 }
105 
btavrcp_register_notification_callback(btrc_event_id_t event_id,uint32_t param)106 static void btavrcp_register_notification_callback(btrc_event_id_t event_id, uint32_t param) {
107     ALOGI("%s", __FUNCTION__);
108 
109     if (!checkCallbackThread()) {
110         ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
111         return;
112     }
113 
114     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_registerNotification,
115                                  (jint)event_id, (jint)param);
116     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
117 }
118 
btavrcp_volume_change_callback(uint8_t volume,uint8_t ctype)119 static void btavrcp_volume_change_callback(uint8_t volume, uint8_t ctype) {
120     ALOGI("%s", __FUNCTION__);
121 
122     if (!checkCallbackThread()) {
123         ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
124         return;
125     }
126 
127     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_volumeChangeCallback, (jint)volume,
128                                                                              (jint)ctype);
129     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
130 }
131 
btavrcp_passthrough_command_callback(int id,int pressed)132 static void btavrcp_passthrough_command_callback(int id, int pressed) {
133     ALOGI("%s", __FUNCTION__);
134 
135     if (!checkCallbackThread()) {
136         ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
137         return;
138     }
139 
140     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_handlePassthroughCmd, (jint)id,
141                                                                              (jint)pressed);
142     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
143 }
144 
145 static btrc_callbacks_t sBluetoothAvrcpCallbacks = {
146     sizeof(sBluetoothAvrcpCallbacks),
147     btavrcp_remote_features_callback,
148     btavrcp_get_play_status_callback,
149     NULL,
150     NULL,
151     NULL,
152     NULL,
153     NULL,
154     NULL,
155     btavrcp_get_element_attr_callback,
156     btavrcp_register_notification_callback,
157     btavrcp_volume_change_callback,
158     btavrcp_passthrough_command_callback,
159 };
160 
classInitNative(JNIEnv * env,jclass clazz)161 static void classInitNative(JNIEnv* env, jclass clazz) {
162     method_getRcFeatures =
163         env->GetMethodID(clazz, "getRcFeatures", "([BI)V");
164     method_getPlayStatus =
165         env->GetMethodID(clazz, "getPlayStatus", "()V");
166 
167     method_getElementAttr =
168         env->GetMethodID(clazz, "getElementAttr", "(B[I)V");
169 
170     method_registerNotification =
171         env->GetMethodID(clazz, "registerNotification", "(II)V");
172 
173     method_volumeChangeCallback =
174         env->GetMethodID(clazz, "volumeChangeCallback", "(II)V");
175 
176     method_handlePassthroughCmd =
177         env->GetMethodID(clazz, "handlePassthroughCmd", "(II)V");
178 
179     ALOGI("%s: succeeds", __FUNCTION__);
180 }
181 
initNative(JNIEnv * env,jobject object)182 static void initNative(JNIEnv *env, jobject object) {
183     const bt_interface_t* btInf;
184     bt_status_t status;
185 
186     if ( (btInf = getBluetoothInterface()) == NULL) {
187         ALOGE("Bluetooth module is not loaded");
188         return;
189     }
190 
191     if (sBluetoothAvrcpInterface !=NULL) {
192          ALOGW("Cleaning up Avrcp Interface before initializing...");
193          sBluetoothAvrcpInterface->cleanup();
194          sBluetoothAvrcpInterface = NULL;
195     }
196 
197     if (mCallbacksObj != NULL) {
198          ALOGW("Cleaning up Avrcp callback object");
199          env->DeleteGlobalRef(mCallbacksObj);
200          mCallbacksObj = NULL;
201     }
202 
203     if ( (sBluetoothAvrcpInterface = (btrc_interface_t *)
204           btInf->get_profile_interface(BT_PROFILE_AV_RC_ID)) == NULL) {
205         ALOGE("Failed to get Bluetooth Avrcp Interface");
206         return;
207     }
208 
209     if ( (status = sBluetoothAvrcpInterface->init(&sBluetoothAvrcpCallbacks)) !=
210          BT_STATUS_SUCCESS) {
211         ALOGE("Failed to initialize Bluetooth Avrcp, status: %d", status);
212         sBluetoothAvrcpInterface = NULL;
213         return;
214     }
215 
216     mCallbacksObj = env->NewGlobalRef(object);
217 }
218 
cleanupNative(JNIEnv * env,jobject object)219 static void cleanupNative(JNIEnv *env, jobject object) {
220     const bt_interface_t* btInf;
221 
222     if ( (btInf = getBluetoothInterface()) == NULL) {
223         ALOGE("Bluetooth module is not loaded");
224         return;
225     }
226 
227     if (sBluetoothAvrcpInterface !=NULL) {
228         sBluetoothAvrcpInterface->cleanup();
229         sBluetoothAvrcpInterface = NULL;
230     }
231 
232     if (mCallbacksObj != NULL) {
233         env->DeleteGlobalRef(mCallbacksObj);
234         mCallbacksObj = NULL;
235     }
236 }
237 
getPlayStatusRspNative(JNIEnv * env,jobject object,jint playStatus,jint songLen,jint songPos)238 static jboolean getPlayStatusRspNative(JNIEnv *env, jobject object, jint playStatus,
239                                        jint songLen, jint songPos) {
240     bt_status_t status;
241 
242     ALOGI("%s: sBluetoothAvrcpInterface: %p", __FUNCTION__, sBluetoothAvrcpInterface);
243     if (!sBluetoothAvrcpInterface) return JNI_FALSE;
244 
245     if ((status = sBluetoothAvrcpInterface->get_play_status_rsp((btrc_play_status_t)playStatus,
246                                             songLen, songPos)) != BT_STATUS_SUCCESS) {
247         ALOGE("Failed get_play_status_rsp, status: %d", status);
248     }
249 
250     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
251 }
252 
getElementAttrRspNative(JNIEnv * env,jobject object,jbyte numAttr,jintArray attrIds,jobjectArray textArray)253   static jboolean getElementAttrRspNative(JNIEnv *env, jobject object, jbyte numAttr,
254                                           jintArray attrIds, jobjectArray textArray) {
255     jint *attr;
256     bt_status_t status;
257     jstring text;
258     int i;
259     btrc_element_attr_val_t *pAttrs = NULL;
260     const char* textStr;
261 
262     if (!sBluetoothAvrcpInterface) return JNI_FALSE;
263 
264     if (numAttr > BTRC_MAX_ELEM_ATTR_SIZE) {
265         ALOGE("get_element_attr_rsp: number of attributes exceed maximum");
266         return JNI_FALSE;
267     }
268 
269     pAttrs = new btrc_element_attr_val_t[numAttr];
270     if (!pAttrs) {
271         ALOGE("get_element_attr_rsp: not have enough memeory");
272         return JNI_FALSE;
273     }
274 
275     attr = env->GetIntArrayElements(attrIds, NULL);
276     if (!attr) {
277         delete[] pAttrs;
278         jniThrowIOException(env, EINVAL);
279         return JNI_FALSE;
280     }
281 
282     for (i = 0; i < numAttr; ++i) {
283         text = (jstring) env->GetObjectArrayElement(textArray, i);
284         textStr = env->GetStringUTFChars(text, NULL);
285         if (!textStr) {
286             ALOGE("get_element_attr_rsp: GetStringUTFChars return NULL");
287             env->DeleteLocalRef(text);
288             break;
289         }
290 
291         pAttrs[i].attr_id = attr[i];
292         if (strlen(textStr) >= BTRC_MAX_ATTR_STR_LEN) {
293             ALOGE("get_element_attr_rsp: string length exceed maximum");
294             strncpy((char *)pAttrs[i].text, textStr, BTRC_MAX_ATTR_STR_LEN-1);
295             pAttrs[i].text[BTRC_MAX_ATTR_STR_LEN-1] = 0;
296         } else {
297             strcpy((char *)pAttrs[i].text, textStr);
298         }
299         env->ReleaseStringUTFChars(text, textStr);
300         env->DeleteLocalRef(text);
301     }
302 
303     if (i < numAttr) {
304         delete[] pAttrs;
305         env->ReleaseIntArrayElements(attrIds, attr, 0);
306         return JNI_FALSE;
307     }
308 
309     if ((status = sBluetoothAvrcpInterface->get_element_attr_rsp(numAttr, pAttrs)) !=
310         BT_STATUS_SUCCESS) {
311         ALOGE("Failed get_element_attr_rsp, status: %d", status);
312     }
313 
314     delete[] pAttrs;
315     env->ReleaseIntArrayElements(attrIds, attr, 0);
316     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
317 }
318 
registerNotificationRspPlayStatusNative(JNIEnv * env,jobject object,jint type,jint playStatus)319 static jboolean registerNotificationRspPlayStatusNative(JNIEnv *env, jobject object,
320                                                         jint type, jint playStatus) {
321     bt_status_t status;
322     btrc_register_notification_t param;
323 
324     ALOGI("%s: sBluetoothAvrcpInterface: %p", __FUNCTION__, sBluetoothAvrcpInterface);
325     if (!sBluetoothAvrcpInterface) return JNI_FALSE;
326 
327     param.play_status = (btrc_play_status_t)playStatus;
328     if ((status = sBluetoothAvrcpInterface->register_notification_rsp(BTRC_EVT_PLAY_STATUS_CHANGED,
329                   (btrc_notification_type_t)type, &param)) != BT_STATUS_SUCCESS) {
330         ALOGE("Failed register_notification_rsp play status, status: %d", status);
331     }
332 
333     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
334 }
335 
registerNotificationRspTrackChangeNative(JNIEnv * env,jobject object,jint type,jbyteArray track)336 static jboolean registerNotificationRspTrackChangeNative(JNIEnv *env, jobject object,
337                                                          jint type, jbyteArray track) {
338     bt_status_t status;
339     btrc_register_notification_t param;
340     jbyte *trk;
341     int i;
342 
343     ALOGI("%s: sBluetoothAvrcpInterface: %p", __FUNCTION__, sBluetoothAvrcpInterface);
344     if (!sBluetoothAvrcpInterface) return JNI_FALSE;
345 
346     trk = env->GetByteArrayElements(track, NULL);
347     if (!trk) {
348         jniThrowIOException(env, EINVAL);
349         return JNI_FALSE;
350     }
351 
352     for (i = 0; i < BTRC_UID_SIZE; ++i) {
353       param.track[i] = trk[i];
354     }
355 
356     if ((status = sBluetoothAvrcpInterface->register_notification_rsp(BTRC_EVT_TRACK_CHANGE,
357                   (btrc_notification_type_t)type, &param)) != BT_STATUS_SUCCESS) {
358         ALOGE("Failed register_notification_rsp track change, status: %d", status);
359     }
360 
361     env->ReleaseByteArrayElements(track, trk, 0);
362     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
363 }
364 
registerNotificationRspPlayPosNative(JNIEnv * env,jobject object,jint type,jint playPos)365 static jboolean registerNotificationRspPlayPosNative(JNIEnv *env, jobject object,
366                                                         jint type, jint playPos) {
367     bt_status_t status;
368     btrc_register_notification_t param;
369 
370     ALOGI("%s: sBluetoothAvrcpInterface: %p", __FUNCTION__, sBluetoothAvrcpInterface);
371     if (!sBluetoothAvrcpInterface) return JNI_FALSE;
372 
373     param.song_pos = (uint32_t)playPos;
374     if ((status = sBluetoothAvrcpInterface->register_notification_rsp(BTRC_EVT_PLAY_POS_CHANGED,
375                   (btrc_notification_type_t)type, &param)) != BT_STATUS_SUCCESS) {
376         ALOGE("Failed register_notification_rsp play position, status: %d", status);
377     }
378 
379     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
380 }
381 
setVolumeNative(JNIEnv * env,jobject object,jint volume)382 static jboolean setVolumeNative(JNIEnv *env, jobject object, jint volume) {
383     bt_status_t status;
384 
385     //TODO: delete test code
386     ALOGI("%s: jint: %d, uint8_t: %u", __FUNCTION__, volume, (uint8_t) volume);
387 
388     ALOGI("%s: sBluetoothAvrcpInterface: %p", __FUNCTION__, sBluetoothAvrcpInterface);
389     if (!sBluetoothAvrcpInterface) return JNI_FALSE;
390 
391     if ((status = sBluetoothAvrcpInterface->set_volume((uint8_t)volume)) != BT_STATUS_SUCCESS) {
392         ALOGE("Failed set_volume, status: %d", status);
393     }
394 
395     return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
396 }
397 
398 static JNINativeMethod sMethods[] = {
399     {"classInitNative", "()V", (void *) classInitNative},
400     {"initNative", "()V", (void *) initNative},
401     {"cleanupNative", "()V", (void *) cleanupNative},
402     {"getPlayStatusRspNative", "(III)Z", (void *) getPlayStatusRspNative},
403     {"getElementAttrRspNative", "(B[I[Ljava/lang/String;)Z", (void *) getElementAttrRspNative},
404     {"registerNotificationRspPlayStatusNative", "(II)Z",
405      (void *) registerNotificationRspPlayStatusNative},
406     {"registerNotificationRspTrackChangeNative", "(I[B)Z",
407      (void *) registerNotificationRspTrackChangeNative},
408     {"registerNotificationRspPlayPosNative", "(II)Z",
409      (void *) registerNotificationRspPlayPosNative},
410     {"setVolumeNative", "(I)Z",
411      (void *) setVolumeNative},
412 };
413 
register_com_android_bluetooth_avrcp(JNIEnv * env)414 int register_com_android_bluetooth_avrcp(JNIEnv* env)
415 {
416     return jniRegisterNativeMethods(env, "com/android/bluetooth/avrcp/Avrcp",
417                                     sMethods, NELEM(sMethods));
418 }
419 
420 }
421