• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@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 
sig_term(int sig)48 static void sig_term(int sig) {
49 	terminate = 1;
50 }
51 
rfcomm_connect(bdaddr_t * src,bdaddr_t * dst,uint8_t channel)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 
sco_connect(bdaddr_t * src,bdaddr_t * dst,uint16_t * handle,uint16_t * mtu)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 
usage(void)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 
main(int argc,char * argv[])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