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