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