From: "suche.org" <admin@suche.org>
To: bluez-devel@lists.sourceforge.net
Subject: [Bluez-devel] BTsco
Date: Wed, 01 Dec 2004 12:35:03 +0100 [thread overview]
Message-ID: <41ADAC67.10706@suche.org> (raw)
In-Reply-To: <200412011224.29191.mail@sebastian-eichner.de>
[-- Attachment #1: Type: text/plain, Size: 229 bytes --]
Hi,
i hope this time it is better c style.
It use now an record with is created for each headset.
Also it now better handle the exit routine.
Capable of multiple headsets.
Why libm, libdl and libpthread are linked ?
Cu Thomas
[-- Attachment #2: btsco.c --]
[-- Type: text/plain, Size: 15093 bytes --]
/*
* Userspace management of snd-bt-sco
*
* Copyright (c) 2003 by Jonathan Paisley <jp@dcs.gla.ac.uk>
*
* Daemon enhancements (c) 2004 by Lars Grunewaldt <lgw@dark-reality.de>
*
* Based on sb16_csp/cspctl.c and hstest.c from bluez-utils/test.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <getopt.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
#include <errno.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/poll.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
#include <bluetooth/sco.h>
#include <bluetooth/rfcomm.h>
#include <bluetooth/sdp.h>
#include <bluetooth/sdp_lib.h>
#include <alsa/asoundlib.h>
#define SNDRV_BT_SCO_IOCTL_SET_SCO_SOCKET _IOW ('H', 0x10, int)
#ifndef SND_HWDEP_IFACE_EMUX_WAVETABLE
#define SND_HWDEP_IFACE_EMUX_WAVETABLE (SND_HWDEP_IFACE_USX2Y + 1)
#endif
#ifndef SND_HWDEP_IFACE_BLUETOOTH
#define SND_HWDEP_IFACE_BLUETOOTH (SND_HWDEP_IFACE_EMUX_WAVETABLE + 1)
#endif
#ifndef SNDRV_HWDEP_IFACE_BT_SCO
#define SNDRV_HWDEP_IFACE_BT_SCO (SND_HWDEP_IFACE_BLUETOOTH + 1)
#endif
static volatile int terminate = 0;
static void sig_term(int sig)
{
terminate = 1;
}
static int rfcomm_connect(bdaddr_t * src, bdaddr_t * dst, uint8_t channel)
{
struct sockaddr_rc addr;
int s;
if ((s = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)) < 0) {
return -1;
}
memset(&addr, 0, sizeof(addr));
addr.rc_family = AF_BLUETOOTH;
bacpy(&addr.rc_bdaddr, src);
addr.rc_channel = 0;
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
close(s);
return -1;
}
memset(&addr, 0, sizeof(addr));
addr.rc_family = AF_BLUETOOTH;
bacpy(&addr.rc_bdaddr, dst);
addr.rc_channel = channel;
if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
close(s);
return -1;
}
return s;
}
static int sco_connect(bdaddr_t * src, bdaddr_t * dst, uint16_t * handle,
uint16_t * mtu)
{
struct sockaddr_sco addr;
struct sco_conninfo conn;
struct sco_options opts;
int s, size;
if ((s = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO)) < 0) {
return -1;
}
memset(&addr, 0, sizeof(addr));
addr.sco_family = AF_BLUETOOTH;
bacpy(&addr.sco_bdaddr, src);
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
close(s);
return -1;
}
memset(&addr, 0, sizeof(addr));
addr.sco_family = AF_BLUETOOTH;
bacpy(&addr.sco_bdaddr, dst);
if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
close(s);
return -1;
}
size = sizeof(conn);
if (getsockopt(s, SOL_SCO, SCO_CONNINFO, &conn, &size) < 0) {
close(s);
return -1;
}
size = sizeof(opts);
if (getsockopt(s, SOL_SCO, SCO_OPTIONS, &opts, &size) < 0) {
close(s);
return -1;
}
if (handle)
*handle = conn.hci_handle;
if (mtu)
*mtu = opts.mtu;
return s;
}
static void error(const char *fmt, ...)
{
va_list va;
va_start(va, fmt);
fprintf(stderr, "Error: ");
vfprintf(stderr, fmt, va);
fprintf(stderr, "\n");
va_end(va);
}
static int bt_sco_set_fd(snd_hwdep_t * handle, int sco_fd)
{
if (snd_hwdep_ioctl
(handle, SNDRV_BT_SCO_IOCTL_SET_SCO_SOCKET, (void *)sco_fd) < 0) {
error("unable to set fd");
return 1;
}
return 0;
}
int find_hwdep_device(int *cardP, int *devP)
{
snd_ctl_t *ctl_handle;
snd_ctl_card_info_t *card_info;
snd_hwdep_info_t *hwdep_info;
int card;
int dev;
int err;
char card_id[32];
ctl_handle = NULL;
snd_ctl_card_info_alloca(&card_info);
snd_hwdep_info_alloca(&hwdep_info);
for (card = 0; card < 7; card++) {
*cardP = card;
if (ctl_handle) {
snd_ctl_close(ctl_handle);
ctl_handle = NULL;
}
// Get control handle for selected card
sprintf(card_id, "hw:%i", card);
if ((err = snd_ctl_open(&ctl_handle, card_id, 0)) < 0) {
error("control open (%s): %s", card_id,
snd_strerror(err));
return -1;
}
// Read control hardware info from card
if ((err = snd_ctl_card_info(ctl_handle, card_info)) < 0) {
error("control hardware info (%s): %s", card_id,
snd_strerror(err));
continue;
}
//if (strcmp(snd_ctl_card_info_get_driver(card_info),"BT SCO (d)"))
// continue;
dev = -1;
err = 1;
while (1) {
int if_type;
if (snd_ctl_hwdep_next_device(ctl_handle, &dev) < 0)
error("hwdep next device (%s): %s",
card_id, snd_strerror(err));
if (dev < 0)
break;
snd_hwdep_info_set_device(hwdep_info, dev);
if (snd_ctl_hwdep_info(ctl_handle, hwdep_info) < 0) {
if (err != -ENOENT)
error
("control hwdep info (%s): %s",
card_id, snd_strerror(err));
continue;
}
if_type = snd_hwdep_info_get_iface(hwdep_info);
if (if_type == SNDRV_HWDEP_IFACE_BT_SCO || if_type==12) {
snd_ctl_close(ctl_handle);
*devP = dev;
return 0;
}
}
}
if (ctl_handle)
snd_ctl_close(ctl_handle);
return -1;
}
static void usage(void)
{
printf("Usage:\n" "\tbtsco <bdaddr> [channel]\n");
}
int detect_channel(bdaddr_t * bdaddr)
{
uuid_t group;
bdaddr_t interface;
sdp_list_t *attrid, *search, *seq, *next;
uint32_t range = 0x0000ffff;
sdp_session_t *sess;
int channel = 2;
int searchresult;
bacpy(&interface, BDADDR_ANY);
sdp_uuid16_create(&group, 0x1108);
sess = sdp_connect(&interface, bdaddr, SDP_RETRY_IF_BUSY);
if (!sess) {
printf
("Failed to connect to SDP server: %s\nAssuming channel %d\n",
strerror(errno), channel);
return channel;
}
attrid = sdp_list_append(0, &range);
search = sdp_list_append(0, &group);
searchresult =
sdp_service_search_attr_req(sess, search, SDP_ATTR_REQ_RANGE,
attrid, &seq);
sdp_list_free(attrid, 0);
sdp_list_free(search, 0);
if (searchresult) {
printf("Service Search failed: %s\nAssuming channel %d\n",
strerror(errno), channel);
sdp_close(sess);
return channel;
}
for (; seq; seq = next) {
sdp_record_t *rec = (sdp_record_t *) seq->data;
sdp_list_t *list = 0;
if (sdp_get_access_protos(rec, &list) == 0) {
channel = sdp_get_proto_port(list, RFCOMM_UUID);
}
next = seq->next;
free(seq);
sdp_record_free(rec);
}
sdp_close(sess);
return channel;
}
struct s_headset {
bdaddr_t local;
bdaddr_t bdaddr;
uint8_t channel;
int rfcomm_fd;
int sco_fd;
snd_hwdep_t *handle;
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");
return 1;
}
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];
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;
}
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;
}
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);
}
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;
}
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;
}
}
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[])
{
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);
}
/* 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_IGN;
sigaction(SIGCHLD, &sa, NULL);
sigaction(SIGPIPE, &sa, NULL);
/* we are not yet connected */
while (!terminate) {
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);
}
}
/*printf("outer loop\n"); */
if (nfds == 0) {
sleep(3);
continue;
}
if (poll(pfds, nfds, 1000) <= 0)
continue;
for (akt_headset = first; akt_headset != NULL; akt_headset = akt_headset->next) {
int j;
for (j=0; j<nfds; j++) {
if (pfds[j].fd == akt_headset->rfcomm_fd) {
if (pfds[j].revents & POLLIN) headset_from_bt (akt_headset);
continue;
}
#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);
}
continue;
}
#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);
}
}
}
return 0;
}
[-- Attachment #3: btsco.c.diff --]
[-- Type: text/plain, Size: 14613 bytes --]
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<nfds; 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);
<
next prev parent reply other threads:[~2004-12-01 11:35 UTC|newest]
Thread overview: 26+ messages / expand[flat|nested] mbox.gz Atom feed top
2004-12-01 7:39 [Bluez-devel] A2DP working :-) , voice not :-( Sebastian Eichner
2004-12-01 7:54 ` Marcel Holtmann
2004-12-01 8:07 ` Sebastian Eichner
2004-12-01 8:31 ` Marcel Holtmann
2004-12-01 8:43 ` Sebastian Eichner
2004-12-01 9:43 ` Marcel Holtmann
2004-12-01 11:24 ` Sebastian Eichner
2004-12-01 11:31 ` Marcel Holtmann
2004-12-01 16:33 ` Sebastian Eichner
2004-12-01 11:35 ` suche.org [this message]
2004-12-01 11:41 ` [Bluez-devel] BTsco Marcel Holtmann
2004-12-01 11:57 ` suche.org
2004-12-01 12:08 ` Marcel Holtmann
2004-12-01 14:20 ` [Bluez-devel] btsco2 Thomas Lußnig
2004-12-01 17:58 ` Brad Midgley
2004-12-01 20:22 ` Domain Admin
2004-12-01 21:32 ` Brad Midgley
2004-12-01 21:51 ` Bluetooth
2004-12-01 23:54 ` Lars Grunewaldt
-- strict thread matches above, loose matches on Subject: below --
2005-01-31 23:01 [Bluez-devel] btsco Dave Henriksen
2005-01-31 22:09 ` Marcel Holtmann
2005-01-31 23:36 ` Dave Henriksen
2005-01-31 22:56 ` Marcel Holtmann
2005-01-31 23:04 ` Lars Grunewaldt
2005-02-01 0:23 ` Dave Henriksen
2005-01-31 23:34 ` Marcel Holtmann
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=41ADAC67.10706@suche.org \
--to=admin@suche.org \
--cc=bluez-devel@lists.sourceforge.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.