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