• 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 "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 
checkCallbackThread()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 
bta2dp_connection_state_callback(btav_connection_state_t state,bt_bdaddr_t * bd_addr)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 
bta2dp_audio_state_callback(btav_audio_state_t state,bt_bdaddr_t * bd_addr)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 
classInitNative(JNIEnv * env,jclass clazz)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 
initNative(JNIEnv * env,jobject object)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 
cleanupNative(JNIEnv * env,jobject object)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 
connectA2dpNative(JNIEnv * env,jobject object,jbyteArray address)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 
disconnectA2dpNative(JNIEnv * env,jobject object,jbyteArray address)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 
register_com_android_bluetooth_a2dp(JNIEnv * env)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