Index: btsco.c =================================================================== RCS file: /cvsroot/bluetooth-alsa/btsco/btsco.c,v retrieving revision 1.11 diff -r1.11 btsco.c 66,68d65 < #define NOT_CONNECTED 0 < #define CONNECTED 1 < 77c74 < { --- > { 104c101 < } --- > } 108c105 < { --- > { 153c150 < } --- > } 156c153 < { --- > { 164c161 < } --- > } 167c164 < { --- > { 174c171 < } --- > } 214d210 < 217a214 > int if_type; 221c218 < if (dev < 0) --- > if (dev < 0) 231,232c228,229 < if (snd_hwdep_info_get_iface(hwdep_info) == < SNDRV_HWDEP_IFACE_BT_SCO) { --- > if_type = snd_hwdep_info_get_iface(hwdep_info); > if (if_type == SNDRV_HWDEP_IFACE_BT_SCO || if_type==12) { 301,313c298 < int main(int argc, char *argv[]) < { < int dev; < int card; < < struct sigaction sa; < < fd_set rfds; < //struct timeval timeout; < unsigned char buf[2048]; < //int sel, rlen, wlen; < int rlen, wlen; < --- > struct s_headset { 317,337c302,303 < < //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 volumes[2], last_volumes[2]; < int opdone; < < // 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; < --- > int rfcomm_fd; > int sco_fd; 339,343c305,331 < char hwdep_name[16]; < < /* detect the audio device */ < if (find_hwdep_device(&card, &dev)) { < error("Can't find device. Bail"); --- > int volumes[2]; > int last_volumes[2]; > struct s_headset *next; > }; > > struct s_headset b_headset; > struct s_headset *first = NULL; > > 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\n"); 345a334,361 > fprintf(stderr, "connected SCO channel\n"); > // write(rd, "RING\r\n", 6); > printf ("Setting sco fd\n"); > bt_sco_set_fd (headset->handle, headset->sco_fd); > printf ("Done setting sco fd\n"); > return 1; > } > > struct s_headset *headset_new (void) > { > struct s_headset *headset; > headset = malloc (sizeof(struct s_headset)); > if (headset == NULL) > return NULL; > headset->sco_fd = -1; > headset->rfcomm_fd = -1; > headset->handle = NULL; > headset->last_volumes[0] = 0; > headset->last_volumes[1] = 0; > headset->next = first; > first = headset; > return headset; > } > > int headset_volume_fromcard (struct s_headset *headset) > { > int len; > char line[100]; 347c363,392 < printf("Device is %d:%d\n", card, dev); --- > len = snd_hwdep_read(headset->handle, headset->volumes, sizeof(headset->volumes)); > if (len != sizeof(headset->volumes)) > return 0; > printf ("volume speaker: %d mic: %d\n", headset->volumes[0], headset->volumes[1]); > if (headset->volumes[0] != headset->last_volumes[0]) { > sprintf(line, "+VGS=%d\r", headset->volumes[0]); > write(headset->rfcomm_fd, line, strlen(line)); > headset->last_volumes[0] = headset->last_volumes[0]; > } > if (headset->volumes[1] != headset->last_volumes[1]) { > sprintf(line, "+VGM=%d\r", headset->volumes[1]); > write(headset->rfcomm_fd, line, strlen(line)); > headset->last_volumes[1] = headset->last_volumes[1]; > } > return 1; > } > > int headset_speaker (struct s_headset *headset) > { > fprintf(stderr, "Sending up speaker change %d\n", headset->volumes[0]); > snd_hwdep_write(headset->handle, headset->volumes, sizeof (headset->volumes)); > return 1; > } > > int headset_micro (struct s_headset *headset) > { > fprintf(stderr, "Sending up microphone change %d\n", headset->volumes[1]); > snd_hwdep_write(headset->handle, headset->volumes, sizeof (headset->volumes)); > return 1; > } 349c394,417 < sprintf(hwdep_name, "hw:%i,%i", card, dev); --- > int headset_from_bt (struct s_headset *headset) > { > unsigned char buf[2048]; > int rlen; > int opdone; > > opdone = 0; > rlen = read(headset->rfcomm_fd, buf, sizeof(buf) - 1); > if (rlen <= 0) > return 0; > buf [rlen] = 0; > fprintf(stderr, "recieved %s\n", buf); > if (strstr(buf, "AT+BVRA=" )) opdone = headset_button(headset); > else if (strstr(buf, "AT+CKPD=200")) opdone = headset_button(headset); > else if (strstr(buf, "AT+CHUP" )) opdone = headset_button(headset); > else if (strstr(buf, "AT+CIND=?" )) opdone = headset_button(headset); > else if (sscanf (buf, "AT+VGS=%d", &headset->volumes[0]) == 1) opdone = headset_speaker (headset); > else if (sscanf (buf, "AT+VGM=%d", &headset->volumes[1]) == 1) opdone = headset_micro (headset); > if (opdone == 1) > /* tell them we recieved */ > write(headset->rfcomm_fd, "\r\nOK\r\n", 6); > else write(headset->rfcomm_fd, "\r\nERROR\r\n", 9); > return 1; > } 351,354c419,425 < /* 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; --- > void headset_destroy(struct s_headset *headset) > { > if (headset == NULL) > return; > if (headset->sco_fd != -1) { > bt_sco_set_fd(headset->handle, -1); > close(headset->sco_fd); 357,361c428,436 < if (argc > 3) { < printf("Clearing fd\n"); < bt_sco_set_fd(handle, 1); < return 1; < } --- > sleep(1); > if (headset->rfcomm_fd != -1) > close(headset->rfcomm_fd); > if (headset->handle != NULL) > snd_hwdep_close(headset->handle); > headset->sco_fd = -1; > headset->rfcomm_fd = -1; > headset->handle = NULL; > } 363,376c438,447 < /* find bdaddr */ < switch (argc) { < case 2: < str2ba(argv[1], &bdaddr); < channel = detect_channel(&bdaddr); < break; < case 3: < str2ba(argv[1], &bdaddr); < channel = atoi(argv[2]); < break; < default: < usage(); < exit(-1); < } --- > void cleanup(void) > { > struct s_headset *akt_headset; > akt_headset = first; > while (akt_headset != NULL) { > struct s_headset *next = akt_headset->next; > headset_destroy(akt_headset); > akt_headset = next; > } > } 377a449,452 > int check_bt_voice(int dev) > { > int dd; > uint16_t vs; 379,380c454 < hci_devba(0, &local); < dd = hci_open_dev(0); --- > dd = hci_open_dev(dev); 397a472,532 > return 0; > } > > int main(int argc, char *argv[]) > { > int dev; > int card; > struct sigaction sa; > > int rlen; > int bt_dev = 0; > > struct pollfd pfds[16]; > > int err; > > char hwdep_name[16]; > struct s_headset *akt_headset; > > atexit(cleanup); > > /* detect the audio device */ > if (find_hwdep_device(&card, &dev)) { > error("Can't find device. Bail"); > return 1; > } > printf("Device is %d:%d\n", card, dev); > sprintf(hwdep_name, "hw:%i,%i", card, dev);S > > if (check_bt_voice(bt_dev)) > return -1; > > > /* find bdaddr */ > switch (argc) { > case 2: > akt_headset = headset_new(); > hci_devba(bt_dev, &akt_headset->local); > str2ba(argv[1], &akt_headset->bdaddr); > akt_headset->channel = detect_channel(&akt_headset->bdaddr); > /* open hwdep on audio device */ > if ((err = snd_hwdep_open(&akt_headset->handle, hwdep_name, O_RDWR)) < 0) { > error("btsco open (%i-%i): %s\n", card, dev, snd_strerror(err)); > return -1; > } > break; > case 3: > akt_headset = headset_new(); > hci_devba(bt_dev, &akt_headset->local); > str2ba(argv[1], &akt_headset->bdaddr); > akt_headset->channel = atoi(argv[2]); > /* open hwdep on audio device */ > if ((err = snd_hwdep_open(&akt_headset->handle, hwdep_name, O_RDWR)) < 0) { > error("btsco open (%i-%i): %s\n", card, dev, snd_strerror(err)); > return -1; > } > break; > default: > usage(); > exit(-1); > } 410,435d544 < /* connect rfcomm control channel */ < if ((rd = rfcomm_connect(&local, &bdaddr, channel)) < 0) { < perror("Can't connect RFCOMM channel"); < return -1; < } < < fprintf(stderr, "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; < 437,438d545 < sco_mode = NOT_CONNECTED; < sd = -1; 439a547,572 > short revents; > int nfds; > nfds = 0; > /* set up data polling description */ > for (akt_headset = first; akt_headset != NULL; akt_headset = akt_headset->next) { > if (akt_headset->rfcomm_fd == -1) > { > /* connect rfcomm control channel */ > if ((akt_headset->rfcomm_fd = rfcomm_connect( > &akt_headset->local, > &akt_headset->bdaddr, > akt_headset->channel)) < 0) > fprintf(stderr, "Can't connect RFCOMM channel"); > else fprintf(stderr, "RFCOMM channel %i connected\n", akt_headset->channel); > } > if (akt_headset->rfcomm_fd != -1) > { > pfds[nfds].fd = akt_headset->rfcomm_fd; > pfds[nfds++].events = POLLIN; > } > if (akt_headset->handle != NULL) > { > /* polling data from hwdep interface */ > nfds += snd_hwdep_poll_descriptors(akt_headset->handle, &pfds[nfds], 1); > } > } 441,444c574,579 < opdone = 0; < < if (poll(pfds, nfds, 1000) > 0) { < short revents; --- > if (nfds == 0) { > sleep(3); > continue; > } > if (poll(pfds, nfds, 1000) <= 0) > continue; 446,472c581,586 < /*printf("inner loop\n"); */ < /* Volume polling (sound card) */ < if (!snd_hwdep_poll_descriptors_revents < (handle, &pfds[nfds - 1], 1, &revents) < && revents & POLLIN) { < int len; < < len = < snd_hwdep_read(handle, volumes, < sizeof(volumes)); < if (len == sizeof(volumes)) { < printf < ("speaker volume: %d mic volume: %d\n", < volumes[0], volumes[1]); < if (volumes[0] != last_volumes[0]) { < sprintf(line, "+VGS=%d\r", < volumes[0]); < write(rd, line, strlen(line)); < } < if (volumes[1] != last_volumes[1]) { < sprintf(line, "+VGM=%d\r", < volumes[1]); < write(rd, line, strlen(line)); < } < memcpy(last_volumes, volumes, < sizeof(volumes)); < opdone = 1; --- > for (akt_headset = first; akt_headset != NULL; akt_headset = akt_headset->next) { > int j; > for (j=0; j if (pfds[j].fd == akt_headset->rfcomm_fd) { > if (pfds[j].revents & POLLIN) headset_from_bt (akt_headset); > continue; 474,548c588,599 < } < // 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) { < fprintf(stderr, "recieved %s\n", buf); < /* tell them we recieved */ < wlen = write(rd, "\r\nOK\r\n", 6); < < if (strstr(buf, "AT+BVRA=") < || strstr(buf, "AT+CKPD=200") < || strstr(buf, "AT+CHUP") < || strstr(buf, "AT+CIND=?")) { < /* mini state machine: handle connect/disconnect */ < switch (sco_mode) { < case NOT_CONNECTED: < fprintf(stderr, < "opened hwdep\n"); < /* connect sco stream */ < if ((sd = < sco_connect(&local, < &bdaddr, < &sco_handle, < &sco_mtu)) < < 0) { < < perror < ("Can't connect SCO audio channel\n"); < } else { < fprintf(stderr, < "connected SCO channel\n"); < // write(rd, "RING\r\n", 6); < printf < ("Setting sco fd\n"); < bt_sco_set_fd < (handle, < sd); < < printf < ("Done setting sco fd\n"); < sco_mode = < CONNECTED; < } < < opdone = 1; < break; < case CONNECTED: < /* close bt_sco audio handle */ < bt_sco_set_fd(handle, < -1); < /* disconnect SCO stream */ < close(sd); < fprintf(stderr, < "disconnected SCO channel\n"); < < sco_mode = < NOT_CONNECTED; < < opdone = 1; < break; < } < } < < if (sscanf < (buf, "AT+VGS=%d", < &volumes[0]) == 1) { < fprintf(stderr, < "Sending up speaker change %d\n", < volumes[0]); < snd_hwdep_write(handle, < volumes, < sizeof < (volumes)); < opdone = 1; --- > #ifdef TEST > if (pfds[j].fd == akt_headset->sco_fd) { > /* Just for testing; handled by kernel driver */ > fd_set rfds; > if (0 && FD_ISSET(akt_headset->sco_fd, &rfds)) { > int i; > unsigned char buf[2048]; > memset(buf, 0, sizeof(buf)); > rlen = read(akt_headset->sco_fd, buf, sizeof(buf)); > write(akt_headset->sco_fd, buf, rlen); > i++; > if (i % 15 == 0) printf("rlen: %d\n", rlen); 550,576c601 < if (sscanf < (buf, "AT+VGM=%d", < &volumes[1]) == 1) { < fprintf(stderr, < "Sending up microphone change %d\n", < volumes[1]); < snd_hwdep_write(handle, < volumes, < sizeof < (volumes)); < opdone = 1; < < } < } < } < < /* Just for testing; handled by kernel driver */ < < if (0 && FD_ISSET(sd, &rfds)) { < memset(buf, 0, sizeof(buf)); < rlen = read(sd, buf, sizeof(buf)); < write(sd, buf, rlen); < < i++; < < if (i % 15 == 0) { < printf("rlen: %d\n", rlen); --- > continue; 577a603,606 > #endif > /* Volume polling (sound card) */ > if (!snd_hwdep_poll_descriptors_revents (akt_headset->handle, &pfds[j], 1, &revents) && revents & POLLIN) > headset_volume_fromcard (akt_headset); 580,581d608 < if (!opdone) < sleep(1); 583,595d609 < < if (sco_mode == CONNECTED) { < close(sd); < < bt_sco_set_fd(handle, -1); < < } < < sleep(1); < close(rd); < < snd_hwdep_close(handle); <