Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 7 Oct 2008 09:13:13 -0700
From:      "Maksim Yevmenkin" <maksim.yevmenkin@gmail.com>
To:        vova@fbsd.ru
Cc:        freebsd-bluetooth@freebsd.org
Subject:   Re: Bluetooth audio (once again)
Message-ID:  <bb4a86c70810070913g177edac5n14aab1b62cc61f86@mail.gmail.com>
In-Reply-To: <1223106788.4832.25.camel@localhost>
References:  <3a386af20809261420j535680e8pf44453dbf6f84b20@mail.gmail.com> <bb4a86c70809261504v45ffe1a8oaf26670a1032e86c@mail.gmail.com> <1223034512.1842.111.camel@localhost> <bb4a86c70810030945g3d870a1eqacc85233d9698a66@mail.gmail.com> <1223106788.4832.25.camel@localhost>

next in thread | previous in thread | raw e-mail | index | archive | help

[-- Attachment #1 --]
On 10/4/08, Vladimir Grebenschikov <vova@fbsd.ru> wrote:
> В Fri, 03/10/2008 в 09:45 -0700, Maksim Yevmenkin пишет:
>
>
>  > >  > sco sockets support was also added, however 1) sco sockets hook is
>  > >  > *not* connected by default and 2) there are some known problems with
>  > >  > the code. more specifically problems are related to "broken" bluetooth
>  > >  > devices and the way they report sco buffer size/packet count. i happen
>  > >  > to have few of those devices. we need to have a way to handle those
>  > >  > kind of devices nicely.
>  > >
>  > > I have Platronics P590 headset with advanced audio and Nokia headset. I
>  > >  may to check them against our bluetooth stack.
>
>
> I bit strange that I can inquiry and l2ping device, but can't list
>  services:
>
>  # l2ping -a p590
>  0 bytes from p590 seq_no=0 time=1794.348 ms result=0x6
>  0 bytes from p590 seq_no=1 time=2023.401 ms result=0x6
>  0 bytes from p590 seq_no=2 time=1761.475 ms result=0x6
>  ^C
>  # l2control -a p590 Read_Channel_List
>  l2control: Could not bind socket, bdaddr=00:19:7f:1b:de:77: Network is
>  down

please read man page for l2control(8) utility. more specifically,

"
    The l2control utility connects to the *local* device with the specified
     BD_ADDR and attempts to send the specified command.
"

l2control(8) will dump information about open channels as seen by
*local* device. NOT remote. therefor is does not make much sense to
put *remote* bd_addr as parameter. it will never work.

>  Should I do "pairing" somehow ?

generally speaking, yes. usually pairing happens when host (i.e. pc)
is trying to connect to the headset's rfcomm channel. in most cases,
the headset will request authentication. however, if it does not, use
hccontrol(8) write_authentication_enable command on host's device to
force authentication (i.e. paring)

>  > ok.be warned, you will need to write some code for that. its
>  > relatively simple. basically open an rfcomm socket and then open a sco
>  > socket. i can provide examples if you want me to.
>
> Please, send me an example if you have.

attached

thanks,
max

[-- Attachment #2 --]
#include <sys/types.h>
#include <sys/bitstring.h>
#include <sys/endian.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <err.h>
#include <fcntl.h>
#include <netdb.h>
#include <netgraph/bluetooth/include/ng_hci.h>
#include <netgraph/bluetooth/include/ng_l2cap.h>
#include <netgraph/bluetooth/include/ng_btsocket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <bluetooth.h>

static char const * const	atcmd[] =
{
	"AT+VGS=15\n\r",
	"+VGS=15\n\r",
	"AT+VGM=15\n\r",
	"+VGM=15\n\r",
	"\n\rRING\n\r",
};

int
main(int argc, char **argv)
{
	int			n, channel, fd, s0rfcomm, s0sco;
	struct sockaddr_rfcomm	rfcaddr;
	struct sockaddr_sco	scoaddr;
	bdaddr_t		addr;
	fd_set			fds;
	struct timeval		tm;
	char			buf[1024];

	channel = 1;
	memcpy(&addr, NG_HCI_BDADDR_ANY, sizeof(addr));

	while ((n = getopt(argc, argv, "a:c:")) != -1) {
		switch (n) {
		case 'a':
			if (!bt_aton(optarg, &addr)) {
				struct hostent	*he = bt_gethostbyname(optarg);
				if (he == NULL)
					errx(1, "bt_gethostbyname(%s)", optarg);

				memcpy(&addr, he->h_addr, sizeof(addr));
			}
			break;

		case 'c':
			channel = atoi(optarg);
			if (channel <= 0 || channel > 31)
				errx(1, "invalid channel %s", optarg);
			break;

		default:
			errx(1, "invalid option %c", n);
			/* NOT REACHED */
		}
	}

	if (memcmp(&addr, NG_HCI_BDADDR_ANY, sizeof(addr)) == 0)
		errx(1, "invalid bdaddr");
	if (channel <= 0 || channel > 31)
		errx(1, "invalid channel %d", channel);

	fd = open("voice", O_WRONLY|O_CREAT|O_TRUNC, 0644);
	if (fd < 0)
		err(1, "open(fd)");

	s0rfcomm = socket(PF_BLUETOOTH, SOCK_STREAM, BLUETOOTH_PROTO_RFCOMM);
	if (s0rfcomm < 0)
		err(1, "socket(rfcomm)");

	rfcaddr.rfcomm_len = sizeof(rfcaddr);
	rfcaddr.rfcomm_family = AF_BLUETOOTH;
	memcpy(&rfcaddr.rfcomm_bdaddr, NG_HCI_BDADDR_ANY, sizeof(rfcaddr.rfcomm_bdaddr));
	rfcaddr.rfcomm_channel = 0;

	if (bind(s0rfcomm, (struct sockaddr*) &rfcaddr, sizeof(rfcaddr)) < 0)
		err(1, "bind(rfcomm)");

	rfcaddr.rfcomm_len = sizeof(rfcaddr);
	rfcaddr.rfcomm_family = AF_BLUETOOTH;
	memcpy(&rfcaddr.rfcomm_bdaddr, &addr, sizeof(rfcaddr.rfcomm_bdaddr));
        rfcaddr.rfcomm_channel = channel;

	if (connect(s0rfcomm, (struct sockaddr *)&rfcaddr, sizeof(rfcaddr)) < 0)
		err(1, "connect(rfcomm)");

#if 0
	sleep(5);

	channel = 0;

	while (1) {
		FD_ZERO(&fds);
		FD_SET(s0rfcomm, &fds);
		tm.tv_sec = 5;
		tm.tv_usec = 0;

		printf("sending: [%s]", atcmd[channel]);
		n = write(s0rfcomm, atcmd[channel], strlen(atcmd[channel]));
		if (n != strlen(atcmd[channel]))
			errx(1, "write(s0rfcomm) = %d", n);

		n = select(s0rfcomm + 1, &fds, NULL, NULL, &tm);
		if (n < 0)
			err(1, "select()");
		if (n == 0) {
			printf("timeout\n");
			if (++ channel >= sizeof(atcmd)/sizeof(atcmd[0]))
				channel = 0;
			continue;
		}

		if (FD_ISSET(s0rfcomm, &fds)) {
			n = read(s0rfcomm, buf, sizeof(buf));
			if (n < 0)
				err(1, "read(s0rfcomm)");
			if (n == 0)
				errx(1, "read(s0rfcomm). eof");

			printf("got: %*.*s\n", n, n, buf);

			if (strncasecmp(buf, "AT+CKPD=200", 11) == 0) {
				printf("sending: OK\n");
				n = write(s0rfcomm, "\r\nOK\r\n", 6);
				if (n != 6)
					errx(1, "write(s0rfcomm) = %d", n);

				break;
			}

			if (++ channel >= sizeof(atcmd)/sizeof(atcmd[0]))
				channel = 0;
		}
	}
#endif

#if 1
	s0sco = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BLUETOOTH_PROTO_SCO);
	if (s0sco < 0)
		err(1, "socket(sco)");

	n = sizeof(scoaddr);
	if (getsockname(s0rfcomm,(struct sockaddr*)&scoaddr,&n)<0)
		err(1, "getsockname(rfcomm)");

	printf("src bdaddr: %s\n", bt_ntoa(&scoaddr.sco_bdaddr, NULL));

	if (bind(s0sco, (struct sockaddr *) &scoaddr, sizeof(scoaddr)) < 0)
		err(1, "bind(sco)");

	n = sizeof(scoaddr);
	if (getpeername(s0rfcomm,(struct sockaddr*)&scoaddr,&n)<0) 
		err(1, "getpeername(rfcomm)");

	printf("dst bdaddr: %s\n", bt_ntoa(&scoaddr.sco_bdaddr, NULL));

	if (connect(s0sco, (struct sockaddr *) &scoaddr, sizeof(scoaddr)) < 0)
		err(1, "connect(sco)");

	while (1) {
		FD_ZERO(&fds);
		FD_SET(s0rfcomm, &fds);
		FD_SET(s0sco, &fds);
		tm.tv_sec = 5;
		tm.tv_usec = 0;

		n = (s0rfcomm > s0sco)? s0rfcomm + 1 : s0sco + 1;

		n = select(n, &fds, NULL, NULL, &tm);
		if (n < 0)
			err(1, "select()");
		if (n == 0) {
			printf("timeout\n");    
			continue;
		}

		if (FD_ISSET(s0rfcomm, &fds)) {
			n = read(s0rfcomm, buf, sizeof(buf));
			if (n < 0)  
				err(1, "read(s0rfcomm)");
			if (n == 0)
				errx(1, "read(s0rfcomm). eof");

			printf("got: %*.*s\n", n, n, buf);
		}

		if (FD_ISSET(s0sco, &fds)) {
			n = read(s0sco, buf, sizeof(buf));
			if (n < 0)  
				err(1, "read(s0sco)");
			if (n == 0)
				errx(1, "read(s0sco). eof");
	
			write(fd, buf, n);
		}
	}

	close(s0sco);
	close(s0rfcomm);
#endif

	return (0);
}

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?bb4a86c70810070913g177edac5n14aab1b62cc61f86>