blob: 7f87d8028b5ebe8dc5b88453773639bb84424702 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2** Copyright 2006, 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 "BluetoothAudioGateway.cpp"
18
19#include "android_bluetooth_common.h"
20#include "android_runtime/AndroidRuntime.h"
21#include "JNIHelp.h"
22#include "jni.h"
23#include "utils/Log.h"
24#include "utils/misc.h"
25
26#define USE_ACCEPT_DIRECTLY (0)
27#define USE_SELECT (0) /* 1 for select(), 0 for poll(); used only when
28 USE_ACCEPT_DIRECTLY == 0 */
29
30#include <stdio.h>
31#include <string.h>
32#include <stdlib.h>
33#include <errno.h>
34#include <unistd.h>
35#include <fcntl.h>
36#include <sys/socket.h>
37#include <sys/time.h>
38#include <sys/types.h>
39#include <unistd.h>
40#include <fcntl.h>
41#include <sys/uio.h>
42#include <ctype.h>
43
44#if USE_SELECT
45#include <sys/select.h>
46#else
47#include <sys/poll.h>
48#endif
49
50#ifdef HAVE_BLUETOOTH
51#include <bluetooth/bluetooth.h>
52#include <bluetooth/hci.h>
53#include <bluetooth/hci_lib.h>
54#include <bluetooth/rfcomm.h>
55#include <bluetooth/sco.h>
56#endif
57
58namespace android {
59
60#ifdef HAVE_BLUETOOTH
61static jfieldID field_mNativeData;
62 /* in */
63static jfieldID field_mHandsfreeAgRfcommChannel;
64static jfieldID field_mHeadsetAgRfcommChannel;
65 /* out */
66static jfieldID field_mTimeoutRemainingMs; /* out */
67
68static jfieldID field_mConnectingHeadsetAddress;
69static jfieldID field_mConnectingHeadsetRfcommChannel; /* -1 when not connected */
70static jfieldID field_mConnectingHeadsetSocketFd;
71
72static jfieldID field_mConnectingHandsfreeAddress;
73static jfieldID field_mConnectingHandsfreeRfcommChannel; /* -1 when not connected */
74static jfieldID field_mConnectingHandsfreeSocketFd;
75
76
77typedef struct {
78 int hcidev;
79 int hf_ag_rfcomm_channel;
80 int hs_ag_rfcomm_channel;
81 int hf_ag_rfcomm_sock;
82 int hs_ag_rfcomm_sock;
83} native_data_t;
84
85static inline native_data_t * get_native_data(JNIEnv *env, jobject object) {
86 return (native_data_t *)(env->GetIntField(object,
87 field_mNativeData));
88}
89
90static int setup_listening_socket(int dev, int channel);
91#endif
92
93static void classInitNative(JNIEnv* env, jclass clazz) {
94 LOGV(__FUNCTION__);
95#ifdef HAVE_BLUETOOTH
96
97 /* in */
98 field_mNativeData = get_field(env, clazz, "mNativeData", "I");
99 field_mHandsfreeAgRfcommChannel =
100 get_field(env, clazz, "mHandsfreeAgRfcommChannel", "I");
101 field_mHeadsetAgRfcommChannel =
102 get_field(env, clazz, "mHeadsetAgRfcommChannel", "I");
103
104 /* out */
105 field_mConnectingHeadsetAddress =
106 get_field(env, clazz,
107 "mConnectingHeadsetAddress", "Ljava/lang/String;");
108 field_mConnectingHeadsetRfcommChannel =
109 get_field(env, clazz, "mConnectingHeadsetRfcommChannel", "I");
110 field_mConnectingHeadsetSocketFd =
111 get_field(env, clazz, "mConnectingHeadsetSocketFd", "I");
112
113 field_mConnectingHandsfreeAddress =
114 get_field(env, clazz,
115 "mConnectingHandsfreeAddress", "Ljava/lang/String;");
116 field_mConnectingHandsfreeRfcommChannel =
117 get_field(env, clazz, "mConnectingHandsfreeRfcommChannel", "I");
118 field_mConnectingHandsfreeSocketFd =
119 get_field(env, clazz, "mConnectingHandsfreeSocketFd", "I");
120
121 field_mTimeoutRemainingMs =
122 get_field(env, clazz, "mTimeoutRemainingMs", "I");
123#endif
124}
125
126static void initializeNativeDataNative(JNIEnv* env, jobject object) {
127 LOGV(__FUNCTION__);
128#ifdef HAVE_BLUETOOTH
129 native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t));
130 if (NULL == nat) {
131 LOGE("%s: out of memory!", __FUNCTION__);
132 return;
133 }
134
135 nat->hcidev = BLUETOOTH_ADAPTER_HCI_NUM;
136
137 env->SetIntField(object, field_mNativeData, (jint)nat);
138 nat->hf_ag_rfcomm_channel =
139 env->GetIntField(object, field_mHandsfreeAgRfcommChannel);
140 nat->hs_ag_rfcomm_channel =
141 env->GetIntField(object, field_mHeadsetAgRfcommChannel);
142 LOGV("HF RFCOMM channel = %d.", nat->hf_ag_rfcomm_channel);
143 LOGV("HS RFCOMM channel = %d.", nat->hs_ag_rfcomm_channel);
144
145 /* Set the default values of these to -1. */
146 env->SetIntField(object, field_mConnectingHeadsetRfcommChannel, -1);
147 env->SetIntField(object, field_mConnectingHandsfreeRfcommChannel, -1);
148
149 nat->hf_ag_rfcomm_sock = -1;
150 nat->hs_ag_rfcomm_sock = -1;
151#endif
152}
153
154static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
155 LOGV(__FUNCTION__);
156#ifdef HAVE_BLUETOOTH
157 native_data_t *nat = get_native_data(env, object);
158 if (nat) {
159 free(nat);
160 }
161#endif
162}
163
164#ifdef HAVE_BLUETOOTH
165
166#if USE_ACCEPT_DIRECTLY==0
167static int set_nb(int sk, bool nb) {
168 int flags = fcntl(sk, F_GETFL);
169 if (flags < 0) {
170 LOGE("Can't get socket flags with fcntl(): %s (%d)",
171 strerror(errno), errno);
172 close(sk);
173 return -1;
174 }
175 flags &= ~O_NONBLOCK;
176 if (nb) flags |= O_NONBLOCK;
177 int status = fcntl(sk, F_SETFL, flags);
178 if (status < 0) {
179 LOGE("Can't set socket to nonblocking mode with fcntl(): %s (%d)",
180 strerror(errno), errno);
181 close(sk);
182 return -1;
183 }
184 return 0;
185}
186#endif /*USE_ACCEPT_DIRECTLY==0*/
187
188static int do_accept(JNIEnv* env, jobject object, int ag_fd,
189 jfieldID out_fd,
190 jfieldID out_address,
191 jfieldID out_channel) {
192
193#if USE_ACCEPT_DIRECTLY==0
194 if (set_nb(ag_fd, true) < 0)
195 return -1;
196#endif
197
198 struct sockaddr_rc raddr;
199 int alen = sizeof(raddr);
200 int nsk = accept(ag_fd, (struct sockaddr *) &raddr, &alen);
201 if (nsk < 0) {
202 LOGE("Error on accept from socket fd %d: %s (%d).",
203 ag_fd,
204 strerror(errno),
205 errno);
206#if USE_ACCEPT_DIRECTLY==0
207 set_nb(ag_fd, false);
208#endif
209 return -1;
210 }
211
212 env->SetIntField(object, out_fd, nsk);
213 env->SetIntField(object, out_channel, raddr.rc_channel);
214
215 char addr[BTADDR_SIZE];
216 get_bdaddr_as_string(&raddr.rc_bdaddr, addr);
217 env->SetObjectField(object, out_address, env->NewStringUTF(addr));
218
219 LOGI("Successful accept() on AG socket %d: new socket %d, address %s, RFCOMM channel %d",
220 ag_fd,
221 nsk,
222 addr,
223 raddr.rc_channel);
224#if USE_ACCEPT_DIRECTLY==0
225 set_nb(ag_fd, false);
226#endif
227 return 0;
228}
229
230#if USE_SELECT
231static inline int on_accept_set_fields(JNIEnv* env, jobject object,
232 fd_set *rset, int ag_fd,
233 jfieldID out_fd,
234 jfieldID out_address,
235 jfieldID out_channel) {
236
237 env->SetIntField(object, out_channel, -1);
238
239 if (ag_fd >= 0 && FD_ISSET(ag_fd, &rset)) {
240 return do_accept(env, object, ag_fd,
241 out_fd, out_address, out_channel);
242 }
243 else {
244 LOGI("fd = %d, FD_ISSET() = %d",
245 ag_fd,
246 FD_ISSET(ag_fd, &rset));
247 if (ag_fd >= 0 && !FD_ISSET(ag_fd, &rset)) {
248 LOGE("WTF???");
249 return -1;
250 }
251 }
252
253 return 0;
254}
255#endif
256#endif /* HAVE_BLUETOOTH */
257
258static jboolean waitForHandsfreeConnectNative(JNIEnv* env, jobject object,
259 jint timeout_ms) {
260// LOGV(__FUNCTION__);
261#ifdef HAVE_BLUETOOTH
262
263 env->SetIntField(object, field_mTimeoutRemainingMs, timeout_ms);
264
265 int n = 0;
266 native_data_t *nat = get_native_data(env, object);
267#if USE_ACCEPT_DIRECTLY
268 if (nat->hf_ag_rfcomm_channel > 0) {
269 LOGI("Setting HF AG server socket to RFCOMM port %d!",
270 nat->hf_ag_rfcomm_channel);
271 struct timeval tv;
272 int len = sizeof(tv);
273 if (getsockopt(nat->hf_ag_rfcomm_channel,
274 SOL_SOCKET, SO_RCVTIMEO, &tv, &len) < 0) {
275 LOGE("getsockopt(%d, SOL_SOCKET, SO_RCVTIMEO): %s (%d)",
276 nat->hf_ag_rfcomm_channel,
277 strerror(errno),
278 errno);
279 return JNI_FALSE;
280 }
281 LOGI("Current HF AG server socket RCVTIMEO is (%d(s), %d(us))!",
282 (int)tv.tv_sec, (int)tv.tv_usec);
283 if (timeout_ms >= 0) {
284 tv.tv_sec = timeout_ms / 1000;
285 tv.tv_usec = 1000 * (timeout_ms % 1000);
286 if (setsockopt(nat->hf_ag_rfcomm_channel,
287 SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
288 LOGE("setsockopt(%d, SOL_SOCKET, SO_RCVTIMEO): %s (%d)",
289 nat->hf_ag_rfcomm_channel,
290 strerror(errno),
291 errno);
292 return JNI_FALSE;
293 }
294 LOGI("Changed HF AG server socket RCVTIMEO to (%d(s), %d(us))!",
295 (int)tv.tv_sec, (int)tv.tv_usec);
296 }
297
298 if (!do_accept(env, object, nat->hf_ag_rfcomm_sock,
299 field_mConnectingHandsfreeSocketFd,
300 field_mConnectingHandsfreeAddress,
301 field_mConnectingHandsfreeRfcommChannel))
302 {
303 env->SetIntField(object, field_mTimeoutRemainingMs, 0);
304 return JNI_TRUE;
305 }
306 return JNI_FALSE;
307 }
308#else
309#if USE_SELECT
310 fd_set rset;
311 FD_ZERO(&rset);
312 int cnt = 0;
313 if (nat->hf_ag_rfcomm_channel > 0) {
314 LOGI("Setting HF AG server socket to RFCOMM port %d!",
315 nat->hf_ag_rfcomm_channel);
316 cnt++;
317 FD_SET(nat->hf_ag_rfcomm_sock, &rset);
318 }
319 if (nat->hs_ag_rfcomm_channel > 0) {
320 LOGI("Setting HS AG server socket to RFCOMM port %d!",
321 nat->hs_ag_rfcomm_channel);
322 cnt++;
323 FD_SET(nat->hs_ag_rfcomm_sock, &rset);
324 }
325 if (cnt == 0) {
326 LOGE("Neither HF nor HS listening sockets are open!");
327 return JNI_FALSE;
328 }
329
330 struct timeval to;
331 if (timeout_ms >= 0) {
332 to.tv_sec = timeout_ms / 1000;
333 to.tv_usec = 1000 * (timeout_ms % 1000);
334 }
335 n = select(MAX(nat->hf_ag_rfcomm_sock,
336 nat->hs_ag_rfcomm_sock) + 1,
337 &rset,
338 NULL,
339 NULL,
340 (timeout_ms < 0 ? NULL : &to));
341 if (timeout_ms > 0) {
342 jint remaining = to.tv_sec*1000 + to.tv_usec/1000;
343 LOGI("Remaining time %ldms", (long)remaining);
344 env->SetIntField(object, field_mTimeoutRemainingMs,
345 remaining);
346 }
347
348 LOGI("listening select() returned %d", n);
349
350 if (n <= 0) {
351 if (n < 0) {
352 LOGE("listening select() on RFCOMM sockets: %s (%d)",
353 strerror(errno),
354 errno);
355 }
356 return JNI_FALSE;
357 }
358
359 n = on_accept_set_fields(env, object,
360 &rset, nat->hf_ag_rfcomm_sock,
361 field_mConnectingHandsfreeSocketFd,
362 field_mConnectingHandsfreeAddress,
363 field_mConnectingHandsfreeRfcommChannel);
364
365 n += on_accept_set_fields(env, object,
366 &rset, nat->hs_ag_rfcomm_sock,
367 field_mConnectingHeadsetSocketFd,
368 field_mConnectingHeadsetAddress,
369 field_mConnectingHeadsetRfcommChannel);
370
371 return !n ? JNI_TRUE : JNI_FALSE;
372#else
373 struct pollfd fds[2];
374 int cnt = 0;
375 if (nat->hf_ag_rfcomm_channel > 0) {
376// LOGI("Setting HF AG server socket %d to RFCOMM port %d!",
377// nat->hf_ag_rfcomm_sock,
378// nat->hf_ag_rfcomm_channel);
379 fds[cnt].fd = nat->hf_ag_rfcomm_sock;
380 fds[cnt].events = POLLIN | POLLPRI | POLLOUT | POLLERR;
381 cnt++;
382 }
383 if (nat->hs_ag_rfcomm_channel > 0) {
384// LOGI("Setting HS AG server socket %d to RFCOMM port %d!",
385// nat->hs_ag_rfcomm_sock,
386// nat->hs_ag_rfcomm_channel);
387 fds[cnt].fd = nat->hs_ag_rfcomm_sock;
388 fds[cnt].events = POLLIN | POLLPRI | POLLOUT | POLLERR;
389 cnt++;
390 }
391 if (cnt == 0) {
392 LOGE("Neither HF nor HS listening sockets are open!");
393 return JNI_FALSE;
394 }
395 n = poll(fds, cnt, timeout_ms);
396 if (n <= 0) {
397 if (n < 0) {
398 LOGE("listening poll() on RFCOMM sockets: %s (%d)",
399 strerror(errno),
400 errno);
401 }
402 else {
403 env->SetIntField(object, field_mTimeoutRemainingMs, 0);
404// LOGI("listening poll() on RFCOMM socket timed out");
405 }
406 return JNI_FALSE;
407 }
408
409 //LOGI("listening poll() on RFCOMM socket returned %d", n);
410 int err = 0;
411 for (cnt = 0; cnt < (int)(sizeof(fds)/sizeof(fds[0])); cnt++) {
412 //LOGI("Poll on fd %d revent = %d.", fds[cnt].fd, fds[cnt].revents);
413 if (fds[cnt].fd == nat->hf_ag_rfcomm_sock) {
414 if (fds[cnt].revents & (POLLIN | POLLPRI | POLLOUT)) {
415 LOGI("Accepting HF connection.\n");
416 err += do_accept(env, object, fds[cnt].fd,
417 field_mConnectingHandsfreeSocketFd,
418 field_mConnectingHandsfreeAddress,
419 field_mConnectingHandsfreeRfcommChannel);
420 n--;
421 }
422 }
423 else if (fds[cnt].fd == nat->hs_ag_rfcomm_sock) {
424 if (fds[cnt].revents & (POLLIN | POLLPRI | POLLOUT)) {
425 LOGI("Accepting HS connection.\n");
426 err += do_accept(env, object, fds[cnt].fd,
427 field_mConnectingHeadsetSocketFd,
428 field_mConnectingHeadsetAddress,
429 field_mConnectingHeadsetRfcommChannel);
430 n--;
431 }
432 }
433 } /* for */
434
435 if (n != 0) {
436 LOGI("Bogus poll(): %d fake pollfd entrie(s)!", n);
437 return JNI_FALSE;
438 }
439
440 return !err ? JNI_TRUE : JNI_FALSE;
441#endif /* USE_SELECT */
442#endif /* USE_ACCEPT_DIRECTLY */
443#else
444 return JNI_FALSE;
445#endif /* HAVE_BLUETOOTH */
446}
447
448static jboolean setUpListeningSocketsNative(JNIEnv* env, jobject object) {
449 LOGV(__FUNCTION__);
450#ifdef HAVE_BLUETOOTH
451 native_data_t *nat = get_native_data(env, object);
452
453 nat->hf_ag_rfcomm_sock =
454 setup_listening_socket(nat->hcidev, nat->hf_ag_rfcomm_channel);
455 if (nat->hf_ag_rfcomm_sock < 0)
456 return JNI_FALSE;
457
458 nat->hs_ag_rfcomm_sock =
459 setup_listening_socket(nat->hcidev, nat->hs_ag_rfcomm_channel);
460 if (nat->hs_ag_rfcomm_sock < 0) {
461 close(nat->hf_ag_rfcomm_sock);
462 nat->hf_ag_rfcomm_sock = -1;
463 return JNI_FALSE;
464 }
465
466 return JNI_TRUE;
467#else
468 return JNI_FALSE;
469#endif /* HAVE_BLUETOOTH */
470}
471
472#ifdef HAVE_BLUETOOTH
473static int setup_listening_socket(int dev, int channel) {
474 struct sockaddr_rc laddr;
475 int sk, lm;
476
477 sk = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
478 if (sk < 0) {
479 LOGE("Can't create RFCOMM socket");
480 return -1;
481 }
482
483 if (debug_no_encrypt()) {
484 lm = RFCOMM_LM_AUTH;
485 } else {
486 lm = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT;
487 }
488
489 if (lm && setsockopt(sk, SOL_RFCOMM, RFCOMM_LM, &lm, sizeof(lm)) < 0) {
490 LOGE("Can't set RFCOMM link mode");
491 close(sk);
492 return -1;
493 }
494
495 laddr.rc_family = AF_BLUETOOTH;
496 bacpy(&laddr.rc_bdaddr, BDADDR_ANY);
497 laddr.rc_channel = channel;
498
499 if (bind(sk, (struct sockaddr *)&laddr, sizeof(laddr)) < 0) {
500 LOGE("Can't bind RFCOMM socket");
501 close(sk);
502 return -1;
503 }
504
505 listen(sk, 10);
506 return sk;
507}
508#endif /* HAVE_BLUETOOTH */
509
510/*
511 private native void tearDownListeningSocketsNative();
512*/
513static void tearDownListeningSocketsNative(JNIEnv *env, jobject object) {
514 LOGV(__FUNCTION__);
515#ifdef HAVE_BLUETOOTH
516 native_data_t *nat = get_native_data(env, object);
517
518 if (nat->hf_ag_rfcomm_sock > 0) {
519 if (close(nat->hf_ag_rfcomm_sock) < 0) {
520 LOGE("Could not close HF server socket: %s (%d)\n",
521 strerror(errno), errno);
522 }
523 nat->hf_ag_rfcomm_sock = -1;
524 }
525 if (nat->hs_ag_rfcomm_sock > 0) {
526 if (close(nat->hs_ag_rfcomm_sock) < 0) {
527 LOGE("Could not close HS server socket: %s (%d)\n",
528 strerror(errno), errno);
529 }
530 nat->hs_ag_rfcomm_sock = -1;
531 }
532#endif /* HAVE_BLUETOOTH */
533}
534
535static JNINativeMethod sMethods[] = {
536 /* name, signature, funcPtr */
537
538 {"classInitNative", "()V", (void*)classInitNative},
539 {"initializeNativeDataNative", "()V", (void *)initializeNativeDataNative},
540 {"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative},
541
542 {"setUpListeningSocketsNative", "()Z", (void *)setUpListeningSocketsNative},
543 {"tearDownListeningSocketsNative", "()V", (void *)tearDownListeningSocketsNative},
544 {"waitForHandsfreeConnectNative", "(I)Z", (void *)waitForHandsfreeConnectNative},
545};
546
547int register_android_bluetooth_BluetoothAudioGateway(JNIEnv *env) {
548 return AndroidRuntime::registerNativeMethods(env,
549 "android/bluetooth/BluetoothAudioGateway", sMethods,
550 NELEM(sMethods));
551}
552
553} /* namespace android */