blob: 3b8fb7974140d88bb157d60ebd18884ec79f60ad [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"
Doug Kwan75d086e2011-07-16 19:14:18 -070020#include "android_bluetooth_c.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021#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>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053#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) {
Steve Block71f2cf12011-10-20 11:56:00 +010093 ALOGV("%s", __FUNCTION__);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094#ifdef HAVE_BLUETOOTH
95
96 /* in */
97 field_mNativeData = get_field(env, clazz, "mNativeData", "I");
Jaikumar Ganesh2653a1e2011-02-22 10:53:29 -080098 field_mHandsfreeAgRfcommChannel =
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099 get_field(env, clazz, "mHandsfreeAgRfcommChannel", "I");
Jaikumar Ganesh2653a1e2011-02-22 10:53:29 -0800100 field_mHeadsetAgRfcommChannel =
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800101 get_field(env, clazz, "mHeadsetAgRfcommChannel", "I");
102
103 /* out */
Jaikumar Ganesh2653a1e2011-02-22 10:53:29 -0800104 field_mConnectingHeadsetAddress =
105 get_field(env, clazz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106 "mConnectingHeadsetAddress", "Ljava/lang/String;");
Jaikumar Ganesh2653a1e2011-02-22 10:53:29 -0800107 field_mConnectingHeadsetRfcommChannel =
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108 get_field(env, clazz, "mConnectingHeadsetRfcommChannel", "I");
Jaikumar Ganesh2653a1e2011-02-22 10:53:29 -0800109 field_mConnectingHeadsetSocketFd =
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110 get_field(env, clazz, "mConnectingHeadsetSocketFd", "I");
111
Jaikumar Ganesh2653a1e2011-02-22 10:53:29 -0800112 field_mConnectingHandsfreeAddress =
113 get_field(env, clazz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114 "mConnectingHandsfreeAddress", "Ljava/lang/String;");
Jaikumar Ganesh2653a1e2011-02-22 10:53:29 -0800115 field_mConnectingHandsfreeRfcommChannel =
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116 get_field(env, clazz, "mConnectingHandsfreeRfcommChannel", "I");
Jaikumar Ganesh2653a1e2011-02-22 10:53:29 -0800117 field_mConnectingHandsfreeSocketFd =
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800118 get_field(env, clazz, "mConnectingHandsfreeSocketFd", "I");
119
Jaikumar Ganesh2653a1e2011-02-22 10:53:29 -0800120 field_mTimeoutRemainingMs =
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800121 get_field(env, clazz, "mTimeoutRemainingMs", "I");
122#endif
123}
124
125static void initializeNativeDataNative(JNIEnv* env, jobject object) {
Steve Block71f2cf12011-10-20 11:56:00 +0100126 ALOGV("%s", __FUNCTION__);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800127#ifdef HAVE_BLUETOOTH
128 native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t));
129 if (NULL == nat) {
Steve Block3762c312012-01-06 19:20:56 +0000130 ALOGE("%s: out of memory!", __FUNCTION__);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800131 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);
Steve Block71f2cf12011-10-20 11:56:00 +0100141 ALOGV("HF RFCOMM channel = %d.", nat->hf_ag_rfcomm_channel);
142 ALOGV("HS RFCOMM channel = %d.", nat->hs_ag_rfcomm_channel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143
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) {
Steve Block71f2cf12011-10-20 11:56:00 +0100154 ALOGV("%s", __FUNCTION__);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155#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) {
Steve Block3762c312012-01-06 19:20:56 +0000169 ALOGE("Can't get socket flags with fcntl(): %s (%d)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800170 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) {
Steve Block3762c312012-01-06 19:20:56 +0000178 ALOGE("Can't set socket to nonblocking mode with fcntl(): %s (%d)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800179 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) {
Steve Block3762c312012-01-06 19:20:56 +0000201 ALOGE("Error on accept from socket fd %d: %s (%d).",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800202 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
Steve Block6215d3f2012-01-04 20:05:49 +0000218 ALOGI("Successful accept() on AG socket %d: new socket %d, address %s, RFCOMM channel %d",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800219 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 {
Steve Block6215d3f2012-01-04 20:05:49 +0000243 ALOGI("fd = %d, FD_ISSET() = %d",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800244 ag_fd,
245 FD_ISSET(ag_fd, &rset));
246 if (ag_fd >= 0 && !FD_ISSET(ag_fd, &rset)) {
Steve Block3762c312012-01-06 19:20:56 +0000247 ALOGE("WTF???");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800248 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) {
Steve Block71f2cf12011-10-20 11:56:00 +0100259// ALOGV("%s", __FUNCTION__);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800260#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) {
Steve Block6215d3f2012-01-04 20:05:49 +0000268 ALOGI("Setting HF AG server socket to RFCOMM port %d!",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800269 nat->hf_ag_rfcomm_channel);
270 struct timeval tv;
271 int len = sizeof(tv);
Jaikumar Ganesh2653a1e2011-02-22 10:53:29 -0800272 if (getsockopt(nat->hf_ag_rfcomm_channel,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800273 SOL_SOCKET, SO_RCVTIMEO, &tv, &len) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000274 ALOGE("getsockopt(%d, SOL_SOCKET, SO_RCVTIMEO): %s (%d)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800275 nat->hf_ag_rfcomm_channel,
276 strerror(errno),
277 errno);
278 return JNI_FALSE;
279 }
Steve Block6215d3f2012-01-04 20:05:49 +0000280 ALOGI("Current HF AG server socket RCVTIMEO is (%d(s), %d(us))!",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800281 (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);
Jaikumar Ganesh2653a1e2011-02-22 10:53:29 -0800285 if (setsockopt(nat->hf_ag_rfcomm_channel,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800286 SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000287 ALOGE("setsockopt(%d, SOL_SOCKET, SO_RCVTIMEO): %s (%d)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800288 nat->hf_ag_rfcomm_channel,
289 strerror(errno),
290 errno);
291 return JNI_FALSE;
292 }
Steve Block6215d3f2012-01-04 20:05:49 +0000293 ALOGI("Changed HF AG server socket RCVTIMEO to (%d(s), %d(us))!",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800294 (int)tv.tv_sec, (int)tv.tv_usec);
295 }
296
Jaikumar Ganesh2653a1e2011-02-22 10:53:29 -0800297 if (!do_accept(env, object, nat->hf_ag_rfcomm_sock,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800298 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) {
Steve Block6215d3f2012-01-04 20:05:49 +0000313 ALOGI("Setting HF AG server socket to RFCOMM port %d!",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800314 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) {
Steve Block6215d3f2012-01-04 20:05:49 +0000319 ALOGI("Setting HS AG server socket to RFCOMM port %d!",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800320 nat->hs_ag_rfcomm_channel);
321 cnt++;
322 FD_SET(nat->hs_ag_rfcomm_sock, &rset);
323 }
324 if (cnt == 0) {
Steve Block3762c312012-01-06 19:20:56 +0000325 ALOGE("Neither HF nor HS listening sockets are open!");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800326 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 }
Jaikumar Ganesh2653a1e2011-02-22 10:53:29 -0800334 n = select(MAX(nat->hf_ag_rfcomm_sock,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800335 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;
Steve Block6215d3f2012-01-04 20:05:49 +0000342 ALOGI("Remaining time %ldms", (long)remaining);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800343 env->SetIntField(object, field_mTimeoutRemainingMs,
344 remaining);
345 }
346
Steve Block6215d3f2012-01-04 20:05:49 +0000347 ALOGI("listening select() returned %d", n);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800348
349 if (n <= 0) {
350 if (n < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000351 ALOGE("listening select() on RFCOMM sockets: %s (%d)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800352 strerror(errno),
353 errno);
354 }
355 return JNI_FALSE;
356 }
357
Jaikumar Ganesh2653a1e2011-02-22 10:53:29 -0800358 n = on_accept_set_fields(env, object,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359 &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) {
Steve Block6215d3f2012-01-04 20:05:49 +0000375// ALOGI("Setting HF AG server socket %d to RFCOMM port %d!",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800376// 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) {
Steve Block6215d3f2012-01-04 20:05:49 +0000383// ALOGI("Setting HS AG server socket %d to RFCOMM port %d!",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800384// 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) {
Steve Block3762c312012-01-06 19:20:56 +0000391 ALOGE("Neither HF nor HS listening sockets are open!");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800392 return JNI_FALSE;
393 }
394 n = poll(fds, cnt, timeout_ms);
395 if (n <= 0) {
396 if (n < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000397 ALOGE("listening poll() on RFCOMM sockets: %s (%d)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800398 strerror(errno),
399 errno);
400 }
401 else {
402 env->SetIntField(object, field_mTimeoutRemainingMs, 0);
Steve Block6215d3f2012-01-04 20:05:49 +0000403// ALOGI("listening poll() on RFCOMM socket timed out");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800404 }
405 return JNI_FALSE;
406 }
407
Steve Block6215d3f2012-01-04 20:05:49 +0000408 //ALOGI("listening poll() on RFCOMM socket returned %d", n);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800409 int err = 0;
410 for (cnt = 0; cnt < (int)(sizeof(fds)/sizeof(fds[0])); cnt++) {
Steve Block6215d3f2012-01-04 20:05:49 +0000411 //ALOGI("Poll on fd %d revent = %d.", fds[cnt].fd, fds[cnt].revents);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800412 if (fds[cnt].fd == nat->hf_ag_rfcomm_sock) {
413 if (fds[cnt].revents & (POLLIN | POLLPRI | POLLOUT)) {
Steve Block6215d3f2012-01-04 20:05:49 +0000414 ALOGI("Accepting HF connection.\n");
Jaikumar Ganesh2653a1e2011-02-22 10:53:29 -0800415 err += do_accept(env, object, fds[cnt].fd,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800416 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)) {
Steve Block6215d3f2012-01-04 20:05:49 +0000424 ALOGI("Accepting HS connection.\n");
Jaikumar Ganesh2653a1e2011-02-22 10:53:29 -0800425 err += do_accept(env, object, fds[cnt].fd,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800426 field_mConnectingHeadsetSocketFd,
427 field_mConnectingHeadsetAddress,
428 field_mConnectingHeadsetRfcommChannel);
429 n--;
430 }
431 }
432 } /* for */
433
434 if (n != 0) {
Steve Block6215d3f2012-01-04 20:05:49 +0000435 ALOGI("Bogus poll(): %d fake pollfd entrie(s)!", n);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800436 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) {
Steve Block71f2cf12011-10-20 11:56:00 +0100448 ALOGV("%s", __FUNCTION__);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800449#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) {
Steve Block3762c312012-01-06 19:20:56 +0000478 ALOGE("Can't create RFCOMM socket");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800479 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
Jaikumar Ganesh14faa3b2011-03-30 14:04:42 -0700488 if (lm && setsockopt(sk, SOL_RFCOMM, RFCOMM_LM, &lm, sizeof(lm)) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000489 ALOGE("Can't set RFCOMM link mode");
Jaikumar Ganesh14faa3b2011-03-30 14:04:42 -0700490 close(sk);
491 return -1;
492 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800493
494 laddr.rc_family = AF_BLUETOOTH;
Doug Kwan75d086e2011-07-16 19:14:18 -0700495 bdaddr_t any = android_bluetooth_bdaddr_any();
496 memcpy(&laddr.rc_bdaddr, &any, sizeof(bdaddr_t));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800497 laddr.rc_channel = channel;
498
Jaikumar Ganesh14faa3b2011-03-30 14:04:42 -0700499 if (bind(sk, (struct sockaddr *)&laddr, sizeof(laddr)) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000500 ALOGE("Can't bind RFCOMM socket");
Jaikumar Ganesh14faa3b2011-03-30 14:04:42 -0700501 close(sk);
502 return -1;
503 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800504
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) {
Steve Block71f2cf12011-10-20 11:56:00 +0100514 ALOGV("%s", __FUNCTION__);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800515#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) {
Steve Block3762c312012-01-06 19:20:56 +0000520 ALOGE("Could not close HF server socket: %s (%d)\n",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800521 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) {
Steve Block3762c312012-01-06 19:20:56 +0000527 ALOGE("Could not close HS server socket: %s (%d)\n",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800528 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 */