📄 btsco.c
字号:
break; } } fclose(cf); return(ret);}int main(int argc, char *argv[]){ int dev; int card; int ret; int fork, clear; struct sigaction sa; //struct timeval timeout; unsigned char buf[2048]; //int sel, rlen, wlen; int rlen, wlen; bdaddr_t local; bdaddr_t bdaddr; uint8_t channel; //char *filename; //mode_t filemode; //int mode = 0; int dd; int rd; // rfcomm handle int sd; //sco handle uint16_t sco_handle, sco_mtu, vs; char line[100]; int last_volumes[2]; int dr_usage, force_sco; // sco_mode is our running mode. 0 => not connect, 1 => connected // see NOT_CONNECTED,CONNECTED :) int sco_mode; struct pollfd pfds[10]; int nfds; int i, err; snd_hwdep_t *handle; char hwdep_name[16]; snd_card_bt_sco_info_t infobuf; struct action *actions; fork = 0; clear = 0; while((i = getopt(argc, argv, "fcvh")) >= 0) { switch(i) { case 'v': verbose++; break; case 'f': fork = 1; break; case 'c': clear = 1; break; case 'h': case '?': case ':': default: usage(); exit((i == 'h')?0:1); } } if(verbose) printf("btsco v0.4\n"); actions = read_actions(); /* detect the audio device */ if (find_hwdep_device(&card, &dev)) { error("Can't find device. Bail"); return 1; } if(verbose) printf("Device is %d:%d\n", card, dev); sprintf(hwdep_name, "hw:%i,%i", card, dev); /* open hwdep on audio device */ if ((err = snd_hwdep_open(&handle, hwdep_name, O_RDWR)) < 0) { error("btsco open (%i-%i): %s\n", card, dev, snd_strerror(err)); return -1; } if (clear) { if(verbose) printf("Clearing fd\n"); bt_sco_set_fd(handle, 1); return 1; } /* find bdaddr */ switch (argc - optind) { case 1: str2ba(argv[optind], &bdaddr); channel = detect_channel(&bdaddr); break; case 2: str2ba(argv[optind], &bdaddr); channel = atoi(argv[optind + 1]); break; default: usage(); exit(-1); } /* check voice settings. in this version we only support mu-law */ hci_devba(0, &local); dd = hci_open_dev(0); hci_read_voice_setting(dd, &vs, 1000); vs = htobs(vs); if(verbose) printf("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) { error("The voice setting must be 0x060\n"); return -1; } /* setup sigterm handler. we must make sure to do a clean disconnect */ 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_ring; sigaction(SIGUSR1, &sa, NULL); sa.sa_handler = sig_hup; sigaction(SIGHUP, &sa, NULL); sa.sa_handler = SIG_IGN; sigaction(SIGCHLD, &sa, NULL); sigaction(SIGPIPE, &sa, NULL); /* connect rfcomm control channel */ if ((rd = rfcomm_connect(&local, &bdaddr, channel)) < 0) { perror("Can't connect RFCOMM channel"); return -1; } if(verbose) printf("RFCOMM channel %i connected\n", channel); i = 0; /* set up data polling description */ nfds = 0; /* polling data from rfcomm */ pfds[nfds].fd = rd; pfds[nfds++].events = POLLIN; // polling data from command line - unused now// pfds[nfds].fd = 0;// pfds[nfds++].events = POLLIN; /* polling data from hwdep interface */ nfds += snd_hwdep_poll_descriptors(handle, &pfds[nfds], 1); last_volumes[0] = last_volumes[1] = 0; snd_hwdep_ioctl(handle, SNDRV_BT_SCO_IOCTL_REQ_INFO, NULL); if(snd_hwdep_read(handle, &infobuf, sizeof(infobuf)) < 0) { perror("read info"); exit(1); } dr_usage = infobuf.playback_count || infobuf.capture_count; force_sco = -1; if (fork) daemon(0, 0); /* we are not yet connected */ sco_mode = NOT_CONNECTED; sd = -1; while (!terminate) { /*printf("outer loop\n"); */ ret = poll(pfds, nfds, -1); if ((ret < 0) && (errno != EINTR)) { perror("poll"); sleep(1); /* Don't steal the CPU in case of non-transient errors. */ } else if (ret > 0) { short revents; /*printf("inner loop\n"); */ /* Volume polling (sound card) */ if (!snd_hwdep_poll_descriptors_revents (handle, &pfds[nfds - 1], 1, &revents)) { if (revents & POLLIN) { int len; len = snd_hwdep_read(handle, &infobuf, sizeof(infobuf)); if (len == sizeof(infobuf)) { if(verbose) printf ("speaker volume: %d mic volume: %d\n", infobuf.mixer_volume[0], infobuf.mixer_volume[1]); if (infobuf.mixer_volume[0] != last_volumes[0]) { sprintf(line, "AT+VGS=%d\r", infobuf.mixer_volume[0]); write(rd, line, strlen(line)); } if (infobuf.mixer_volume[1] != last_volumes[1]) { sprintf(line, "AT+VGM=%d\r", infobuf.mixer_volume[1]); write(rd, line, strlen(line)); } memcpy(last_volumes, infobuf.mixer_volume, sizeof(infobuf.mixer_volume)); dr_usage = infobuf.playback_count || infobuf.capture_count; } } } if ((pfds[0].revents & POLLHUP) || (pfds[0].revents & POLLERR)) { /* RFCOMM channel lost. * For now, exit. */ if(verbose) printf("RFCOMM channel lost\n"); terminate = 1; } // control transmission events for volume and channel control if (pfds[0].revents & POLLIN) { memset(buf, 0, sizeof(buf)); rlen = read(rd, buf, sizeof(buf) - 1); if (rlen > 0) { struct action *cur; if(verbose) printf("recieved %s\n", buf); /* tell them we recieved */ wlen = write(rd, "\r\nOK\r\n", 6); for(cur = actions; cur != NULL; cur = cur->next) { regmatch_t matches[10]; char *cmdbuf, *args; int match; if(regexec(&cur->regex, buf, 10, matches, 0)) continue; cmdbuf = strdup(cur->cmd); if((args = strchr(cmdbuf, ' ')) != NULL) *(args++) = 0; if(!strcmp(cmdbuf, "system")) { char *subst; char *sysbuf; int substl = 0; subst = NULL; sysbuf = strdup(args); for(i = 0; sysbuf[i]; i++) { if((sysbuf[i] == '\\') && (sysbuf[i + 1] >= '0') && (sysbuf[i + 1] <= '9')) { match = sysbuf[i + 1] - '0'; if(matches[match].rm_so == -1) continue; substl = matches[match].rm_eo - matches[match].rm_so; subst = memcpy(malloc(substl), buf + matches[match].rm_so, substl); } if((sysbuf[i] == '\\') && (sysbuf[i + 1] == 'p')) { subst = malloc(11); /* For potentially 32-bit PIDs */ substl = snprintf(subst, 11, "%i", getpid()); } if(subst != NULL) { sysbuf = realloc(sysbuf, strlen(sysbuf) + substl - 1); memmove(sysbuf + i + substl, sysbuf + i + 2, strlen(sysbuf) - i - 1); memmove(sysbuf + i, subst, substl); free(subst); subst = NULL; i += substl - 1; } } if(verbose) printf("running %s\n", sysbuf); system(sysbuf); free(sysbuf); } else if(!strcmp(cmdbuf, "sco-toggle")) { int target; char *p; target = 1; p = NULL; if(args != NULL) { if((p = strchr(args, ' ')) != NULL) *(p++) = 0; if(!strcmp(args, "on")) target = 1; else if(!strcmp(args, "off")) target = 0; else if(!strcmp(args, "none")) target = -1; } if(force_sco == target) { force_sco = -1; if(p != NULL) { if(!strcmp(p, "on")) force_sco = 1; else if(!strcmp(p, "off")) force_sco = 0; else if(!strcmp(p, "none")) force_sco = -1; } } else { force_sco = target; } } else if(!strcmp(cmdbuf, "sco-force")) { if(args != NULL) { if(!strcmp(args, "on")) force_sco = 1; else if(!strcmp(args, "off")) force_sco = 0; else if(!strcmp(args, "none")) force_sco = -1; } } free(cmdbuf); } if (sscanf (buf, "AT+VGS=%d", &infobuf.mixer_volume[0]) == 1) { if(verbose) printf("Sending up speaker change %d\n", infobuf.mixer_volume[0]); snd_hwdep_write(handle, infobuf.mixer_volume, sizeof (infobuf.mixer_volume)); } if (sscanf (buf, "AT+VGM=%d", &infobuf.mixer_volume[1]) == 1) { if(verbose) printf("Sending up microphone change %d\n", infobuf.mixer_volume[1]); snd_hwdep_write(handle, infobuf.mixer_volume, sizeof (infobuf.mixer_volume)); } } } } if(((dr_usage && (force_sco != 0)) || (force_sco == 1)) && (sco_mode == NOT_CONNECTED)) { if(verbose) printf("driver is in use\n"); /* connect sco stream */ if ((sd = sco_connect(&local, &bdaddr, &sco_handle, &sco_mtu)) < 0) { perror ("Can't connect SCO audio channel\n"); } else { if(verbose) printf("connected SCO channel\n"); bt_sco_set_fd (handle, sd); if(verbose) printf ("Done setting sco fd\n"); sco_mode = CONNECTED; } } if(((!dr_usage && (force_sco != 1)) || (force_sco == 0)) && (sco_mode == CONNECTED)) { if(verbose) printf("driver is not in use\n"); /* close bt_sco audio handle */ bt_sco_set_fd(handle, -1); /* disconnect SCO stream */ close(sd); if(verbose) printf("disconnected SCO channel\n"); sco_mode = NOT_CONNECTED; } if (ring) { write(rd, "\r\nRING\r\n", 8); ring = 0; } if (hupped) { free_actions(actions); actions = read_actions(); hupped = 0; } } if (sco_mode == CONNECTED) { close(sd); bt_sco_set_fd(handle, -1); } sleep(1); close(rd); snd_hwdep_close(handle); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -