android_bluetooth_BluetoothAudioGateway.cpp revision 54b6cfa9a9e5b861a9930af873580d6dc20f773c
1/* 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 */ 554