Linux bluetooth development
 help / color / mirror / Atom feed
From: Mayank Batra <mayankbatra@yahoo.co.in>
To: BLUEZ DEVELOPERS LIST <bluez-devel@lists.sourceforge.net>
Cc: Brad Midgley <bmidgley@xmission.com>
Subject: [Bluez-devel] A2DP sink code finally
Date: Sun, 24 Apr 2005 16:09:30 +0100 (BST)	[thread overview]
Message-ID: <20050424150930.71134.qmail@web8308.mail.in.yahoo.com> (raw)

[-- 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;
}

             reply	other threads:[~2005-04-24 15:09 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2005-04-24 15:09 Mayank Batra [this message]
2005-04-25  3:24 ` [Bluez-devel] A2DP sink code finally 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
  -- strict thread matches above, loose matches on Subject: below --
2005-04-26 12:29 Mayank Batra
2005-04-26 12:34 Mayank Batra
2005-04-27 16:27 ` Brad Midgley
2005-05-01 15:16 ` Henryk Plötz
2005-05-03 13:23   ` Mayank Batra
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

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=20050424150930.71134.qmail@web8308.mail.in.yahoo.com \
    --to=mayankbatra@yahoo.co.in \
    --cc=bluez-devel@lists.sourceforge.net \
    --cc=bmidgley@xmission.com \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox