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