* Re: [Bluez-devel] A2DP sink code finally
@ 2005-04-26 12:34 Mayank Batra
2005-04-27 16:27 ` Brad Midgley
2005-05-01 15:16 ` Henryk Plötz
0 siblings, 2 replies; 15+ messages in thread
From: Mayank Batra @ 2005-04-26 12:34 UTC (permalink / raw)
To: bluez-devel
Henryk,
> Hmm, how do I test that? I can't seem to get my
> audio dongle to connect.
> Is there anything else I've got to do apart from
> | hciconfig hci0 class 0x200404
Don't know whether this is required...?
> | sdptool add A2SNK
> | ./a2snk
> ?
I think this is sufficient.
Are u sure that the a2play code is correct?
Because I've used exactly this code to connect with
BlueSoleil, and the connection takes place very well.
Otherwise, BlueSoleil is a very clumsy sw and it sends
disconnect even if we skip or mix a step.
So, this means that maybe u r making some mistake.
Mayank
________________________________________________________________________
Yahoo! India Matrimony: Find your life partner online
Go to: http://yahoo.shaadi.com/india-matrimony
-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click
_______________________________________________
Bluez-devel mailing list
Bluez-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bluez-devel
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Bluez-devel] A2DP sink code finally
2005-04-26 12:34 [Bluez-devel] A2DP sink code finally Mayank Batra
@ 2005-04-27 16:27 ` Brad Midgley
2005-05-01 15:16 ` Henryk Plötz
1 sibling, 0 replies; 15+ messages in thread
From: Brad Midgley @ 2005-04-27 16:27 UTC (permalink / raw)
To: bluez-devel
Guys,
I updated the docs to reflect the new a2play usage and basic a2snk
operation.
I think the best effort spent on a2play now would be to:
- use the real-time clock for timing
- optionally open and perform ioctls on /dev/dsp to operate directly on it
Both of these should make live streaming tighter.
Timing improvements include both inserting delays and throwing out data
when the link doesn't accept it fast enough (or to take up delay), but
you only need the latter for live streaming.
Brad
-------------------------------------------------------
SF.Net email is sponsored by: Tell us your software development plans!
Take this survey and enter to win a one-year sub to SourceForge.net
Plus IDC's 2005 look-ahead and a copy of this survey
Click here to start! http://www.idcswdc.com/cgi-bin/survey?id=105hix
_______________________________________________
Bluez-devel mailing list
Bluez-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bluez-devel
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Bluez-devel] A2DP sink code finally
2005-04-26 12:34 [Bluez-devel] A2DP sink code finally Mayank Batra
2005-04-27 16:27 ` Brad Midgley
@ 2005-05-01 15:16 ` Henryk Plötz
2005-05-03 13:23 ` Mayank Batra
1 sibling, 1 reply; 15+ messages in thread
From: Henryk Plötz @ 2005-05-01 15:16 UTC (permalink / raw)
To: bluez-devel
[-- Attachment #1: Type: text/plain, Size: 835 bytes --]
Moin,
Am Tue, 26 Apr 2005 13:34:12 +0100 (BST) schrieb Mayank Batra:
> > Hmm, how do I test that? I can't seem to get my
> > audio dongle to connect.
Ah, stupid me. I forgot to enable pairing mode on the audio dongle.
> > Is there anything else I've got to do apart from
> > | hciconfig hci0 class 0x200404
>
> Don't know whether this is required...?
Seems so. After doing
> > | sdptool add A2SNK
> > | ./a2snk
_and_ enabling pairing on the audio dongle nothing happened. But as soon
as I changed my device class the audio dongle started a connection. Now
a2snk stalls after "Sent Stream End Point Discovery Response".
--
Henryk Plötz
Grüße aus Berlin
~~~~~~~ Un-CDs, nein danke! http://www.heise.de/ct/cd-register/ ~~~~~~~
~ Help Microsoft fight software piracy: Give Linux to a friend today! ~
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Bluez-devel] A2DP sink code finally
2005-05-01 15:16 ` Henryk Plötz
@ 2005-05-03 13:23 ` Mayank Batra
0 siblings, 0 replies; 15+ messages in thread
From: Mayank Batra @ 2005-05-03 13:23 UTC (permalink / raw)
To: bluez-devel
Henryk,
> Ah, stupid me. I forgot to enable pairing mode on
> the audio dongle.
Never mind. better late than never.
> > > Is there anything else I've got to do apart from
>
> > > | hciconfig hci0 class 0x200404
> >
> > Don't know whether this is required...?
>
> Seems so. After doing
>
> > > | sdptool add A2SNK
> > > | ./a2snk
>
> _and_ enabling pairing on the audio dongle nothing
> happened. But as soon
> as I changed my device class the audio dongle
> started a connection. Now
> a2snk stalls after "Sent Stream End Point Discovery
> Response".
I suggest you scan the hcidump and see whether avdtp
commands are being exchanged properly. This was the
problem i faced while coding the a2recv. Please refer
to my query mail in which i raised the question of
exchanging the position of packet_type and
message_type.
I interchanged them and it started working.
If i don't, then the sink sends a cont command which
the source rejects and sends a disconnection.
Also, do send me a copy of the dump.
Regards,
Mayank
________________________________________________________________________
Yahoo! India Matrimony: Find your life partner online
Go to: http://yahoo.shaadi.com/india-matrimony
-------------------------------------------------------
This SF.Net email is sponsored by: NEC IT Guy Games.
Get your fingers limbered up and give it your best shot. 4 great events, 4
opportunities to win big! Highest score wins.NEC IT Guy Games. Play to
win an NEC 61 plasma display. Visit http://www.necitguy.com/?r=20
_______________________________________________
Bluez-devel mailing list
Bluez-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bluez-devel
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Bluez-devel] A2DP sink code finally
@ 2005-04-26 12:35 Mayank Batra
2005-04-26 13:10 ` Brad Midgley
0 siblings, 1 reply; 15+ messages in thread
From: Mayank Batra @ 2005-04-26 12:35 UTC (permalink / raw)
To: bluez-devel
Brad,
> I'm not sure anyone has used the dongle yet.
> (Mayank?)
>
Yes I have definitely used dongles (Simple USB Dongle,
I don't know what does an audio dongle mean. I hope
there is not much of a difference)
Mayank
Mayank Batra
Whether you think you can or whether you think you can't, you are right. -Henry Ford.
________________________________________________________________________
Yahoo! India Matrimony: Find your life partner online
Go to: http://yahoo.shaadi.com/india-matrimony
-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click
_______________________________________________
Bluez-devel mailing list
Bluez-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bluez-devel
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Bluez-devel] A2DP sink code finally
2005-04-26 12:35 Mayank Batra
@ 2005-04-26 13:10 ` Brad Midgley
2005-04-26 15:50 ` Marcel Holtmann
0 siblings, 1 reply; 15+ messages in thread
From: Brad Midgley @ 2005-04-26 13:10 UTC (permalink / raw)
To: bluez-devel
Mayank,
The term is overloaded. Henryk is trying to use the little box from
bluetake that runs as an a2dp source. It only has one button on it, so
it has to be able to find the sink using only sdp.
Brad
Mayank Batra wrote:
> Brad,
>
>
>>I'm not sure anyone has used the dongle yet.
>>(Mayank?)
>>
>
>
> Yes I have definitely used dongles (Simple USB Dongle,
> I don't know what does an audio dongle mean. I hope
> there is not much of a difference)
>
> Mayank
>
> Mayank Batra
>
>
> Whether you think you can or whether you think you can't, you are right. -Henry Ford.
>
> ________________________________________________________________________
> Yahoo! India Matrimony: Find your life partner online
> Go to: http://yahoo.shaadi.com/india-matrimony
>
>
> -------------------------------------------------------
> SF email is sponsored by - The IT Product Guide
> Read honest & candid reviews on hundreds of IT Products from real users.
> Discover which products truly live up to the hype. Start reading now.
> http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click
> _______________________________________________
> Bluez-devel mailing list
> Bluez-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/bluez-devel
-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click
_______________________________________________
Bluez-devel mailing list
Bluez-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bluez-devel
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Bluez-devel] A2DP sink code finally
2005-04-26 13:10 ` Brad Midgley
@ 2005-04-26 15:50 ` Marcel Holtmann
2005-04-27 19:08 ` Brad Midgley
0 siblings, 1 reply; 15+ messages in thread
From: Marcel Holtmann @ 2005-04-26 15:50 UTC (permalink / raw)
To: bluez-devel
Hi Brad,
> The term is overloaded. Henryk is trying to use the little box from
> bluetake that runs as an a2dp source. It only has one button on it, so
> it has to be able to find the sink using only sdp.
I tried the box from my Aiptek headphone once and it was not really
working, because I think all GCT devices expect a role switch at some
time.
Regards
Marcel
-------------------------------------------------------
SF.Net email is sponsored by: Tell us your software development plans!
Take this survey and enter to win a one-year sub to SourceForge.net
Plus IDC's 2005 look-ahead and a copy of this survey
Click here to start! http://www.idcswdc.com/cgi-bin/survey?id=105hix
_______________________________________________
Bluez-devel mailing list
Bluez-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bluez-devel
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Bluez-devel] A2DP sink code finally
2005-04-26 15:50 ` Marcel Holtmann
@ 2005-04-27 19:08 ` Brad Midgley
0 siblings, 0 replies; 15+ messages in thread
From: Brad Midgley @ 2005-04-27 19:08 UTC (permalink / raw)
To: bluez-devel
Marcel
>>The term is overloaded. Henryk is trying to use the little box from
>>bluetake that runs as an a2dp source. It only has one button on it, so
>>it has to be able to find the sink using only sdp.
>
>
> I tried the box from my Aiptek headphone once and it was not really
> working, because I think all GCT devices expect a role switch at some
> time.
Forgive my ignorance, but is a role switch something we have to
accommodate in our code, like in a2snk.c or is it just in hcid.conf?
Brad
-------------------------------------------------------
SF.Net email is sponsored by: Tell us your software development plans!
Take this survey and enter to win a one-year sub to SourceForge.net
Plus IDC's 2005 look-ahead and a copy of this survey
Click here to start! http://www.idcswdc.com/cgi-bin/survey?id=105hix
_______________________________________________
Bluez-devel mailing list
Bluez-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bluez-devel
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Bluez-devel] A2DP sink code finally
@ 2005-04-26 12:29 Mayank Batra
0 siblings, 0 replies; 15+ messages in thread
From: Mayank Batra @ 2005-04-26 12:29 UTC (permalink / raw)
To: bluez-devel
Brad,
> I suspect the distortion could be happening if the
> read() gets an sbc
> frame fragment at the end... it would be discarded
> by the decoder if
> that happens.
Well, I did printf()s whenever each sbc frame was
being deoded and it turned out that the no. of sbc
frames being decoded from the a2dp packet were EXACTLY
the no. present in the packet.
If mtu is 676 then there are approx 8 sbc frames, and
exactly 8 were getting decoded.
Also, the sound produced(whatever that was being
produced) was similar to the original music.
Just the fact that it is not exactly same.
It means two things:
1) Either we are not configuring the sound card
properly.
2) Or our SBC decoder is not working properly. Henryk,
what do you say about this possibility. Is it possible
?
Mayank
Mayank Batra
Whether you think you can or whether you think you can't, you are right. -Henry Ford.
________________________________________________________________________
Yahoo! India Matrimony: Find your life partner online
Go to: http://yahoo.shaadi.com/india-matrimony
-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click
_______________________________________________
Bluez-devel mailing list
Bluez-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bluez-devel
^ permalink raw reply [flat|nested] 15+ messages in thread
* [Bluez-devel] A2DP sink code finally
@ 2005-04-24 15:09 Mayank Batra
2005-04-25 3:24 ` Brad Midgley
0 siblings, 1 reply; 15+ messages in thread
From: Mayank Batra @ 2005-04-24 15:09 UTC (permalink / raw)
To: BLUEZ DEVELOPERS LIST; +Cc: Brad Midgley
[-- Attachment #1: Type: text/plain, Size: 504 bytes --]
Hi Brad,
This is the code for the A2DP sink application.
Compilation:
gcc -o a2snk a2snk.c -lbluetooth
Running the application:
./a2snk
Right now the following bugs exist:
1) Poor sound quality.
2) Unclean disconnection.
Help me improve the above areas.
Please add this code to the CVS.
Thanks and Regards,
Mayank
________________________________________________________________________
Yahoo! India Matrimony: Find your life partner online
Go to: http://yahoo.shaadi.com/india-matrimony
[-- Attachment #2: a2snk.c --]
[-- Type: text/plain, Size: 18249 bytes --]
/*
* a2snk.c
* This program functions as an A2DP sink
* (Emulation of an A2DP headset)
* Mayank Batra <mayankbatra@yahoo.co.in>
* Abhinav Mathur <abhinavpmathur@yahoo.com>
*
* 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
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <getopt.h>
#include <signal.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/soundcard.h> //To play the sound on the sound card
#include "sbc/sbc.h"
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
#include <bluetooth/l2cap.h>
#include <bluetooth/sdp.h>
#include <bluetooth/sdp_lib.h>
#include <netinet/in.h>
/* AVDTP structures */
/* packet components */
struct avdtp_header {
//uint8_t packet_type:2;
uint8_t message_type:2;
uint8_t packet_type:2;
uint8_t transaction_label:4;
uint8_t signal_id:6;
uint8_t rfa0:2;
} __attribute__ ((packed));
struct acp_seid_info {
uint8_t rfa0:1;
uint8_t inuse0:1;
uint8_t acp_seid:6;
uint8_t rfa2:3;
uint8_t tsep:1;
uint8_t media_type:4;
} __attribute__ ((packed));
struct sbc_codec_specific_elements {
// a2dp p. 20
uint8_t channel_mode:4;
uint8_t frequency:4;
uint8_t allocation_method:2;
uint8_t subbands:2;
uint8_t block_length:4;
uint8_t min_bitpool;
uint8_t max_bitpool;
} __attribute__ ((packed));
#define MAX_ADDITIONAL_CODEC 0 //Right now only SBC is supported
#define MAX_ADDITIONAL_CODEC_OCTETS (MAX_ADDITIONAL_CODEC*sizeof(struct acp_seid_info))
/* packets */
struct sepd_req {
struct avdtp_header header;
} __attribute__ ((packed));
struct sepd_resp {
struct avdtp_header header;
struct acp_seid_info infos[1 + MAX_ADDITIONAL_CODEC];
} __attribute__ ((packed));
struct getcap_req {
struct avdtp_header header;
uint8_t rfa1:2;
uint8_t acp_seid:6;
} __attribute__ ((packed));
struct getcap_resp {
struct avdtp_header header;
uint8_t serv_cap;
uint8_t serv_cap_len;
uint8_t cap_type;
uint8_t length;
uint8_t media_type;
uint8_t media_codec_type;
struct sbc_codec_specific_elements sbc_elements;
} __attribute__ ((packed));
struct set_config {
struct avdtp_header header;
uint8_t rfa0:2;
uint8_t acp_seid:6;
uint8_t rfa1:2;
uint8_t int_seid:6;
uint8_t serv_cap;
uint8_t serv_cap_len;
uint8_t cap_type;
uint8_t length;
uint8_t media_type;
uint8_t media_codec_type;
struct sbc_codec_specific_elements sbc_elements;
} __attribute__ ((packed));
struct set_config_resp {
struct avdtp_header header;
// only present for an error
uint8_t serv_cat;
uint8_t error_code;
} __attribute__ ((packed));
struct open_stream_cmd {
struct avdtp_header header;
uint8_t rfa0:2;
uint8_t acp_seid:6;
} __attribute__ ((packed));
struct open_stream_rsp {
struct avdtp_header header;
// only present for an error
uint8_t error;
} __attribute__ ((packed));
struct start_stream_cmd {
struct avdtp_header header;
uint8_t rfa0:2;
uint8_t acp_seid:6;
} __attribute__ ((packed));
struct start_stream_rsp {
struct avdtp_header header;
// only present for an error
uint8_t rfa0:2;
uint8_t acp_seid:6;
uint8_t error;
} __attribute__ ((packed));
struct close_stream_cmd {
struct avdtp_header header;
uint8_t rfa0:2;
uint8_t acp_seid:6;
} __attribute__ ((packed));
struct close_stream_rsp {
struct avdtp_header header;
// only present for an error
uint8_t error;
} __attribute__ ((packed));
// this is an rtp, not bluetooth header, so values are big endian
struct media_packet_header {
uint8_t cc:4;
uint8_t x:1;
uint8_t p:1;
uint8_t v:2;
uint8_t pt:7;
uint8_t m:1;
uint16_t sequence_number;
uint32_t timestamp;
uint32_t ssrc;
uint32_t csrc[0];
} __attribute__ ((packed));
struct media_payload_header {
uint8_t frame_count:4;
uint8_t rfa0:1;
uint8_t is_last_fragment:1;
uint8_t is_first_fragment:1;
uint8_t is_fragmented:1;
} __attribute__ ((packed));
// SBC file format header
struct sbc_frame_header {
uint8_t syncword:8; /* Sync word */
uint8_t subbands:1; /* Subbands */
uint8_t allocation_method:1; /* Allocation method */
uint8_t channel_mode:2; /* Channel mode */
uint8_t blocks:2; /* Blocks */
uint8_t sampling_frequency:2; /* Sampling frequency */
uint8_t bitpool:8; /* Bitpool */
uint8_t crc_check:8; /* CRC check */
} __attribute__ ((packed));
//A2DP signal types
#define AVDTP_DISCOVER 1
#define AVDTP_GET_CAPABILITIES 2
#define AVDTP_SET_CONFIGURATION 3
#define AVDTP_OPEN 6
#define AVDTP_START 7
#define AVDTP_CLOSE 8
#define MEDIA_TRANSPORT_CATEGORY 1
#define MEDIA_CODEC 7
#define SBC_MEDIA_CODEC_TYPE 0
#define MPEG12_MEDIA_CODEC_TYPE 1
#define AUDIO_MEDIA_TYPE 0
//Packet Types
#define PACKET_TYPE_SINGLE 0
#define PACKET_TYPE_START 4
#define PACKET_TYPE_CONTINUE 8
#define PACKET_TYPE_END 12
//Message Types
#define MESSAGE_TYPE_COMMAND 0
#define MESSAGE_TYPE_ACCEPT 2
#define MESSAGE_TYPE_REJECT 3
#define BUFS 1024
#define MEDIA_PACKET_HEADER_LENGTH 14
#define NONSPECAUDIO 1
static volatile int terminate = 0;
static int cmdfd;
static struct sbc_frame_header sbc_info;
sbc_t sbc;
int audio_fd;
#define BUF_SIZE 4096
unsigned char audio_buffer[BUF_SIZE];
int speed, channels;
static void sig_term(int sig)
{
terminate = 1;
}
static void usage()
{
fprintf(stderr, "use: ./a2snk\n");
}
int opensound()
{
int format=AFMT_S16_BE,len,i;
char c;
if((audio_fd=open("/dev/dsp",O_WRONLY,0))==-1) {
perror("\nFile open error\n");
exit(1);
}
if(ioctl(audio_fd,SNDCTL_DSP_SETFMT,&format)==-1) {
perror("\nioctl no. 1\n");
exit(1);
}
if(ioctl(audio_fd,SNDCTL_DSP_CHANNELS,&channels)==-1) {
perror("\nioctl no. 2\n");
exit(1);
}
if(ioctl(audio_fd,SNDCTL_DSP_SPEED,&speed)==-1) {
perror("\nioctl no. 3\n");
exit(1);
}
return 1;
}
int closesound()
{
if(close(audio_fd)<0) {
perror("\nUnable to close the sound card");
exit(1);
}
}
static ssize_t __write(int fd,void *buf,size_t count)
{
ssize_t len,pos=0;
while(count>0){
len=write(fd,buf+pos,count);
if(len<=0)
return len;
count -= len;
pos += len;
}
return pos;
}
static void decode(char *stream,int streamlen)
{
int fd, id, pos, framelen;
static int turn = 1;
pos = 0;
framelen = sbc_decode(&sbc, stream, streamlen);
printf("%d Hz, %d channels\n", sbc.rate, sbc.channels);
channels=sbc.channels;
speed=sbc.rate;
if(turn == 1) {
/* Open the sound card only once during the streaming */
opensound();
turn = 0;
}
char c;
while (framelen > 0) {
//dump_packet(sbc.data,sbc.len);
write(audio_fd,sbc.data,sbc.len);
pos += framelen;
framelen = sbc_decode(&sbc, stream + pos, streamlen - pos);
}
}
int sk;
static int do_listen(bdaddr_t *src, unsigned short psm, uint16_t *mtu)
{
struct sockaddr_l2 addr;
struct l2cap_options opts;
int opt;
int nsk;
sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
if (sk < 0) {
fprintf(stderr, "Can't create socket. %s(%d)\n",
strerror(errno), errno);
return -1;
}
memset(&addr, 0, sizeof(addr));
addr.l2_family = AF_BLUETOOTH;
bacpy(&addr.l2_bdaddr, src);
addr.l2_psm=htobs(psm);
if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
fprintf(stderr, "Can't bind socket. %s(%d)\n",
strerror(errno), errno);
return -1;
}
/* Get default options */
opt = sizeof(opts);
if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, &opt) < 0) {
fprintf(stderr, "Can't get default L2CAP options. %s(%d)\n",
strerror(errno), errno);
return -1;
}
/* Set new options */
//opts.omtu = 48;
//opts.imtu = imtu;
if (setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, opt) < 0) {
fprintf(stderr, "Can't set L2CAP options. %s(%d)\n",
strerror(errno), errno);
return -1;
}
if(listen(sk,5)<0) {
fprintf(stderr,"\nCan't listen.%s(%d)\n",strerror(errno),errno);
close(sk);
return -1;
}
socklen_t addrlen;
memset(&addr, 0, sizeof(addr));
addrlen = sizeof(addr);
if ((nsk = accept(sk, (struct sockaddr *) &addr, &addrlen)) < 0)
return -1;
else printf("\nConnected");
opt = sizeof(opts);
if (getsockopt(nsk, SOL_L2CAP, L2CAP_OPTIONS, &opts, &opt) < 0) {
fprintf(stderr, "Can't get L2CAP options. %s(%d)\n",
strerror(errno), errno);
close(nsk);
return -1;
}
fprintf(stderr, "Connected [imtu %d, omtu %d, flush_to %d]\n",
opts.imtu, opts.omtu, opts.flush_to);
if (mtu)
*mtu = opts.omtu;
return nsk;
}
#if 0
static void dump_packet(void *p, int size)
{
uint8_t *c = (uint8_t *) p;
while (size-- > 0)
printf(" %02x\n", *c++);
printf("\n");
}
#endif
static void init_request(struct avdtp_header * header, int request_id)
{
static int transaction = 0;
header->packet_type = PACKET_TYPE_SINGLE;
header->message_type = MESSAGE_TYPE_ACCEPT;
header->transaction_label = transaction;
header->signal_id = request_id;
// clear rfa bits
header->rfa0 = 0;
if(header->signal_id!=AVDTP_OPEN)
transaction = (transaction + 1) & 0xf;
else transaction = (transaction + 2) & 0xf;
}
static int calc_frame_len(struct sbc_frame_header *hdr)
{
int tmp, nrof_subbands, nrof_blocks;
nrof_subbands = (hdr->subbands + 1) * 4;
nrof_blocks = (hdr->blocks + 1) * 4;
switch (hdr->channel_mode) {
case 0x00:
nrof_subbands /= 2;
tmp = nrof_blocks * hdr->bitpool;
break;
case 0x01:
tmp = nrof_blocks * hdr->bitpool * 2;
break;
case 0x02:
tmp = nrof_blocks * hdr->bitpool;
break;
case 0x03:
tmp = nrof_blocks * hdr->bitpool + nrof_subbands;
break;
default:
return 0;
}
return (nrof_subbands + ((tmp + 7) / 8));
}
static int read_header(int fd, struct sbc_frame_header *sbc_info) {
if (read(fd, sbc_info, sizeof(*sbc_info)) < sizeof(*sbc_info)) {
fprintf(stderr, "reached end of file?\n");
return -1;
}
if (sbc_info->syncword != 0x9c) {
printf("out of sync (0x%02x)\n", sbc_info->syncword);
return -1;
}
return calc_frame_len(sbc_info);
}
int main(int argc, char *argv[])
{
struct sigaction sa;
int streamfd;
bdaddr_t src, dst;
unsigned short psm_cmd, psm_stream;
unsigned long flags;
int frame_len;
time_t timestamp;
uint16_t mtu, seq_num;
int fd;
bacpy(&src, BDADDR_ANY);
psm_cmd=25;
cmdfd = do_listen(&src, psm_cmd, NULL);
if (cmdfd < 0) {
fprintf(stderr, "cannot open psm_cmd = %d\n", psm_cmd);
exit(-1);
}
// avdtp discover request
//Reading the discover request
struct sepd_req get_resp;
int size;
size = read(cmdfd, &get_resp, sizeof(get_resp));
if(get_resp.header.signal_id!=AVDTP_DISCOVER) {
fprintf(stderr,"Couldn't get avdtp_discover\n");
close(cmdfd);
exit(-1);
}
else printf("\nGot Stream End Point Discovery Request");
//Writing the discover response
struct sepd_resp send_resp;
//Fill in the values in send_resp
memset(&send_resp,0,sizeof(send_resp));
init_request(&send_resp.header,AVDTP_DISCOVER);
send_resp.infos[0].rfa0=0;
send_resp.infos[0].inuse0=0;
send_resp.infos[0].acp_seid=1;
send_resp.infos[0].rfa2=2;
send_resp.infos[0].tsep=1;
send_resp.infos[0].media_type=0;
if(write(cmdfd,&send_resp,sizeof(send_resp))!=sizeof(send_resp)) {
fprintf(stderr,"\nCould not send discover response\n");
close(cmdfd);
exit(-1);
}
else printf("\nSent Stream End Point Discovery Response\n");
//Now read the get capablities request from the source
struct getcap_req get_req;
memset(&get_req,0,sizeof(get_req));
if(read(cmdfd,&get_req,sizeof(get_req))!=sizeof(get_req) || (get_req.header.signal_id!=AVDTP_GET_CAPABILITIES)) {
fprintf(stderr,"\nDidn't get a get cap req");
}
else printf("\nGot a get capabilities request\n");
//Send a get cap resp
struct getcap_resp cap_resp;
memset(&cap_resp,0,sizeof(cap_resp));
init_request(&cap_resp.header,AVDTP_GET_CAPABILITIES);
//Fill in the values of the structure
cap_resp.serv_cap=MEDIA_TRANSPORT_CATEGORY;
cap_resp.serv_cap_len=0;
cap_resp.cap_type=MEDIA_CODEC;
cap_resp.media_type=AUDIO_MEDIA_TYPE;
cap_resp.length=6;
cap_resp.media_codec_type=SBC_MEDIA_CODEC_TYPE;
cap_resp.sbc_elements.channel_mode=15;
cap_resp.sbc_elements.frequency=15;
cap_resp.sbc_elements.allocation_method=3;
cap_resp.sbc_elements.subbands=3;
cap_resp.sbc_elements.min_bitpool=2;
cap_resp.sbc_elements.max_bitpool=250;
cap_resp.sbc_elements.block_length=15;
if(write(cmdfd,&cap_resp,sizeof(cap_resp))<sizeof(cap_resp)) {
fprintf(stderr,"couldn't reply the caps\n");
}
else printf("\nSent the get capabilities response");
//Now read the set config req
struct set_config s_config;
if(read(cmdfd,&s_config,sizeof(s_config))!=sizeof(s_config) || (s_config.header.signal_id!=AVDTP_SET_CONFIGURATION)) {
fprintf(stderr,"couldn't get a set configurations request\n");
}
else printf("\nGot a set configurations request\n");
//Now send the set config resp
struct set_config_resp s_resp;
//Fill in the values of the structure
memset(&s_resp,0,sizeof(s_resp));
init_request(&s_resp.header,AVDTP_SET_CONFIGURATION);
s_resp.header.signal_id=AVDTP_SET_CONFIGURATION;
s_resp.header.message_type=MESSAGE_TYPE_ACCEPT;
if(write(cmdfd,&s_resp,sizeof(s_resp))!=sizeof(s_resp)) {
fprintf(stderr,"couldn't send set config resp\n");
}
else printf("\nSent a Set configurations response\n");
struct open_stream_cmd open_stream;
memset(&open_stream, 0, sizeof(open_stream));
if ((read(cmdfd, &open_stream, sizeof(open_stream)) != sizeof(open_stream)) || (open_stream.header.signal_id!=AVDTP_OPEN)){
printf("\nDidn't receive an open stream command\n");
return (-1);
}
printf("\nReceived an open stream command\n");
struct open_stream_rsp open_resp;
memset(&open_resp,0,sizeof(open_resp));
init_request(&open_resp.header,AVDTP_OPEN);
open_resp.header.signal_id=AVDTP_OPEN;
open_resp.header.message_type=MESSAGE_TYPE_ACCEPT;
if (write(cmdfd, &open_resp, sizeof(open_resp)) < sizeof(open_resp)) {
fprintf(stderr, "couldn't send open stream response confirm for seid = %d\n", open_stream.acp_seid);
return (-1);
}
printf("\nSent open stream confirm\n");
// open the stream l2cap
mtu = 48;
socklen_t addrlen;
struct sockaddr_l2 addr;
memset(&addr, 0, sizeof(addr));
addrlen = sizeof(addr);
streamfd = accept(sk, (struct sockaddr *) &addr, &addrlen);
if (streamfd < 0) {
fprintf(stderr, "cannot open psm_stream = %d\n", psm_stream);
exit(-1);
}
else printf("\nConnected on the streamfd channel");
// start the stream
struct start_stream_cmd start_stream;
memset(&start_stream, 0, sizeof(start_stream));
//Read the start stream command
if (read(cmdfd, &start_stream, sizeof(start_stream)) != sizeof(start_stream) || (start_stream.header.signal_id!=AVDTP_START)) {
fprintf(stderr, "\nDid not get a start stream command\n");
close(streamfd);
close(cmdfd);
exit(-1);
}
else printf("\nGot a stream-start command\n");
//Give the start stream response
struct start_stream_rsp start_resp;
//Fill in the values of the structure
memset(&start_resp,0,sizeof(start_resp));
init_request(&start_resp.header,AVDTP_START);
if (write(cmdfd, &start_resp, sizeof(start_resp)) < sizeof(start_resp)) {
fprintf(stderr, "Couldn't send start stream command confirm");
close(streamfd);
close(cmdfd);
return (-1);
}
else printf("\nSent start stream confirm\n");
char buf[BUFS];
int psize;
if (mtu > BUFS)
mtu = BUFS;
terminate = 0;
seq_num = 1;
sbc_init(&sbc,SBC_NULL);
struct media_packet_header packet_header;
struct media_payload_header payload_header;
memset(&payload_header, 0, sizeof(payload_header));
int packsize; //Size of the packet that is read
timestamp = 0;
packsize=read(streamfd,buf,1024);
decode(buf+(sizeof(packet_header)+sizeof(payload_header)),(packsize-sizeof(packet_header)-sizeof(payload_header)));
printf("Channels=%d,speed=%d",channels,speed);
struct close_stream_cmd close_stream;
memset(&close_stream,0,sizeof(close_stream));
while (!terminate) {
packsize=read(streamfd, buf,1024);
if(packsize < 0)
break;
printf("\nRead:%d bytes",packsize);
decode(buf+(sizeof(packet_header)+sizeof(payload_header)),(packsize-sizeof(packet_header)-sizeof(payload_header)));
seq_num++;
}
sbc_finish(&sbc);
printf("Received %d packets\n", seq_num);
// signal the stream close
if (read(cmdfd, &close_stream, sizeof(close_stream)) != sizeof(close_stream)) {
fprintf(stderr, "couldn't get close_stream\n");
close(streamfd);
close(cmdfd);
exit(-1);
}
if(close_stream.header.signal_id==AVDTP_CLOSE) {
printf("Got stream-close\n");
struct close_stream_rsp close_resp;
init_request(&close_resp.header,AVDTP_CLOSE);
if (write(cmdfd, &close_resp, sizeof(close_resp)) < sizeof(close_resp)) {
fprintf(stderr, "Couldn't send close_resp confirm \n");
close(streamfd);
close(cmdfd);
return (-1);
}
else printf("Sent close stream confirm\n");
}
else {
printf("\nDidnt get a stream close as expected");
close(streamfd);
close(cmdfd);
exit(-1);
}
closesound();
close(streamfd);
close(cmdfd);
return 0;
}
^ permalink raw reply [flat|nested] 15+ messages in thread* Re: [Bluez-devel] A2DP sink code finally
2005-04-24 15:09 Mayank Batra
@ 2005-04-25 3:24 ` Brad Midgley
2005-04-25 3:58 ` Brad Midgley
` (2 more replies)
0 siblings, 3 replies; 15+ messages in thread
From: Brad Midgley @ 2005-04-25 3:24 UTC (permalink / raw)
To: bluez-devel
Mayank,
Thanks for the submission. I corrected some warnings, disabled unused
functions, and added it to Makefile.am.
We definitely need to do a lot of cleanup (eg now that a2play and a2snk
have so much duplication), but first off we need to see why audio is
being distorted...
Brad
Mayank Batra wrote:
> Hi Brad,
>
> This is the code for the A2DP sink application.
>
> Compilation:
>
> gcc -o a2snk a2snk.c -lbluetooth
>
> Running the application:
>
> ./a2snk
>
> Right now the following bugs exist:
>
> 1) Poor sound quality.
>
> 2) Unclean disconnection.
>
> Help me improve the above areas.
>
> Please add this code to the CVS.
>
> Thanks and Regards,
>
> Mayank
>
> ________________________________________________________________________
> Yahoo! India Matrimony: Find your life partner online
> Go to: http://yahoo.shaadi.com/india-matrimony
>
>
> ------------------------------------------------------------------------
>
> /*
> * a2snk.c
> * This program functions as an A2DP sink
> * (Emulation of an A2DP headset)
> * Mayank Batra <mayankbatra@yahoo.co.in>
> * Abhinav Mathur <abhinavpmathur@yahoo.com>
> *
> * 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
> *
> */
>
> #ifdef HAVE_CONFIG_H
> #include <config.h>
> #endif
>
> #include <stdio.h>
> #include <errno.h>
> #include <fcntl.h>
> #include <unistd.h>
> #include <stdlib.h>
> #include <getopt.h>
> #include <signal.h>
> #include <string.h>
> #include <sys/socket.h>
> #include <sys/stat.h>
> #include <sys/soundcard.h> //To play the sound on the sound card
>
> #include "sbc/sbc.h"
>
> #include <bluetooth/bluetooth.h>
> #include <bluetooth/hci.h>
> #include <bluetooth/hci_lib.h>
> #include <bluetooth/l2cap.h>
> #include <bluetooth/sdp.h>
> #include <bluetooth/sdp_lib.h>
>
> #include <netinet/in.h>
>
> /* AVDTP structures */
>
> /* packet components */
>
> struct avdtp_header {
> //uint8_t packet_type:2;
> uint8_t message_type:2;
> uint8_t packet_type:2;
> uint8_t transaction_label:4;
> uint8_t signal_id:6;
> uint8_t rfa0:2;
> } __attribute__ ((packed));
>
> struct acp_seid_info {
> uint8_t rfa0:1;
> uint8_t inuse0:1;
> uint8_t acp_seid:6;
> uint8_t rfa2:3;
> uint8_t tsep:1;
> uint8_t media_type:4;
> } __attribute__ ((packed));
>
> struct sbc_codec_specific_elements {
> // a2dp p. 20
> uint8_t channel_mode:4;
> uint8_t frequency:4;
> uint8_t allocation_method:2;
> uint8_t subbands:2;
> uint8_t block_length:4;
> uint8_t min_bitpool;
> uint8_t max_bitpool;
> } __attribute__ ((packed));
>
> #define MAX_ADDITIONAL_CODEC 0 //Right now only SBC is supported
> #define MAX_ADDITIONAL_CODEC_OCTETS (MAX_ADDITIONAL_CODEC*sizeof(struct acp_seid_info))
>
> /* packets */
>
> struct sepd_req {
> struct avdtp_header header;
> } __attribute__ ((packed));
>
> struct sepd_resp {
> struct avdtp_header header;
> struct acp_seid_info infos[1 + MAX_ADDITIONAL_CODEC];
> } __attribute__ ((packed));
>
> struct getcap_req {
> struct avdtp_header header;
> uint8_t rfa1:2;
> uint8_t acp_seid:6;
> } __attribute__ ((packed));
>
> struct getcap_resp {
> struct avdtp_header header;
>
> uint8_t serv_cap;
> uint8_t serv_cap_len;
>
> uint8_t cap_type;
> uint8_t length;
> uint8_t media_type;
> uint8_t media_codec_type;
>
> struct sbc_codec_specific_elements sbc_elements;
>
> } __attribute__ ((packed));
>
> struct set_config {
> struct avdtp_header header;
>
> uint8_t rfa0:2;
> uint8_t acp_seid:6;
> uint8_t rfa1:2;
> uint8_t int_seid:6;
>
> uint8_t serv_cap;
> uint8_t serv_cap_len;
>
> uint8_t cap_type;
> uint8_t length;
> uint8_t media_type;
> uint8_t media_codec_type;
>
> struct sbc_codec_specific_elements sbc_elements;
>
> } __attribute__ ((packed));
>
> struct set_config_resp {
> struct avdtp_header header;
>
> // only present for an error
>
> uint8_t serv_cat;
> uint8_t error_code;
> } __attribute__ ((packed));
>
> struct open_stream_cmd {
> struct avdtp_header header;
> uint8_t rfa0:2;
> uint8_t acp_seid:6;
> } __attribute__ ((packed));
>
> struct open_stream_rsp {
> struct avdtp_header header;
>
> // only present for an error
>
> uint8_t error;
> } __attribute__ ((packed));
>
> struct start_stream_cmd {
> struct avdtp_header header;
> uint8_t rfa0:2;
> uint8_t acp_seid:6;
> } __attribute__ ((packed));
>
> struct start_stream_rsp {
> struct avdtp_header header;
>
> // only present for an error
>
> uint8_t rfa0:2;
> uint8_t acp_seid:6;
> uint8_t error;
> } __attribute__ ((packed));
>
> struct close_stream_cmd {
> struct avdtp_header header;
> uint8_t rfa0:2;
> uint8_t acp_seid:6;
> } __attribute__ ((packed));
>
> struct close_stream_rsp {
> struct avdtp_header header;
>
> // only present for an error
>
> uint8_t error;
> } __attribute__ ((packed));
>
> // this is an rtp, not bluetooth header, so values are big endian
> struct media_packet_header {
> uint8_t cc:4;
> uint8_t x:1;
> uint8_t p:1;
> uint8_t v:2;
>
> uint8_t pt:7;
> uint8_t m:1;
>
> uint16_t sequence_number;
> uint32_t timestamp;
> uint32_t ssrc;
> uint32_t csrc[0];
> } __attribute__ ((packed));
>
> struct media_payload_header {
> uint8_t frame_count:4;
> uint8_t rfa0:1;
> uint8_t is_last_fragment:1;
> uint8_t is_first_fragment:1;
> uint8_t is_fragmented:1;
> } __attribute__ ((packed));
>
> // SBC file format header
>
> struct sbc_frame_header {
> uint8_t syncword:8; /* Sync word */
> uint8_t subbands:1; /* Subbands */
> uint8_t allocation_method:1; /* Allocation method */
> uint8_t channel_mode:2; /* Channel mode */
> uint8_t blocks:2; /* Blocks */
> uint8_t sampling_frequency:2; /* Sampling frequency */
> uint8_t bitpool:8; /* Bitpool */
> uint8_t crc_check:8; /* CRC check */
> } __attribute__ ((packed));
>
> //A2DP signal types
> #define AVDTP_DISCOVER 1
> #define AVDTP_GET_CAPABILITIES 2
> #define AVDTP_SET_CONFIGURATION 3
> #define AVDTP_OPEN 6
> #define AVDTP_START 7
> #define AVDTP_CLOSE 8
>
> #define MEDIA_TRANSPORT_CATEGORY 1
> #define MEDIA_CODEC 7
>
> #define SBC_MEDIA_CODEC_TYPE 0
> #define MPEG12_MEDIA_CODEC_TYPE 1
> #define AUDIO_MEDIA_TYPE 0
>
> //Packet Types
> #define PACKET_TYPE_SINGLE 0
> #define PACKET_TYPE_START 4
> #define PACKET_TYPE_CONTINUE 8
> #define PACKET_TYPE_END 12
>
> //Message Types
> #define MESSAGE_TYPE_COMMAND 0
> #define MESSAGE_TYPE_ACCEPT 2
> #define MESSAGE_TYPE_REJECT 3
>
> #define BUFS 1024
>
> #define MEDIA_PACKET_HEADER_LENGTH 14
>
> #define NONSPECAUDIO 1
>
> static volatile int terminate = 0;
> static int cmdfd;
> static struct sbc_frame_header sbc_info;
> sbc_t sbc;
> int audio_fd;
> #define BUF_SIZE 4096
> unsigned char audio_buffer[BUF_SIZE];
> int speed, channels;
>
>
> static void sig_term(int sig)
> {
> terminate = 1;
> }
>
> static void usage()
> {
> fprintf(stderr, "use: ./a2snk\n");
> }
>
> int opensound()
> {
> int format=AFMT_S16_BE,len,i;
> char c;
>
> if((audio_fd=open("/dev/dsp",O_WRONLY,0))==-1) {
> perror("\nFile open error\n");
> exit(1);
> }
> if(ioctl(audio_fd,SNDCTL_DSP_SETFMT,&format)==-1) {
> perror("\nioctl no. 1\n");
> exit(1);
> }
>
> if(ioctl(audio_fd,SNDCTL_DSP_CHANNELS,&channels)==-1) {
> perror("\nioctl no. 2\n");
> exit(1);
> }
>
> if(ioctl(audio_fd,SNDCTL_DSP_SPEED,&speed)==-1) {
> perror("\nioctl no. 3\n");
> exit(1);
> }
>
> return 1;
> }
>
> int closesound()
> {
> if(close(audio_fd)<0) {
> perror("\nUnable to close the sound card");
> exit(1);
> }
> }
>
>
> static ssize_t __write(int fd,void *buf,size_t count)
> {
> ssize_t len,pos=0;
> while(count>0){
> len=write(fd,buf+pos,count);
> if(len<=0)
> return len;
> count -= len;
> pos += len;
> }
> return pos;
> }
>
> static void decode(char *stream,int streamlen)
> {
> int fd, id, pos, framelen;
> static int turn = 1;
> pos = 0;
>
> framelen = sbc_decode(&sbc, stream, streamlen);
>
> printf("%d Hz, %d channels\n", sbc.rate, sbc.channels);
> channels=sbc.channels;
> speed=sbc.rate;
> if(turn == 1) {
> /* Open the sound card only once during the streaming */
> opensound();
> turn = 0;
> }
>
> char c;
> while (framelen > 0) {
> //dump_packet(sbc.data,sbc.len);
> write(audio_fd,sbc.data,sbc.len);
>
> pos += framelen;
>
> framelen = sbc_decode(&sbc, stream + pos, streamlen - pos);
> }
>
> }
>
>
>
> int sk;
> static int do_listen(bdaddr_t *src, unsigned short psm, uint16_t *mtu)
> {
> struct sockaddr_l2 addr;
> struct l2cap_options opts;
>
> int opt;
> int nsk;
>
> sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
> if (sk < 0) {
> fprintf(stderr, "Can't create socket. %s(%d)\n",
> strerror(errno), errno);
> return -1;
> }
>
> memset(&addr, 0, sizeof(addr));
> addr.l2_family = AF_BLUETOOTH;
> bacpy(&addr.l2_bdaddr, src);
> addr.l2_psm=htobs(psm);
> if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
> fprintf(stderr, "Can't bind socket. %s(%d)\n",
> strerror(errno), errno);
> return -1;
> }
>
> /* Get default options */
> opt = sizeof(opts);
> if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, &opt) < 0) {
> fprintf(stderr, "Can't get default L2CAP options. %s(%d)\n",
> strerror(errno), errno);
> return -1;
> }
>
> /* Set new options */
> //opts.omtu = 48;
> //opts.imtu = imtu;
> if (setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, opt) < 0) {
> fprintf(stderr, "Can't set L2CAP options. %s(%d)\n",
> strerror(errno), errno);
> return -1;
> }
>
> if(listen(sk,5)<0) {
> fprintf(stderr,"\nCan't listen.%s(%d)\n",strerror(errno),errno);
> close(sk);
> return -1;
> }
>
> socklen_t addrlen;
>
> memset(&addr, 0, sizeof(addr));
> addrlen = sizeof(addr);
>
> if ((nsk = accept(sk, (struct sockaddr *) &addr, &addrlen)) < 0)
> return -1;
> else printf("\nConnected");
>
> opt = sizeof(opts);
> if (getsockopt(nsk, SOL_L2CAP, L2CAP_OPTIONS, &opts, &opt) < 0) {
> fprintf(stderr, "Can't get L2CAP options. %s(%d)\n",
> strerror(errno), errno);
> close(nsk);
> return -1;
> }
>
> fprintf(stderr, "Connected [imtu %d, omtu %d, flush_to %d]\n",
> opts.imtu, opts.omtu, opts.flush_to);
>
> if (mtu)
> *mtu = opts.omtu;
>
> return nsk;
> }
>
> #if 0
> static void dump_packet(void *p, int size)
> {
> uint8_t *c = (uint8_t *) p;
> while (size-- > 0)
> printf(" %02x\n", *c++);
> printf("\n");
> }
> #endif
>
> static void init_request(struct avdtp_header * header, int request_id)
> {
> static int transaction = 0;
>
> header->packet_type = PACKET_TYPE_SINGLE;
> header->message_type = MESSAGE_TYPE_ACCEPT;
> header->transaction_label = transaction;
> header->signal_id = request_id;
>
> // clear rfa bits
> header->rfa0 = 0;
> if(header->signal_id!=AVDTP_OPEN)
> transaction = (transaction + 1) & 0xf;
> else transaction = (transaction + 2) & 0xf;
> }
>
>
> static int calc_frame_len(struct sbc_frame_header *hdr)
> {
> int tmp, nrof_subbands, nrof_blocks;
>
> nrof_subbands = (hdr->subbands + 1) * 4;
> nrof_blocks = (hdr->blocks + 1) * 4;
>
> switch (hdr->channel_mode) {
> case 0x00:
> nrof_subbands /= 2;
> tmp = nrof_blocks * hdr->bitpool;
> break;
> case 0x01:
> tmp = nrof_blocks * hdr->bitpool * 2;
> break;
> case 0x02:
> tmp = nrof_blocks * hdr->bitpool;
> break;
> case 0x03:
> tmp = nrof_blocks * hdr->bitpool + nrof_subbands;
> break;
> default:
> return 0;
> }
>
> return (nrof_subbands + ((tmp + 7) / 8));
> }
>
> static int read_header(int fd, struct sbc_frame_header *sbc_info) {
> if (read(fd, sbc_info, sizeof(*sbc_info)) < sizeof(*sbc_info)) {
> fprintf(stderr, "reached end of file?\n");
> return -1;
> }
>
> if (sbc_info->syncword != 0x9c) {
> printf("out of sync (0x%02x)\n", sbc_info->syncword);
> return -1;
> }
>
> return calc_frame_len(sbc_info);
> }
>
> int main(int argc, char *argv[])
> {
> struct sigaction sa;
> int streamfd;
>
> bdaddr_t src, dst;
> unsigned short psm_cmd, psm_stream;
> unsigned long flags;
> int frame_len;
> time_t timestamp;
> uint16_t mtu, seq_num;
> int fd;
>
> bacpy(&src, BDADDR_ANY);
>
> psm_cmd=25;
> cmdfd = do_listen(&src, psm_cmd, NULL);
> if (cmdfd < 0) {
> fprintf(stderr, "cannot open psm_cmd = %d\n", psm_cmd);
> exit(-1);
> }
> // avdtp discover request
>
> //Reading the discover request
> struct sepd_req get_resp;
> int size;
> size = read(cmdfd, &get_resp, sizeof(get_resp));
> if(get_resp.header.signal_id!=AVDTP_DISCOVER) {
> fprintf(stderr,"Couldn't get avdtp_discover\n");
> close(cmdfd);
> exit(-1);
> }
> else printf("\nGot Stream End Point Discovery Request");
>
>
> //Writing the discover response
>
> struct sepd_resp send_resp;
> //Fill in the values in send_resp
> memset(&send_resp,0,sizeof(send_resp));
> init_request(&send_resp.header,AVDTP_DISCOVER);
> send_resp.infos[0].rfa0=0;
> send_resp.infos[0].inuse0=0;
> send_resp.infos[0].acp_seid=1;
> send_resp.infos[0].rfa2=2;
> send_resp.infos[0].tsep=1;
> send_resp.infos[0].media_type=0;
>
> if(write(cmdfd,&send_resp,sizeof(send_resp))!=sizeof(send_resp)) {
> fprintf(stderr,"\nCould not send discover response\n");
> close(cmdfd);
> exit(-1);
> }
> else printf("\nSent Stream End Point Discovery Response\n");
>
>
> //Now read the get capablities request from the source
>
> struct getcap_req get_req;
> memset(&get_req,0,sizeof(get_req));
> if(read(cmdfd,&get_req,sizeof(get_req))!=sizeof(get_req) || (get_req.header.signal_id!=AVDTP_GET_CAPABILITIES)) {
> fprintf(stderr,"\nDidn't get a get cap req");
> }
> else printf("\nGot a get capabilities request\n");
>
> //Send a get cap resp
> struct getcap_resp cap_resp;
> memset(&cap_resp,0,sizeof(cap_resp));
> init_request(&cap_resp.header,AVDTP_GET_CAPABILITIES);
> //Fill in the values of the structure
> cap_resp.serv_cap=MEDIA_TRANSPORT_CATEGORY;
> cap_resp.serv_cap_len=0;
> cap_resp.cap_type=MEDIA_CODEC;
> cap_resp.media_type=AUDIO_MEDIA_TYPE;
> cap_resp.length=6;
> cap_resp.media_codec_type=SBC_MEDIA_CODEC_TYPE;
> cap_resp.sbc_elements.channel_mode=15;
> cap_resp.sbc_elements.frequency=15;
> cap_resp.sbc_elements.allocation_method=3;
> cap_resp.sbc_elements.subbands=3;
> cap_resp.sbc_elements.min_bitpool=2;
> cap_resp.sbc_elements.max_bitpool=250;
> cap_resp.sbc_elements.block_length=15;
>
> if(write(cmdfd,&cap_resp,sizeof(cap_resp))<sizeof(cap_resp)) {
> fprintf(stderr,"couldn't reply the caps\n");
> }
> else printf("\nSent the get capabilities response");
>
> //Now read the set config req
>
> struct set_config s_config;
>
> if(read(cmdfd,&s_config,sizeof(s_config))!=sizeof(s_config) || (s_config.header.signal_id!=AVDTP_SET_CONFIGURATION)) {
> fprintf(stderr,"couldn't get a set configurations request\n");
> }
> else printf("\nGot a set configurations request\n");
>
> //Now send the set config resp
>
> struct set_config_resp s_resp;
> //Fill in the values of the structure
> memset(&s_resp,0,sizeof(s_resp));
> init_request(&s_resp.header,AVDTP_SET_CONFIGURATION);
> s_resp.header.signal_id=AVDTP_SET_CONFIGURATION;
> s_resp.header.message_type=MESSAGE_TYPE_ACCEPT;
> if(write(cmdfd,&s_resp,sizeof(s_resp))!=sizeof(s_resp)) {
> fprintf(stderr,"couldn't send set config resp\n");
> }
> else printf("\nSent a Set configurations response\n");
>
>
> struct open_stream_cmd open_stream;
> memset(&open_stream, 0, sizeof(open_stream));
>
> if ((read(cmdfd, &open_stream, sizeof(open_stream)) != sizeof(open_stream)) || (open_stream.header.signal_id!=AVDTP_OPEN)){
> printf("\nDidn't receive an open stream command\n");
> return (-1);
> }
>
> printf("\nReceived an open stream command\n");
>
> struct open_stream_rsp open_resp;
> memset(&open_resp,0,sizeof(open_resp));
> init_request(&open_resp.header,AVDTP_OPEN);
> open_resp.header.signal_id=AVDTP_OPEN;
> open_resp.header.message_type=MESSAGE_TYPE_ACCEPT;
> if (write(cmdfd, &open_resp, sizeof(open_resp)) < sizeof(open_resp)) {
> fprintf(stderr, "couldn't send open stream response confirm for seid = %d\n", open_stream.acp_seid);
> return (-1);
> }
>
> printf("\nSent open stream confirm\n");
>
> // open the stream l2cap
>
> mtu = 48;
> socklen_t addrlen;
> struct sockaddr_l2 addr;
> memset(&addr, 0, sizeof(addr));
> addrlen = sizeof(addr);
>
> streamfd = accept(sk, (struct sockaddr *) &addr, &addrlen);
>
> if (streamfd < 0) {
> fprintf(stderr, "cannot open psm_stream = %d\n", psm_stream);
> exit(-1);
> }
> else printf("\nConnected on the streamfd channel");
>
> // start the stream
>
> struct start_stream_cmd start_stream;
> memset(&start_stream, 0, sizeof(start_stream));
>
> //Read the start stream command
> if (read(cmdfd, &start_stream, sizeof(start_stream)) != sizeof(start_stream) || (start_stream.header.signal_id!=AVDTP_START)) {
> fprintf(stderr, "\nDid not get a start stream command\n");
> close(streamfd);
> close(cmdfd);
> exit(-1);
> }
>
> else printf("\nGot a stream-start command\n");
>
> //Give the start stream response
> struct start_stream_rsp start_resp;
> //Fill in the values of the structure
> memset(&start_resp,0,sizeof(start_resp));
> init_request(&start_resp.header,AVDTP_START);
> if (write(cmdfd, &start_resp, sizeof(start_resp)) < sizeof(start_resp)) {
> fprintf(stderr, "Couldn't send start stream command confirm");
> close(streamfd);
> close(cmdfd);
> return (-1);
> }
>
> else printf("\nSent start stream confirm\n");
>
> char buf[BUFS];
> int psize;
>
> if (mtu > BUFS)
> mtu = BUFS;
>
> terminate = 0;
> seq_num = 1;
>
> sbc_init(&sbc,SBC_NULL);
> struct media_packet_header packet_header;
> struct media_payload_header payload_header;
> memset(&payload_header, 0, sizeof(payload_header));
> int packsize; //Size of the packet that is read
> timestamp = 0;
> packsize=read(streamfd,buf,1024);
> decode(buf+(sizeof(packet_header)+sizeof(payload_header)),(packsize-sizeof(packet_header)-sizeof(payload_header)));
>
> printf("Channels=%d,speed=%d",channels,speed);
> struct close_stream_cmd close_stream;
> memset(&close_stream,0,sizeof(close_stream));
> while (!terminate) {
>
> packsize=read(streamfd, buf,1024);
> if(packsize < 0)
> break;
> printf("\nRead:%d bytes",packsize);
>
> decode(buf+(sizeof(packet_header)+sizeof(payload_header)),(packsize-sizeof(packet_header)-sizeof(payload_header)));
>
> seq_num++;
> }
> sbc_finish(&sbc);
>
> printf("Received %d packets\n", seq_num);
>
> // signal the stream close
>
> if (read(cmdfd, &close_stream, sizeof(close_stream)) != sizeof(close_stream)) {
> fprintf(stderr, "couldn't get close_stream\n");
> close(streamfd);
> close(cmdfd);
> exit(-1);
> }
>
> if(close_stream.header.signal_id==AVDTP_CLOSE) {
> printf("Got stream-close\n");
> struct close_stream_rsp close_resp;
> init_request(&close_resp.header,AVDTP_CLOSE);
> if (write(cmdfd, &close_resp, sizeof(close_resp)) < sizeof(close_resp)) {
> fprintf(stderr, "Couldn't send close_resp confirm \n");
> close(streamfd);
> close(cmdfd);
> return (-1);
> }
> else printf("Sent close stream confirm\n");
> }
> else {
> printf("\nDidnt get a stream close as expected");
> close(streamfd);
> close(cmdfd);
> exit(-1);
> }
> closesound();
> close(streamfd);
> close(cmdfd);
>
> return 0;
> }
-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click
_______________________________________________
Bluez-devel mailing list
Bluez-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bluez-devel
^ permalink raw reply [flat|nested] 15+ messages in thread* Re: [Bluez-devel] A2DP sink code finally
2005-04-25 3:24 ` Brad Midgley
@ 2005-04-25 3:58 ` Brad Midgley
2005-04-25 6:08 ` Henryk Plötz
2005-04-26 12:23 ` Mayank Batra
2 siblings, 0 replies; 15+ messages in thread
From: Brad Midgley @ 2005-04-25 3:58 UTC (permalink / raw)
To: bluez-devel
Mayank,
I suspect the distortion could be happening if the read() gets an sbc
frame fragment at the end... it would be discarded by the decoder if
that happens.
Brad
-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click
_______________________________________________
Bluez-devel mailing list
Bluez-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bluez-devel
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Bluez-devel] A2DP sink code finally
2005-04-25 3:24 ` Brad Midgley
2005-04-25 3:58 ` Brad Midgley
@ 2005-04-25 6:08 ` Henryk Plötz
2005-04-25 14:40 ` Brad Midgley
2005-04-26 12:23 ` Mayank Batra
2 siblings, 1 reply; 15+ messages in thread
From: Henryk Plötz @ 2005-04-25 6:08 UTC (permalink / raw)
To: bluez-devel
[-- Attachment #1: Type: text/plain, Size: 754 bytes --]
Moin,
Am Sun, 24 Apr 2005 21:24:04 -0600 schrieb Brad Midgley:
> Thanks for the submission. I corrected some warnings, disabled unused
> functions, and added it to Makefile.am.
Ah, thanks.
> We definitely need to do a lot of cleanup (eg now that a2play and
> a2snk have so much duplication), but first off we need to see why
> audio is being distorted...
Hmm, how do I test that? I can't seem to get my audio dongle to connect.
Is there anything else I've got to do apart from
| hciconfig hci0 class 0x200404
| sdptool add A2SNK
| ./a2snk
?
--
Henryk Plötz
Grüße aus Berlin
~~~~~~~ Un-CDs, nein danke! http://www.heise.de/ct/cd-register/ ~~~~~~~
~ Help Microsoft fight software piracy: Give Linux to a friend today! ~
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Bluez-devel] A2DP sink code finally
2005-04-25 6:08 ` Henryk Plötz
@ 2005-04-25 14:40 ` Brad Midgley
0 siblings, 0 replies; 15+ messages in thread
From: Brad Midgley @ 2005-04-25 14:40 UTC (permalink / raw)
To: bluez-devel
Henryk,
I'm not sure anyone has used the dongle yet. (Mayank?)
I'll be trying it once I have another machine set up to run a2play.
Brad
Henryk Plötz wrote:
> Moin,
>
> Am Sun, 24 Apr 2005 21:24:04 -0600 schrieb Brad Midgley:
>
>
>>Thanks for the submission. I corrected some warnings, disabled unused
>>functions, and added it to Makefile.am.
>
>
> Ah, thanks.
>
>
>>We definitely need to do a lot of cleanup (eg now that a2play and
>>a2snk have so much duplication), but first off we need to see why
>>audio is being distorted...
>
>
> Hmm, how do I test that? I can't seem to get my audio dongle to connect.
> Is there anything else I've got to do apart from
> | hciconfig hci0 class 0x200404
> | sdptool add A2SNK
> | ./a2snk
> ?
>
-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click
_______________________________________________
Bluez-devel mailing list
Bluez-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bluez-devel
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Bluez-devel] A2DP sink code finally
2005-04-25 3:24 ` Brad Midgley
2005-04-25 3:58 ` Brad Midgley
2005-04-25 6:08 ` Henryk Plötz
@ 2005-04-26 12:23 ` Mayank Batra
2 siblings, 0 replies; 15+ messages in thread
From: Mayank Batra @ 2005-04-26 12:23 UTC (permalink / raw)
To: bluez-devel
Brad,
> Thanks for the submission. I corrected some
> warnings, disabled unused
> functions, and added it to Makefile.am.
Great!
> We definitely need to do a lot of cleanup (eg now
> that a2play and a2snk
> have so much duplication), but first off we need to
> see why audio is
> being distorted...
Exactly. Once the audio part is ok then we can take
care of the duplication part.
Mayank
> Mayank Batra wrote:
> > Hi Brad,
> >
> > This is the code for the A2DP sink application.
> >
> > Compilation:
> >
> > gcc -o a2snk a2snk.c -lbluetooth
> >
> > Running the application:
> >
> > ./a2snk
> >
> > Right now the following bugs exist:
> >
> > 1) Poor sound quality.
> >
> > 2) Unclean disconnection.
> >
> > Help me improve the above areas.
> >
> > Please add this code to the CVS.
> >
> > Thanks and Regards,
> >
> > Mayank
> >
> >
>
________________________________________________________________________
> > Yahoo! India Matrimony: Find your life partner
> online
> > Go to: http://yahoo.shaadi.com/india-matrimony
> >
> >
> >
>
------------------------------------------------------------------------
> >
> > /*
> > * a2snk.c
> > * This program functions as an A2DP sink
> > * (Emulation of an A2DP headset)
> > * Mayank Batra <mayankbatra@yahoo.co.in>
> > * Abhinav Mathur <abhinavpmathur@yahoo.com>
> > *
> > * 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
> > *
> > */
> >
> > #ifdef HAVE_CONFIG_H
> > #include <config.h>
> > #endif
> >
> > #include <stdio.h>
> > #include <errno.h>
> > #include <fcntl.h>
> > #include <unistd.h>
> > #include <stdlib.h>
> > #include <getopt.h>
> > #include <signal.h>
> > #include <string.h>
> > #include <sys/socket.h>
> > #include <sys/stat.h>
> > #include <sys/soundcard.h> //To play the sound on
> the sound card
> >
> > #include "sbc/sbc.h"
> >
> > #include <bluetooth/bluetooth.h>
> > #include <bluetooth/hci.h>
> > #include <bluetooth/hci_lib.h>
> > #include <bluetooth/l2cap.h>
> > #include <bluetooth/sdp.h>
> > #include <bluetooth/sdp_lib.h>
> >
> > #include <netinet/in.h>
> >
> > /* AVDTP structures */
> >
> > /* packet components */
> >
> > struct avdtp_header {
> > //uint8_t packet_type:2;
> > uint8_t message_type:2;
> > uint8_t packet_type:2;
> > uint8_t transaction_label:4;
> > uint8_t signal_id:6;
> > uint8_t rfa0:2;
> > } __attribute__ ((packed));
> >
> > struct acp_seid_info {
> > uint8_t rfa0:1;
> > uint8_t inuse0:1;
> > uint8_t acp_seid:6;
> > uint8_t rfa2:3;
> > uint8_t tsep:1;
> > uint8_t media_type:4;
> > } __attribute__ ((packed));
> >
> > struct sbc_codec_specific_elements {
> > // a2dp p. 20
> > uint8_t channel_mode:4;
> > uint8_t frequency:4;
> > uint8_t allocation_method:2;
> > uint8_t subbands:2;
> > uint8_t block_length:4;
> > uint8_t min_bitpool;
> > uint8_t max_bitpool;
> > } __attribute__ ((packed));
> >
> > #define MAX_ADDITIONAL_CODEC 0 //Right now only
> SBC is supported
> > #define MAX_ADDITIONAL_CODEC_OCTETS
> (MAX_ADDITIONAL_CODEC*sizeof(struct acp_seid_info))
> >
> > /* packets */
> >
> > struct sepd_req {
> > struct avdtp_header header;
> > } __attribute__ ((packed));
> >
> > struct sepd_resp {
> > struct avdtp_header header;
> > struct acp_seid_info infos[1 +
> MAX_ADDITIONAL_CODEC];
> > } __attribute__ ((packed));
> >
> > struct getcap_req {
> > struct avdtp_header header;
> > uint8_t rfa1:2;
> > uint8_t acp_seid:6;
> > } __attribute__ ((packed));
> >
> > struct getcap_resp {
> > struct avdtp_header header;
> >
> > uint8_t serv_cap;
> > uint8_t serv_cap_len;
> >
> > uint8_t cap_type;
> > uint8_t length;
> > uint8_t media_type;
> > uint8_t media_codec_type;
> >
> > struct sbc_codec_specific_elements sbc_elements;
> >
> > } __attribute__ ((packed));
> >
> > struct set_config {
> > struct avdtp_header header;
> >
> > uint8_t rfa0:2;
> > uint8_t acp_seid:6;
> > uint8_t rfa1:2;
> > uint8_t int_seid:6;
> >
> > uint8_t serv_cap;
> > uint8_t serv_cap_len;
> >
> > uint8_t cap_type;
> > uint8_t length;
> > uint8_t media_type;
> > uint8_t media_codec_type;
> >
> > struct sbc_codec_specific_elements sbc_elements;
> >
> > } __attribute__ ((packed));
>
=== message truncated ===
________________________________________________________________________
Yahoo! India Matrimony: Find your life partner online
Go to: http://yahoo.shaadi.com/india-matrimony
-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click
_______________________________________________
Bluez-devel mailing list
Bluez-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bluez-devel
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2005-05-03 13:23 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-04-26 12:34 [Bluez-devel] A2DP sink code finally Mayank Batra
2005-04-27 16:27 ` Brad Midgley
2005-05-01 15:16 ` Henryk Plötz
2005-05-03 13:23 ` Mayank Batra
-- strict thread matches above, loose matches on Subject: below --
2005-04-26 12:35 Mayank Batra
2005-04-26 13:10 ` Brad Midgley
2005-04-26 15:50 ` Marcel Holtmann
2005-04-27 19:08 ` Brad Midgley
2005-04-26 12:29 Mayank Batra
2005-04-24 15:09 Mayank Batra
2005-04-25 3:24 ` Brad Midgley
2005-04-25 3:58 ` Brad Midgley
2005-04-25 6:08 ` Henryk Plötz
2005-04-25 14:40 ` Brad Midgley
2005-04-26 12:23 ` Mayank Batra
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.