17490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann/*
27490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann *
3b8707600fd45e0cda31654fc7b2932f29b28d1a1Marcel Holtmann *  BlueZ - Bluetooth protocol stack for Linux
47490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann *
59184e2eeb7b97371c6b83b747c8984e2340d2b47Marcel Holtmann *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
67490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann *
77490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann *
87490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann *  This program is free software; you can redistribute it and/or modify
9632a9432774ff3a0c6e556e8f32a565b38890767Marcel Holtmann *  it under the terms of the GNU General Public License as published by
10632a9432774ff3a0c6e556e8f32a565b38890767Marcel Holtmann *  the Free Software Foundation; either version 2 of the License, or
11632a9432774ff3a0c6e556e8f32a565b38890767Marcel Holtmann *  (at your option) any later version.
127490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann *
13632a9432774ff3a0c6e556e8f32a565b38890767Marcel Holtmann *  This program is distributed in the hope that it will be useful,
14632a9432774ff3a0c6e556e8f32a565b38890767Marcel Holtmann *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15632a9432774ff3a0c6e556e8f32a565b38890767Marcel Holtmann *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16632a9432774ff3a0c6e556e8f32a565b38890767Marcel Holtmann *  GNU General Public License for more details.
177490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann *
18632a9432774ff3a0c6e556e8f32a565b38890767Marcel Holtmann *  You should have received a copy of the GNU General Public License
19632a9432774ff3a0c6e556e8f32a565b38890767Marcel Holtmann *  along with this program; if not, write to the Free Software
20632a9432774ff3a0c6e556e8f32a565b38890767Marcel Holtmann *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
217490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann *
227490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann */
237490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
24b8707600fd45e0cda31654fc7b2932f29b28d1a1Marcel Holtmann#ifdef HAVE_CONFIG_H
25b8707600fd45e0cda31654fc7b2932f29b28d1a1Marcel Holtmann#include <config.h>
26b8707600fd45e0cda31654fc7b2932f29b28d1a1Marcel Holtmann#endif
27b8707600fd45e0cda31654fc7b2932f29b28d1a1Marcel Holtmann
287490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann#include <stdio.h>
297490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann#include <errno.h>
307490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann#include <fcntl.h>
317490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann#include <unistd.h>
327490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann#include <stdlib.h>
337490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann#include <signal.h>
347490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann#include <termios.h>
357490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann#include <sys/wait.h>
367490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann#include <sys/time.h>
377490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann#include <sys/ioctl.h>
387490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann#include <sys/socket.h>
397490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
407490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann#include <bluetooth/bluetooth.h>
417490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann#include <bluetooth/hci.h>
427490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann#include <bluetooth/hci_lib.h>
437490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann#include <bluetooth/sco.h>
447490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann#include <bluetooth/rfcomm.h>
457490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
467490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmannstatic volatile int terminate = 0;
477490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
487490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmannstatic void sig_term(int sig) {
497490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	terminate = 1;
507490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann}
517490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
527490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmannstatic int rfcomm_connect(bdaddr_t *src, bdaddr_t *dst, uint8_t channel)
537490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann{
547490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	struct sockaddr_rc addr;
557490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	int s;
567490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
577490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	if ((s = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)) < 0) {
587490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		return -1;
597490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	}
607490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
617490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	memset(&addr, 0, sizeof(addr));
627490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	addr.rc_family = AF_BLUETOOTH;
637490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	bacpy(&addr.rc_bdaddr, src);
647490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	addr.rc_channel = 0;
657490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
667490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		close(s);
677490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		return -1;
687490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	}
697490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
707490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	memset(&addr, 0, sizeof(addr));
717490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	addr.rc_family = AF_BLUETOOTH;
727490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	bacpy(&addr.rc_bdaddr, dst);
737490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	addr.rc_channel = channel;
747490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0 ){
757490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		close(s);
767490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		return -1;
777490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	}
787490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
797490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	return s;
807490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann}
817490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
827490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmannstatic int sco_connect(bdaddr_t *src, bdaddr_t *dst, uint16_t *handle, uint16_t *mtu)
837490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann{
847490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	struct sockaddr_sco addr;
857490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	struct sco_conninfo conn;
867490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	struct sco_options opts;
871f422e5f2b343d35a8c77ce4be16f74b2819b2bfMarcel Holtmann	socklen_t size;
881f422e5f2b343d35a8c77ce4be16f74b2819b2bfMarcel Holtmann	int s;
897490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
907490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	if ((s = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO)) < 0) {
917490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		return -1;
927490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	}
937490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
947490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	memset(&addr, 0, sizeof(addr));
957490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	addr.sco_family = AF_BLUETOOTH;
967490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	bacpy(&addr.sco_bdaddr, src);
97bbda499067067aefc8e642a2784d247ac0331eaeMarcel Holtmann
987490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
997490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		close(s);
1007490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		return -1;
1017490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	}
1027490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
1037490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	memset(&addr, 0, sizeof(addr));
1047490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	addr.sco_family = AF_BLUETOOTH;
1057490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	bacpy(&addr.sco_bdaddr, dst);
106bbda499067067aefc8e642a2784d247ac0331eaeMarcel Holtmann
1077490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0 ){
1087490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		close(s);
1097490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		return -1;
1107490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	}
1117490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
112bbda499067067aefc8e642a2784d247ac0331eaeMarcel Holtmann	memset(&conn, 0, sizeof(conn));
1137490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	size = sizeof(conn);
114bbda499067067aefc8e642a2784d247ac0331eaeMarcel Holtmann
1157490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	if (getsockopt(s, SOL_SCO, SCO_CONNINFO, &conn, &size) < 0) {
1167490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		close(s);
1177490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		return -1;
1187490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	}
1197490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
120bbda499067067aefc8e642a2784d247ac0331eaeMarcel Holtmann	memset(&opts, 0, sizeof(opts));
1217490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	size = sizeof(opts);
122bbda499067067aefc8e642a2784d247ac0331eaeMarcel Holtmann
1237490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	if (getsockopt(s, SOL_SCO, SCO_OPTIONS, &opts, &size) < 0) {
1247490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		close(s);
1257490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		return -1;
1267490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	}
1277490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
1287490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	if (handle)
1297490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		*handle = conn.hci_handle;
1307490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
1317490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	if (mtu)
1327490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		*mtu = opts.mtu;
1337490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
1347490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	return s;
1357490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann}
1367490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
1377490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmannstatic void usage(void)
1387490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann{
1397490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	printf("Usage:\n"
1407490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		"\thstest play   <file> <bdaddr> [channel]\n"
1417490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		"\thstest record <file> <bdaddr> [channel]\n");
1427490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann}
1437490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
1447490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann#define PLAY	1
1457490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann#define RECORD	2
1467490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
1477490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmannint main(int argc, char *argv[])
1487490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann{
1497490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	struct sigaction sa;
1507490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
1517490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	fd_set rfds;
1527490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	struct timeval timeout;
15367f9a013ade0649d032b9b25e694567a089237d1Marcel Holtmann	unsigned char buf[2048], *p;
1547490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	int maxfd, sel, rlen, wlen;
1557490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
1567490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	bdaddr_t local;
1577490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	bdaddr_t bdaddr;
1587490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	uint8_t channel;
1597490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
1607490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	char *filename;
1617490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	mode_t filemode;
1622076574365b22a211b569a4dcc9a4df6f924f41cJohan Hedberg	int mode = 0;
1637490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	int dd, rd, sd, fd;
1647490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	uint16_t sco_handle, sco_mtu, vs;
1657490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
1667490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	switch (argc) {
1677490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	case 4:
1687490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		str2ba(argv[3], &bdaddr);
1697490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		channel = 6;
1707490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		break;
1717490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	case 5:
1727490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		str2ba(argv[3], &bdaddr);
1737490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		channel = atoi(argv[4]);
1747490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		break;
1757490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	default:
1767490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		usage();
1777490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		exit(-1);
1787490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	}
1797490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
1807490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	if (strncmp(argv[1], "play", 4) == 0) {
1817490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		mode = PLAY;
1827490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		filemode = O_RDONLY;
1837490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	} else if (strncmp(argv[1], "rec", 3) == 0) {
1847490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		mode = RECORD;
1857490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		filemode = O_WRONLY | O_CREAT | O_TRUNC;
1867490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	} else {
1877490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		usage();
1887490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		exit(-1);
1897490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	}
1907490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
1917490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	filename = argv[2];
1927490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
1937490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	hci_devba(0, &local);
1947490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	dd = hci_open_dev(0);
1957490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	hci_read_voice_setting(dd, &vs, 1000);
196499f43343f20d5a562ee041d950086df01fb4868Marcel Holtmann	vs = htobs(vs);
1977490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	fprintf(stderr, "Voice setting: 0x%04x\n", vs);
1987490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	close(dd);
199693d345b0cc02c961748aad2074a2ca64934c9f5Marcel Holtmann	if (vs != 0x0060) {
200693d345b0cc02c961748aad2074a2ca64934c9f5Marcel Holtmann		fprintf(stderr, "The voice setting must be 0x0060\n");
2017490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		return -1;
2027490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	}
2037490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
2047490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	if (strcmp(filename, "-") == 0) {
2057490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		switch (mode) {
2067490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		case PLAY:
2077490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann			fd = 0;
2087490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann			break;
2097490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		case RECORD:
2107490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann			fd = 1;
2117490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann			break;
2127490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		default:
2137490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann			return -1;
2147490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		}
2157490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	} else {
2167490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		if ((fd = open(filename, filemode)) < 0) {
2177490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann			perror("Can't open input/output file");
2187490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann			return -1;
2197490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		}
2207490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	}
2217490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
2227490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	memset(&sa, 0, sizeof(sa));
2237490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	sa.sa_flags = SA_NOCLDSTOP;
2247490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	sa.sa_handler = sig_term;
2257490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	sigaction(SIGTERM, &sa, NULL);
2267490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	sigaction(SIGINT,  &sa, NULL);
2277490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
2287490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	sa.sa_handler = SIG_IGN;
2297490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	sigaction(SIGCHLD, &sa, NULL);
2307490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	sigaction(SIGPIPE, &sa, NULL);
2317490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
2327490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	if ((rd = rfcomm_connect(&local, &bdaddr, channel)) < 0) {
2337490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		perror("Can't connect RFCOMM channel");
2347490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		return -1;
2357490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	}
2367490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
2377490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	fprintf(stderr, "RFCOMM channel connected\n");
2387490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
2397490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	if ((sd = sco_connect(&local, &bdaddr, &sco_handle, &sco_mtu)) < 0) {
2407490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		perror("Can't connect SCO audio channel");
2417490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		close(rd);
2427490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		return -1;
2437490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	}
2447490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
2457490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	fprintf(stderr, "SCO audio channel connected (handle %d, mtu %d)\n", sco_handle, sco_mtu);
2467490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
2472076574365b22a211b569a4dcc9a4df6f924f41cJohan Hedberg	if (mode == RECORD) {
2482076574365b22a211b569a4dcc9a4df6f924f41cJohan Hedberg		if (write(rd, "RING\r\n", 6) < 0)
2492076574365b22a211b569a4dcc9a4df6f924f41cJohan Hedberg			return -errno;
2502076574365b22a211b569a4dcc9a4df6f924f41cJohan Hedberg	}
2517490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
2527490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	maxfd = (rd > sd) ? rd : sd;
2537490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
2547490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	while (!terminate) {
2557490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
2567490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		FD_ZERO(&rfds);
2577490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		FD_SET(rd, &rfds);
2587490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		FD_SET(sd, &rfds);
2597490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
2607490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		timeout.tv_sec = 0;
2617490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		timeout.tv_usec = 10000;
2627490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
2637490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		if ((sel = select(maxfd + 1, &rfds, NULL, NULL, &timeout)) > 0) {
2647490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
2657490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann			if (FD_ISSET(rd, &rfds)) {
2667490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann				memset(buf, 0, sizeof(buf));
2677490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann				rlen = read(rd, buf, sizeof(buf));
2687490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann				if (rlen > 0) {
2697490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann					fprintf(stderr, "%s\n", buf);
2707490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann					wlen = write(rd, "OK\r\n", 4);
2717490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann				}
2727490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann			}
2737490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
2747490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann			if (FD_ISSET(sd, &rfds)) {
2757490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann				memset(buf, 0, sizeof(buf));
2767490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann				rlen = read(sd, buf, sizeof(buf));
2777490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann				if (rlen > 0)
2787490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann					switch (mode) {
2797490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann					case PLAY:
2807490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann						rlen = read(fd, buf, rlen);
28167f9a013ade0649d032b9b25e694567a089237d1Marcel Holtmann
2826968c52091ad2f85038e5b2903b61cc78f3d29c9José Antonio Santos Cadenas						wlen = 0;
28367f9a013ade0649d032b9b25e694567a089237d1Marcel Holtmann						p = buf;
28467f9a013ade0649d032b9b25e694567a089237d1Marcel Holtmann						while (rlen > sco_mtu) {
28567f9a013ade0649d032b9b25e694567a089237d1Marcel Holtmann						        wlen += write(sd, p, sco_mtu);
28667f9a013ade0649d032b9b25e694567a089237d1Marcel Holtmann						        rlen -= sco_mtu;
28767f9a013ade0649d032b9b25e694567a089237d1Marcel Holtmann						        p += sco_mtu;
28867f9a013ade0649d032b9b25e694567a089237d1Marcel Holtmann						}
28967f9a013ade0649d032b9b25e694567a089237d1Marcel Holtmann						wlen += write(sd, p, rlen);
2907490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann						break;
2917490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann					case RECORD:
2927490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann						wlen = write(fd, buf, rlen);
2937490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann						break;
2947490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann					default:
2957490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann						break;
2967490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann					}
2977490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann			}
2987490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
2997490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann		}
3007490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
3017490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	}
3027490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
3037490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	close(sd);
3047490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	sleep(5);
3057490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	close(rd);
3067490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
3077490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	close(fd);
3087490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann
3097490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann	return 0;
3107490b6c61bfa0b581ff7a15f6482787973cf7e3fMarcel Holtmann}
311