Home | History | Annotate | Download | only in test
      1 /*
      2  *
      3  *  BlueZ - Bluetooth protocol stack for Linux
      4  *
      5  *  Copyright (C) 2002-2009  Marcel Holtmann <marcel (at) holtmann.org>
      6  *
      7  *
      8  *  This program is free software; you can redistribute it and/or modify
      9  *  it under the terms of the GNU General Public License as published by
     10  *  the Free Software Foundation; either version 2 of the License, or
     11  *  (at your option) any later version.
     12  *
     13  *  This program is distributed in the hope that it will be useful,
     14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16  *  GNU General Public License for more details.
     17  *
     18  *  You should have received a copy of the GNU General Public License
     19  *  along with this program; if not, write to the Free Software
     20  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     21  *
     22  */
     23 
     24 #ifdef HAVE_CONFIG_H
     25 #include <config.h>
     26 #endif
     27 
     28 #include <stdio.h>
     29 #include <errno.h>
     30 #include <fcntl.h>
     31 #include <unistd.h>
     32 #include <stdlib.h>
     33 #include <signal.h>
     34 #include <termios.h>
     35 #include <sys/wait.h>
     36 #include <sys/time.h>
     37 #include <sys/ioctl.h>
     38 #include <sys/socket.h>
     39 
     40 #include <bluetooth/bluetooth.h>
     41 #include <bluetooth/hci.h>
     42 #include <bluetooth/hci_lib.h>
     43 #include <bluetooth/sco.h>
     44 #include <bluetooth/rfcomm.h>
     45 
     46 static volatile int terminate = 0;
     47 
     48 static void sig_term(int sig) {
     49 	terminate = 1;
     50 }
     51 
     52 static int rfcomm_connect(bdaddr_t *src, bdaddr_t *dst, uint8_t channel)
     53 {
     54 	struct sockaddr_rc addr;
     55 	int s;
     56 
     57 	if ((s = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)) < 0) {
     58 		return -1;
     59 	}
     60 
     61 	memset(&addr, 0, sizeof(addr));
     62 	addr.rc_family = AF_BLUETOOTH;
     63 	bacpy(&addr.rc_bdaddr, src);
     64 	addr.rc_channel = 0;
     65 	if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
     66 		close(s);
     67 		return -1;
     68 	}
     69 
     70 	memset(&addr, 0, sizeof(addr));
     71 	addr.rc_family = AF_BLUETOOTH;
     72 	bacpy(&addr.rc_bdaddr, dst);
     73 	addr.rc_channel = channel;
     74 	if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0 ){
     75 		close(s);
     76 		return -1;
     77 	}
     78 
     79 	return s;
     80 }
     81 
     82 static int sco_connect(bdaddr_t *src, bdaddr_t *dst, uint16_t *handle, uint16_t *mtu)
     83 {
     84 	struct sockaddr_sco addr;
     85 	struct sco_conninfo conn;
     86 	struct sco_options opts;
     87 	socklen_t size;
     88 	int s;
     89 
     90 	if ((s = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO)) < 0) {
     91 		return -1;
     92 	}
     93 
     94 	memset(&addr, 0, sizeof(addr));
     95 	addr.sco_family = AF_BLUETOOTH;
     96 	bacpy(&addr.sco_bdaddr, src);
     97 
     98 	if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
     99 		close(s);
    100 		return -1;
    101 	}
    102 
    103 	memset(&addr, 0, sizeof(addr));
    104 	addr.sco_family = AF_BLUETOOTH;
    105 	bacpy(&addr.sco_bdaddr, dst);
    106 
    107 	if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0 ){
    108 		close(s);
    109 		return -1;
    110 	}
    111 
    112 	memset(&conn, 0, sizeof(conn));
    113 	size = sizeof(conn);
    114 
    115 	if (getsockopt(s, SOL_SCO, SCO_CONNINFO, &conn, &size) < 0) {
    116 		close(s);
    117 		return -1;
    118 	}
    119 
    120 	memset(&opts, 0, sizeof(opts));
    121 	size = sizeof(opts);
    122 
    123 	if (getsockopt(s, SOL_SCO, SCO_OPTIONS, &opts, &size) < 0) {
    124 		close(s);
    125 		return -1;
    126 	}
    127 
    128 	if (handle)
    129 		*handle = conn.hci_handle;
    130 
    131 	if (mtu)
    132 		*mtu = opts.mtu;
    133 
    134 	return s;
    135 }
    136 
    137 static void usage(void)
    138 {
    139 	printf("Usage:\n"
    140 		"\thstest play   <file> <bdaddr> [channel]\n"
    141 		"\thstest record <file> <bdaddr> [channel]\n");
    142 }
    143 
    144 #define PLAY	1
    145 #define RECORD	2
    146 
    147 int main(int argc, char *argv[])
    148 {
    149 	struct sigaction sa;
    150 
    151 	fd_set rfds;
    152 	struct timeval timeout;
    153 	unsigned char buf[2048], *p;
    154 	int maxfd, sel, rlen, wlen;
    155 
    156 	bdaddr_t local;
    157 	bdaddr_t bdaddr;
    158 	uint8_t channel;
    159 
    160 	char *filename;
    161 	mode_t filemode;
    162 	int err, mode = 0;
    163 	int dd, rd, sd, fd;
    164 	uint16_t sco_handle, sco_mtu, vs;
    165 
    166 	switch (argc) {
    167 	case 4:
    168 		str2ba(argv[3], &bdaddr);
    169 		channel = 6;
    170 		break;
    171 	case 5:
    172 		str2ba(argv[3], &bdaddr);
    173 		channel = atoi(argv[4]);
    174 		break;
    175 	default:
    176 		usage();
    177 		exit(-1);
    178 	}
    179 
    180 	if (strncmp(argv[1], "play", 4) == 0) {
    181 		mode = PLAY;
    182 		filemode = O_RDONLY;
    183 	} else if (strncmp(argv[1], "rec", 3) == 0) {
    184 		mode = RECORD;
    185 		filemode = O_WRONLY | O_CREAT | O_TRUNC;
    186 	} else {
    187 		usage();
    188 		exit(-1);
    189 	}
    190 
    191 	filename = argv[2];
    192 
    193 	hci_devba(0, &local);
    194 	dd = hci_open_dev(0);
    195 	hci_read_voice_setting(dd, &vs, 1000);
    196 	vs = htobs(vs);
    197 	fprintf(stderr, "Voice setting: 0x%04x\n", vs);
    198 	close(dd);
    199 	if (vs != 0x0060) {
    200 		fprintf(stderr, "The voice setting must be 0x0060\n");
    201 		return -1;
    202 	}
    203 
    204 	if (strcmp(filename, "-") == 0) {
    205 		switch (mode) {
    206 		case PLAY:
    207 			fd = 0;
    208 			break;
    209 		case RECORD:
    210 			fd = 1;
    211 			break;
    212 		default:
    213 			return -1;
    214 		}
    215 	} else {
    216 		if ((fd = open(filename, filemode)) < 0) {
    217 			perror("Can't open input/output file");
    218 			return -1;
    219 		}
    220 	}
    221 
    222 	memset(&sa, 0, sizeof(sa));
    223 	sa.sa_flags = SA_NOCLDSTOP;
    224 	sa.sa_handler = sig_term;
    225 	sigaction(SIGTERM, &sa, NULL);
    226 	sigaction(SIGINT,  &sa, NULL);
    227 
    228 	sa.sa_handler = SIG_IGN;
    229 	sigaction(SIGCHLD, &sa, NULL);
    230 	sigaction(SIGPIPE, &sa, NULL);
    231 
    232 	if ((rd = rfcomm_connect(&local, &bdaddr, channel)) < 0) {
    233 		perror("Can't connect RFCOMM channel");
    234 		return -1;
    235 	}
    236 
    237 	fprintf(stderr, "RFCOMM channel connected\n");
    238 
    239 	if ((sd = sco_connect(&local, &bdaddr, &sco_handle, &sco_mtu)) < 0) {
    240 		perror("Can't connect SCO audio channel");
    241 		close(rd);
    242 		return -1;
    243 	}
    244 
    245 	fprintf(stderr, "SCO audio channel connected (handle %d, mtu %d)\n", sco_handle, sco_mtu);
    246 
    247 	if (mode == RECORD)
    248 		err = write(rd, "RING\r\n", 6);
    249 
    250 	maxfd = (rd > sd) ? rd : sd;
    251 
    252 	while (!terminate) {
    253 
    254 		FD_ZERO(&rfds);
    255 		FD_SET(rd, &rfds);
    256 		FD_SET(sd, &rfds);
    257 
    258 		timeout.tv_sec = 0;
    259 		timeout.tv_usec = 10000;
    260 
    261 		if ((sel = select(maxfd + 1, &rfds, NULL, NULL, &timeout)) > 0) {
    262 
    263 			if (FD_ISSET(rd, &rfds)) {
    264 				memset(buf, 0, sizeof(buf));
    265 				rlen = read(rd, buf, sizeof(buf));
    266 				if (rlen > 0) {
    267 					fprintf(stderr, "%s\n", buf);
    268 					wlen = write(rd, "OK\r\n", 4);
    269 				}
    270 			}
    271 
    272 			if (FD_ISSET(sd, &rfds)) {
    273 				memset(buf, 0, sizeof(buf));
    274 				rlen = read(sd, buf, sizeof(buf));
    275 				if (rlen > 0)
    276 					switch (mode) {
    277 					case PLAY:
    278 						rlen = read(fd, buf, rlen);
    279 
    280 						wlen = 0;
    281 						p = buf;
    282 						while (rlen > sco_mtu) {
    283 						        wlen += write(sd, p, sco_mtu);
    284 						        rlen -= sco_mtu;
    285 						        p += sco_mtu;
    286 						}
    287 						wlen += write(sd, p, rlen);
    288 						break;
    289 					case RECORD:
    290 						wlen = write(fd, buf, rlen);
    291 						break;
    292 					default:
    293 						break;
    294 					}
    295 			}
    296 
    297 		}
    298 
    299 	}
    300 
    301 	close(sd);
    302 	sleep(5);
    303 	close(rd);
    304 
    305 	close(fd);
    306 
    307 	return 0;
    308 }
    309