All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Frédéric DALLEAU" <frederic.dalleau@palmsource.com>
To: BlueZ development <bluez-devel@lists.sourceforge.net>
Subject: [Bluez-devel] New A2DP related progress
Date: Fri, 28 Jul 2006 12:26:56 +0200	[thread overview]
Message-ID: <44C9E670.70105@palmsource.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 850 bytes --]

Hi all, Brad, Matthew, Fabien,

My latest work on a2dp daemon. I got good sound on both pc and arm!! 
Features a volume control plugin.

Stereo stream is still inverted.
There is also a parasite sound that you hear when silence is sent. Both 
are certainly related!
minor cracks when starting a stream.

Matthew, bmp does work well if esd is selected as output. This is due to 
difference in alsa data transfer (SND_PCM_ACCESS_RW_INTERLEAVED vs 
SND_PCM_ACCESS_MMAP_INTERLEAVED). I will have a look later.

Fabien, I successfully used alsamixer to configure volume on my device. 
Do you know of other software that would allow mixing for any control 
device? I cannot tell xmms to use the device.

Brad, as usual tarball :D available : 
http://fdalleau.free.fr/btsco.tar.gz, and a patch attached.

Hope you like it!
Frédéric


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: btsco-diff-cvs-2006-07-28.patch --]
[-- Type: text/x-patch; name="btsco-diff-cvs-2006-07-28.patch", Size: 186175 bytes --]

? .deps
? Makefile
? Makefile.in
? aclocal.m4
? autom4te.cache
? config.guess
? config.h
? config.h.in
? config.log
? config.status
? config.sub
? configure
? depcomp
? install-sh
? libtool
? missing
? mkinstalldirs
? stamp-h
? stamp-h.in
? alsa-plugins/.deps
? alsa-plugins/Makefile
? alsa-plugins/Makefile.in
? avdtp/.deps
? avdtp/Makefile
? avdtp/Makefile.in
? sbc/.deps
? sbc/Makefile
? sbc/Makefile.in
Index: configure.in
===================================================================
RCS file: /cvsroot/bluetooth-alsa/btsco/configure.in,v
retrieving revision 1.11
diff -u -r1.11 configure.in
--- configure.in	5 Jan 2006 22:51:06 -0000	1.11
+++ configure.in	28 Jul 2006 09:48:08 -0000
@@ -5,7 +5,7 @@
 AC_PREREQ(2.50)
 AC_INIT()
 
-AM_INIT_AUTOMAKE(btsco, 0.2)
+AM_INIT_AUTOMAKE(btsco, 0.42)
 AM_CONFIG_HEADER(config.h)
 
 if (test "${CFLAGS}" = ""); then
Index: alsa-plugins/Makefile.am
===================================================================
RCS file: /cvsroot/bluetooth-alsa/btsco/alsa-plugins/Makefile.am,v
retrieving revision 1.3
diff -u -r1.3 Makefile.am
--- alsa-plugins/Makefile.am	12 Jul 2006 05:47:06 -0000	1.3
+++ alsa-plugins/Makefile.am	28 Jul 2006 09:48:08 -0000
@@ -1,5 +1,6 @@
 libasound_module_pcm_a2dp_la_LDFLAGS = -module -avoid-version -export-dynamic
 libasound_module_pcm_a2dpd_la_LDFLAGS = -module -avoid-version -export-dynamic
+libasound_module_ctl_a2dpd_la_LDFLAGS = -module -avoid-version -export-dynamic
 libasound_module_pcm_headset_la_LDFLAGS = -module -avoid-version -export-dynamic
 
 if ALSAPLUGIN
@@ -8,20 +9,23 @@
 
 alsadir = $(libdir)/alsa-lib
 
-alsa_LTLIBRARIES = libasound_module_pcm_a2dp.la libasound_module_pcm_a2dpd.la libasound_module_pcm_headset.la
+alsa_LTLIBRARIES = libasound_module_pcm_a2dp.la libasound_module_pcm_a2dpd.la libasound_module_ctl_a2dpd.la libasound_module_pcm_headset.la
 
 libasound_module_pcm_a2dp_la_SOURCES = pcm_a2dp.c
 libasound_module_pcm_a2dp_la_LIBADD = @ALSA_LIBS@ @BLUEZ_LIBS@ -lsbc -lpthread
 
-libasound_module_pcm_a2dpd_la_SOURCES = pcm_a2dpd.c
-libasound_module_pcm_a2dpd_la_LIBADD = @ALSA_LIBS@ @BLUEZ_LIBS@ -lsbc -lpthread
+libasound_module_pcm_a2dpd_la_SOURCES = pcm_a2dpd.c a2dp_timer.c a2dp_ipc.c
+libasound_module_pcm_a2dpd_la_LIBADD = @ALSA_LIBS@ -lrt
+
+libasound_module_ctl_a2dpd_la_SOURCES = ctl_a2dpd.c a2dp_ipc.c
+libasound_module_ctl_a2dpd_la_LIBADD = @ALSA_LIBS@
 
 libasound_module_pcm_headset_la_SOURCES = pcm_headset.c
 libasound_module_pcm_headset_la_LIBADD = @ALSA_LIBS@ @BLUEZ_LIBS@ -lpthread
 
-noinst_PROGRAMS = a2dpd
-a2dpd_SOURCES = a2dpd.c a2dplib.c
-a2dpd_LDADD = @BLUEZ_LIBS@ -lsbc -lpthread
+bin_PROGRAMS = a2dpd
+a2dpd_SOURCES = a2dpd.c a2dplib.c a2dp_timer.c a2dp_ipc.c
+a2dpd_LDADD = @BLUEZ_LIBS@ -lsbc -lpthread -lrt
 
 AM_CFLAGS = @ALSA_CFLAGS@ @BLUEZ_CFLAGS@ -pthread
 
Index: alsa-plugins/a2dp_ipc.c
===================================================================
RCS file: alsa-plugins/a2dp_ipc.c
diff -N alsa-plugins/a2dp_ipc.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ alsa-plugins/a2dp_ipc.c	28 Jul 2006 09:48:08 -0000
@@ -0,0 +1,173 @@
+/*
+*
+*  A2DPD - Bluetooth A2DP daemon for Linux
+*
+*  Copyright (C) 2006  Frédéric DALLEAU <frederic.dalleau@palmsource.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.
+*/
+
+#include "a2dp_ipc.h"
+#include <unistd.h>
+#include <string.h>
+#include <syslog.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#define DEFAULTIP    "127.0.0.1"
+#define DEFAULTPORT  21453
+#define BROADCASTIP  "127.0.0.255"
+
+void close_socket(int sockfd)
+{
+        if(sockfd>0) close(sockfd);
+}
+
+int make_udp_socket()
+{
+        int sockfd = socket(PF_INET, SOCK_DGRAM, 0);
+        if(sockfd>0)
+        {
+                int broadcast=1;
+                if(setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast)) == 0)
+                {
+                        struct sockaddr_in peer_addr;
+                        peer_addr.sin_family = AF_INET;
+                        peer_addr.sin_port = htons(DEFAULTPORT);
+                        peer_addr.sin_addr.s_addr = inet_addr(BROADCASTIP);
+                        // Connect on a datagram socket simulate recvfrom with the address specified
+                        bind(sockfd, (struct sockaddr *)&peer_addr, sizeof(peer_addr));
+                        if(connect(sockfd, (struct sockaddr*)&peer_addr, sizeof(peer_addr)) == 0)
+                        {
+                        }
+                        else
+                        {
+                                close(sockfd);
+                                sockfd=-1;
+                        }
+               }
+               else
+               {
+                       close(sockfd);
+                       sockfd=-1;
+               }
+        }
+        return sockfd;
+}
+
+int make_client_socket()
+{
+        int sockfd = socket(PF_INET, SOCK_STREAM, 0);
+        if(sockfd>0)
+        {
+                struct sockaddr_in peer_addr;
+                peer_addr.sin_family = AF_INET;
+                peer_addr.sin_port = htons(DEFAULTPORT);
+                peer_addr.sin_addr.s_addr = inet_addr(DEFAULTIP);
+                connect(sockfd, (struct sockaddr*)&peer_addr, sizeof(peer_addr));
+        }
+        return sockfd;
+}
+
+int make_server_socket()
+{
+        int sockfd = socket(PF_INET, SOCK_STREAM, 0);
+        struct sockaddr_in my_addr;
+        memset(&my_addr, 0, sizeof(my_addr));
+        my_addr.sin_family = AF_INET;
+        my_addr.sin_port = htons(DEFAULTPORT);
+        my_addr.sin_addr.s_addr = INADDR_ANY;
+
+        if(sockfd>0)
+        {
+                if(bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr))==0)
+                {
+                        if(listen(sockfd, 10)==0)
+                        {
+                                // No error
+                        }
+                        else
+                        {
+                                close(sockfd);
+                                sockfd = -3;
+                        }
+                }
+                else
+                {
+                        close(sockfd);
+                        sockfd = -2;
+                }
+        }
+
+        return sockfd;
+}
+
+int accept_socket(int sockfd)
+{
+        // Block until connections
+        struct sockaddr_in peer_addr;
+        int sin_size = sizeof(peer_addr);
+        int new_fd = accept(sockfd, (struct sockaddr *)&peer_addr, &sin_size);
+        return new_fd;
+}
+
+void setup_socket(int sockfd)
+{
+        // Timeouts
+        struct timeval t = { 2, 100 };
+        setsockopt( sockfd, SOL_SOCKET, SO_SNDTIMEO, &t, sizeof(t));
+        setsockopt( sockfd, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(t));
+}
+
+
+int send_socket(int sockfd, void* buffer, int size)
+{
+        int result = -1;
+        int ioffset = 0;
+        while(sockfd>0 && ioffset<size)
+        {
+                result=send(sockfd, ((char*)buffer)+ioffset, size-ioffset, MSG_NOSIGNAL);
+                if(result>0)
+                {
+                        ioffset += result;
+                }
+                else
+                {
+                        break;
+                }
+        }
+        return result;
+
+}
+
+int recv_socket(int sockfd, void* buffer, int size)
+{
+        int received = 0;
+        while(buffer && received<size)
+        {
+                int result = recv(sockfd, buffer+received, size-received, MSG_NOSIGNAL);
+                if(result>0)
+                {
+                        received += result;
+                }
+                else
+                {
+                        received=result;
+                        break;
+                }
+        }
+        return received;
+}
Index: alsa-plugins/a2dp_ipc.h
===================================================================
RCS file: alsa-plugins/a2dp_ipc.h
diff -N alsa-plugins/a2dp_ipc.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ alsa-plugins/a2dp_ipc.h	28 Jul 2006 09:48:08 -0000
@@ -0,0 +1,39 @@
+/*
+*
+*  A2DPD - Bluetooth A2DP daemon for Linux
+*
+*  Copyright (C) 2006  Frédéric DALLEAU <frederic.dalleau@palmsource.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.
+*/
+
+
+#ifndef __A2DP_IPC_H__
+#define __A2DP_IPC_H__
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+int make_udp_socket();
+int make_client_socket();
+int make_server_socket();
+void setup_socket(int sockfd);
+void close_socket(int sockfd);
+int accept_socket(int sockfd);
+int send_socket(int sockfd, void* buffer, int size);
+int recv_socket(int sockfd, void* buffer, int size);
+
+#endif
Index: alsa-plugins/a2dp_timer.c
===================================================================
RCS file: alsa-plugins/a2dp_timer.c
diff -N alsa-plugins/a2dp_timer.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ alsa-plugins/a2dp_timer.c	28 Jul 2006 09:48:08 -0000
@@ -0,0 +1,122 @@
+/*
+*
+*  A2DPD - Bluetooth A2DP daemon for Linux
+*
+*  Copyright (C) 2006  Frédéric DALLEAU <frederic.dalleau@palmsource.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.
+*/
+
+#include "a2dp_timer.h"
+#include <time.h>
+#include <unistd.h>
+#include <syslog.h>
+
+void sleeptodate(LPTIMERINFO lpTimerInfo, struct timeval* date, int predelay)
+{
+        struct timeval now;
+        struct timeval resolutionval={0, predelay + (int)(lpTimerInfo->timer_resolution.tv_nsec/1000)};
+
+        // See if we have time to wait
+        timeradd(&lpTimerInfo->timeofday, &resolutionval, &now);
+        if (timercmp(date, &now, >))
+        {
+                // Synchronise with usleep 20 ms cycle
+                usleep(1);
+                // See if we must wait again
+                gettimeofday(&now, NULL);
+                timeradd(&now, &resolutionval, &now);
+                if (timercmp(date, &now, >))
+                {
+                        struct timeval interval = { 0, 0 };
+                        timersub(date, &now, &interval);
+                        // sleep
+                        usleep(interval.tv_usec);
+                }
+        }
+        else
+        {
+                // We're late, do not wait
+        }
+}
+
+// This version uses values never reset
+void keepfreqtotal(LPTIMERINFO lpTimerInfo, LPKEEPFREQ lpKeepFreq, int predelay)
+{
+        struct timeval playtime, theoricaldate;
+
+        playtime.tv_sec=((int)(1.0*1000.0*1000.0*lpTimerInfo->itotalcount/lpTimerInfo->fps))/1000000;
+        playtime.tv_usec=((int)(1.0*1000.0*1000.0*lpTimerInfo->itotalcount/lpTimerInfo->fps))%1000000;
+        timeradd(&lpTimerInfo->totalcounter, &playtime, &theoricaldate);
+        // Si la date théorique est supérieure à la date actuelle
+        if(timercmp(&theoricaldate, &lpTimerInfo->timeofday, >))
+        {
+                sleeptodate(lpTimerInfo, &theoricaldate, predelay);
+        }
+}
+
+void a2dp_timer_notifyframe(LPTIMERINFO lpTimerInfo)
+{
+        struct timeval lastframe_interval = {0,0};
+        struct timeval maxallowed_interval = {0,200*1000};
+        gettimeofday(&lpTimerInfo->timeofday, NULL);
+        timersub(&lpTimerInfo->timeofday, &lpTimerInfo->lastframe, &lastframe_interval);
+        // Previous frames older than 1 second, reset counters
+        if(timercmp(&lastframe_interval, &maxallowed_interval, >))
+        {
+                // We must reset the total counter because else, we will believe the date is late
+                gettimeofday(&lpTimerInfo->totalcounter, NULL);
+                lpTimerInfo->itotalcount=0;
+        }
+        gettimeofday(&lpTimerInfo->lastframe, NULL);
+}
+
+void a2dp_timer_sleep(LPTIMERINFO lpTimerInfo, int predelay)
+{
+        gettimeofday(&lpTimerInfo->timeofday, NULL);
+
+        // Initialize timers
+        if(lpTimerInfo->staticcounter.tv_sec==0)
+                gettimeofday(&lpTimerInfo->staticcounter, NULL);
+        if(lpTimerInfo->totalcounter.tv_sec==0)
+        {
+                gettimeofday(&lpTimerInfo->totalcounter, NULL);
+                lpTimerInfo->itotalcount=0;
+        }
+        if(lpTimerInfo->timer_resolution.tv_nsec == 0)
+                clock_getres(CLOCK_REALTIME, &lpTimerInfo->timer_resolution);
+
+        // Duration since last call
+        timersub(&lpTimerInfo->timeofday, &lpTimerInfo->staticcounter, &lpTimerInfo->duration);
+
+        // Display data once per second
+        if(lpTimerInfo->duration.tv_sec>0)
+        {
+                // Reset all statistics
+                gettimeofday(&lpTimerInfo->staticcounter, NULL);
+                lpTimerInfo->display=lpTimerInfo->icount;
+                lpTimerInfo->icount=0;
+        }
+        else
+        {
+                lpTimerInfo->display=0;
+        }
+
+        keepfreqtotal(lpTimerInfo, &lpTimerInfo->k, predelay);
+
+        lpTimerInfo->icount++;
+        lpTimerInfo->itotalcount++;
+}
+
Index: alsa-plugins/a2dp_timer.h
===================================================================
RCS file: alsa-plugins/a2dp_timer.h
diff -N alsa-plugins/a2dp_timer.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ alsa-plugins/a2dp_timer.h	28 Jul 2006 09:48:08 -0000
@@ -0,0 +1,75 @@
+/*
+*
+*  A2DPD - Bluetooth A2DP daemon for Linux
+*
+*  Copyright (C) 2006  Frédéric DALLEAU <frederic.dalleau@palmsource.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.
+*/
+
+
+#ifndef __A2DP_TIMER_H__
+#define __A2DP_TIMER_H__
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/time.h>
+
+#define A2DPTIMERPREDELAY       2000
+#define CUMULATIVESLEEPDELAY    10000
+
+typedef struct
+{
+        struct timeval t;
+} SLEEPTILL, *LPSLEEPTILL;
+
+
+typedef struct
+{
+        struct timeval t;
+} KEEPFREQ, *LPKEEPFREQ;
+
+// 
+typedef struct 
+{
+        float fps;                              // Number of frames per second to achieve
+
+        union
+        {
+                SLEEPTILL s;
+                KEEPFREQ  k;
+        };
+
+        struct timespec timer_resolution;       // Resolution of the timer in nanoseconds
+        struct timeval timeofday;               // Date of this frame
+        struct timeval lastframe;               // Date of last frame
+        struct timeval staticcounter;           // Date of frame 0 (icount=0) reseted each second
+        struct timeval totalcounter;            // Date of frame 0 (itotalcount=0)
+        struct timeval duration;                // Time since last frame
+        int icount;                             // Count of frames for this second
+        int itotalcount;                        // Count of frames since startup
+        int display;                            // non zéro if a second has just ended
+} TIMERINFO, *LPTIMERINFO;
+
+// Use notify frame when some data is sent
+void a2dp_timer_notifyframe(LPTIMERINFO lpTimerInfo);
+
+// Use sleep in your upper level loop
+// When no calls to notify_frame are done, internal statistics counter will be reseted
+void a2dp_timer_sleep(LPTIMERINFO lpTimerInfo, int predelay);
+
+#endif
Index: alsa-plugins/a2dpd.c
===================================================================
RCS file: /cvsroot/bluetooth-alsa/btsco/alsa-plugins/a2dpd.c,v
retrieving revision 1.1
diff -u -r1.1 a2dpd.c
--- alsa-plugins/a2dpd.c	12 Jul 2006 05:47:06 -0000	1.1
+++ alsa-plugins/a2dpd.c	28 Jul 2006 09:48:08 -0000
@@ -27,26 +27,26 @@
 #include <errno.h>
 #include <signal.h>
 #include <pthread.h>
+#include <sys/socket.h>
 #include <sys/types.h>
 #include <sys/time.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
 
 #include "a2dplib.h"
+#include "a2dpd_protocol.h"
+#include "a2dp_timer.h"
+#include "a2dp_ipc.h"
 
 #define BLUETOOTHSOUNDFIFOSIZE (16*1024)
 #define MAXBLUETOOTHDEVICES    3
-#define MYPORT                 21453
 #define MAXCLIENTSPERDEVICE    8
-#define MAXCLIENTSRINGSIZE     8
-#define POOLENTRYSIZE          512
+#define MAXCLIENTSRINGSIZE     64
+#define POOLENTRYSIZE          A2DPD_BLOCK_SIZE
 
 // if 1 then quit gently
-static int bSigINTReceived = 0;
+static sig_atomic_t bSigINTReceived = 0;
 
 // count the number of client running
-static int iThreadsRunning = 0;
+static sig_atomic_t iThreadsRunning = 0;
 
 #define max(x,y) ((x)>(y)?(x):(y))
 
@@ -59,35 +59,35 @@
 {
         free(pool);
 }
-
 // Data used to mix audio
 typedef struct
 {
-        int     lives;
-        pthread_mutex_t mutex;
-        int     ring_in;
-        int     ring_out;
-        int     ring_len[MAXCLIENTSRINGSIZE];
-        char*   ring[MAXCLIENTSRINGSIZE];
+        int                     lives;
+        pthread_mutex_t         mutex;
+        int                     ring_in;
+        int                     ring_out;
+        int                     ring_len[MAXCLIENTSRINGSIZE];
+        char*                   ring[MAXCLIENTSRINGSIZE];
 } BTA2DPPERCLIENTDATA;
 
 // Data to keep per Bluetooth device
 typedef struct
 {
-        char 				addr[20];
-        pthread_t 			thread;
-        pthread_t 			receiverthread;
-        pthread_mutex_t 		mutex;
-        int				nb_clients;
-        BTA2DPPERCLIENTDATA             clients[MAXCLIENTSPERDEVICE];
+        char                    addr[20];
+        pthread_t               thread;
+        pthread_t               receiverthread;
+        pthread_mutex_t         mutex;
+        AUDIOMIXERDATA          mixer;
+        int                     nb_clients;
+        BTA2DPPERCLIENTDATA     clients[MAXCLIENTSPERDEVICE];
 } BTA2DPPERDEVICEDATA, *LPBTA2DPPERDEVICEDATA;
 
 // Data needed per Audio Streaming Client
 typedef struct
 {
-        LPBTA2DPPERDEVICEDATA 		lpDevice;
-        int 				sockfd;
-        pthread_t 	    		thread;
+        LPBTA2DPPERDEVICEDATA   lpDevice;
+        int                     sockfd;
+        pthread_t               thread;
 } A2DPDCLIENT, *LPA2DPDCLIENT;
 
 // Allocate a new device
@@ -99,6 +99,10 @@
         {
                 memset(lpDevice, 0, sizeof(BTA2DPPERDEVICEDATA));
                 strncpy(lpDevice->addr, addr, sizeof(lpDevice->addr)); lpDevice->addr[sizeof(lpDevice->addr)-1] = 0;
+                lpDevice->mixer.volume_speaker_left = A2DPD_VOLUME_MAX;
+                lpDevice->mixer.volume_speaker_right = A2DPD_VOLUME_MAX;
+                lpDevice->mixer.volume_micro_left = A2DPD_VOLUME_MAX;
+                lpDevice->mixer.volume_micro_right = A2DPD_VOLUME_MAX;
                 pthread_mutex_init(&lpDevice->mutex, NULL);
                 for(i=0;i<MAXCLIENTSPERDEVICE; i++)
                 {
@@ -139,53 +143,8 @@
                 printf("handling SIGINT\n");
         
                 // Dummy connection to unlock server (currently accepting)
-                {
-                        int sockfd = socket(PF_INET, SOCK_STREAM, 0);
-                        if(sockfd>0)
-                        {
-                                struct sockaddr_in peer_addr;
-                                peer_addr.sin_family = AF_INET;
-                                peer_addr.sin_port = htons(MYPORT);
-                                peer_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
-                                connect(sockfd, (struct sockaddr*)&peer_addr, sizeof(peer_addr));
-                                close(sockfd);
-                        }
-                }
-        }
-}
-
-// Create server socket
-int make_the_socket()
-{
-        int sockfd = socket(PF_INET, SOCK_STREAM, 0);
-        struct sockaddr_in my_addr;
-        memset(&my_addr, 0, sizeof(my_addr));
-        my_addr.sin_family = AF_INET;
-        my_addr.sin_port = htons(MYPORT);
-        my_addr.sin_addr.s_addr = INADDR_ANY;
-
-        if(sockfd>0)
-        {
-                if(bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr))==0)
-                {
-                        if(listen(sockfd, 10)==0)
-                        {
-                                // No error
-                        }
-                        else
-                        {
-                                close(sockfd);
-                                sockfd = -3;
-                        }
-                }
-                else
-                {
-                        close(sockfd);
-                        sockfd = -2;
-                }
+                close_socket(make_client_socket());
         }
-
-        return sockfd;
 }
 
 // This function handles a client
@@ -193,121 +152,151 @@
 {
         int bError = 0;
         int client_index = -1;
-        
+        int32_t client_type = INVALID_CLIENT_TYPE;
+        int result;
+        LPA2DPDCLIENT lpClient = (LPA2DPDCLIENT)param;
+        AUDIOMIXERDATA AudioMixerData = INVALIDAUDIOMIXERDATA;
+
         // We should not terminate the process if clients are still running
         iThreadsRunning ++;
 
-        LPA2DPDCLIENT lpClient = (LPA2DPDCLIENT)param;
         pthread_detach(lpClient->thread);
 
-        // Find an index in clients table
-        pthread_mutex_lock(&lpClient->lpDevice->mutex);
-        for(client_index=0; client_index<MAXCLIENTSPERDEVICE; client_index++)
+        setup_socket(lpClient->sockfd);
+
+        // Receive type of client
+        result = recv_socket(lpClient->sockfd, &client_type, sizeof(client_type));
+
+        // This client wants to send us pcm control data
+        if(client_type==A2DPD_PLUGIN_CTL_WRITE)
         {
-                if(lpClient->lpDevice->clients[client_index].lives==0)
+                printf("CTL WRITE thread %d.%d started\n", client_index, lpClient->sockfd);
+
+                if(recv_socket(lpClient->sockfd, &AudioMixerData, sizeof(AudioMixerData))==sizeof(AudioMixerData))
                 {
-                        lpClient->lpDevice->clients[client_index].lives = 1;
-                        lpClient->lpDevice->clients[client_index].ring_in = 0;
-                        lpClient->lpDevice->clients[client_index].ring_out = 0;
-                        break;
+                        pthread_mutex_lock(&lpClient->lpDevice->mutex);
+                        if(AudioMixerData.volume_speaker_left != -1)
+                                lpClient->lpDevice->mixer.volume_speaker_left = AudioMixerData.volume_speaker_left;
+                        if(AudioMixerData.volume_speaker_left != -1)
+                                lpClient->lpDevice->mixer.volume_speaker_right= AudioMixerData.volume_speaker_right;
+                        if(AudioMixerData.volume_micro_left != -1)
+                                lpClient->lpDevice->mixer.volume_micro_left = AudioMixerData.volume_micro_left;
+                        if(AudioMixerData.volume_micro_left != -1)
+                                lpClient->lpDevice->mixer.volume_micro_right= AudioMixerData.volume_micro_right;
+                        pthread_mutex_unlock(&lpClient->lpDevice->mutex);
+                        // Notify other clients
+                        int notifyfd = make_udp_socket();
+                        int i=send_socket(notifyfd, &AudioMixerData, sizeof(AudioMixerData));
+                        printf("Notify return %d\n", i);
+                        close_socket(notifyfd);
                 }
         }
-        pthread_mutex_unlock(&lpClient->lpDevice->mutex);
-        
-        if(client_index>=MAXCLIENTSPERDEVICE)
+
+        // This client wants to read our control status
+        if(client_type==A2DPD_PLUGIN_CTL_READ)
         {
-                printf("Client thread %d cannot start (too many clients already connected)\n", client_index);
-                return 0;
-        }
+                printf("CTL READ thread %d.%d started\n", client_index, lpClient->sockfd);
 
-        // Allocate buffer
-        printf("Client thread %d.%d started\n", client_index, lpClient->sockfd);
+                pthread_mutex_lock(&lpClient->lpDevice->mutex);
+                AudioMixerData = lpClient->lpDevice->mixer;
+                pthread_mutex_unlock(&lpClient->lpDevice->mutex);
 
-        struct timeval t = { 1, 0 };
-        setsockopt( lpClient->sockfd, SOL_SOCKET, SO_SNDTIMEO, &t, sizeof(t));
-        setsockopt( lpClient->sockfd, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(t));
+                send_socket(lpClient->sockfd, &AudioMixerData, sizeof(AudioMixerData));
+        }
 
-        // Loop while we receive data
-        while(!bSigINTReceived && !bError)
+        // This client wants to send us pcm stream
+        if(client_type==A2DPD_PLUGIN_PCM_WRITE)
         {
-                // Receive data
-                int pcm_buffer_size = 0;
-                int result = recv(lpClient->sockfd, &pcm_buffer_size, sizeof(pcm_buffer_size), 0);
-                if(result == sizeof(pcm_buffer_size) && pcm_buffer_size<=POOLENTRYSIZE)
-                {
-                        int received = 0;
-                        char* pcm_buffer = pool_pop();
-                        
-                        while(pcm_buffer && received<pcm_buffer_size)
+                // Find an index in clients table for the mixer
+                pthread_mutex_lock(&lpClient->lpDevice->mutex);
+                for(client_index=0; client_index<MAXCLIENTSPERDEVICE; client_index++)
+                {
+                        if(lpClient->lpDevice->clients[client_index].lives==0)
                         {
-                                result = recv(lpClient->sockfd, pcm_buffer+received, pcm_buffer_size-received, 0);
-                                if(result>0)
-                                {
-                                        //if(result<pcm_buffer_size) printf("PART : Received %d bytes of data\n", result);
-                                        received += result;
-                                }
-                                else
-                                {
-                                        break;
-                                }
+                                lpClient->lpDevice->clients[client_index].lives = 1;
+                                lpClient->lpDevice->clients[client_index].ring_in = 0;
+                                lpClient->lpDevice->clients[client_index].ring_out = 0;
+                                break;
                         }
+                }
+                pthread_mutex_unlock(&lpClient->lpDevice->mutex);
+
+                printf("PCM thread %d.%d started\n", client_index, lpClient->sockfd);
 
-                        if(received==pcm_buffer_size)
+                if(client_index>=MAXCLIENTSPERDEVICE)
+                {
+                        printf("Client thread %d cannot start (too many clients already connected)\n", client_index);
+                        return 0;
+                }
+
+                // Loop while we receive data
+                while(!bSigINTReceived && !bError)
+                {
+                        // Receive data
+                        int32_t pcm_buffer_size = 0;
+                        result = recv_socket(lpClient->sockfd, &pcm_buffer_size, sizeof(pcm_buffer_size));
+                        if(result == sizeof(pcm_buffer_size) && pcm_buffer_size<=POOLENTRYSIZE)
                         {
-                                // Enqueue in bluetooth headset if we can else loose packet
-                                pthread_mutex_lock(&lpClient->lpDevice->clients[client_index].mutex);
+                                char* pcm_buffer = pool_pop();
+                                result = recv_socket(lpClient->sockfd, pcm_buffer, pcm_buffer_size);
+
+                                if(result==pcm_buffer_size)
+                                {
+                                        // Enqueue in bluetooth headset if we can else loose packet
+                                        pthread_mutex_lock(&lpClient->lpDevice->clients[client_index].mutex);
+
+                                        // Append data to ring
+                                        int this_ring = lpClient->lpDevice->clients[client_index].ring_in;
+                                        int next_ring = ((this_ring+1)%MAXCLIENTSRINGSIZE);
+
+                                        if(next_ring != lpClient->lpDevice->clients[client_index].ring_out)
+                                        {
+                                                lpClient->lpDevice->clients[client_index].ring[this_ring] = pcm_buffer;
+                                                lpClient->lpDevice->clients[client_index].ring_len[this_ring] = pcm_buffer_size;
+                                                lpClient->lpDevice->clients[client_index].ring_in = next_ring;
+                                                // We will not free that buffer, it's the bthandler thread which will do it
+                                                pcm_buffer = NULL;
+                                        }
 
-                                // Append data to ring
-                                int next_ring = ((lpClient->lpDevice->clients[client_index].ring_in+1)%MAXCLIENTSRINGSIZE);
-                                if(next_ring != lpClient->lpDevice->clients[client_index].ring_out)
-                                {
-                                        //printf("Writing pool %d[%d ] = %p\n", client_index, lpClient->lpDevice->clients[client_index].ring_in, pcm_buffer);
-                                        lpClient->lpDevice->clients[client_index].ring[lpClient->lpDevice->clients[client_index].ring_in] = pcm_buffer;
-                                        lpClient->lpDevice->clients[client_index].ring_len[lpClient->lpDevice->clients[client_index].ring_in] = pcm_buffer_size;
-                                        lpClient->lpDevice->clients[client_index].ring_in = next_ring;
-                                        pcm_buffer = NULL;
+                                        pthread_mutex_unlock(&lpClient->lpDevice->clients[client_index].mutex);
+
+                                        // Reintegrate data in pool
+                                        if(pcm_buffer) pool_push(pcm_buffer);
                                 }
                                 else
                                 {
-                                        //printf("Client thread %d.%d ring is full (ring_in=%d, next_ring=%d, ring_out=%d)\n", client_index, lpClient->sockfd, lpClient->lpDevice->clients[client_index].ring_in, next_ring, lpClient->lpDevice->clients[client_index].ring_out);
+                                        printf("[2] Receiving failed on socket %d.%d error (%d/%d bytes)\n", client_index, lpClient->sockfd, result, pcm_buffer_size);
+                                        bError = 1;
                                 }
-
-                                pthread_mutex_unlock(&lpClient->lpDevice->clients[client_index].mutex);
-
-                                // Reintegrate data in pool
-                                if(pcm_buffer) pool_push(pcm_buffer);
                         }
                         else
                         {
-                                printf("[2] Receiving failed on socket %d.%d error (%d/%d bytes)\n", client_index, lpClient->sockfd, result, pcm_buffer_size);
+                                if(result==sizeof(pcm_buffer_size))
+                                {
+                                        printf("[1] Receiving will not fit pool (poolentrysize=%d != pcm_buffer_size=%d)\n", POOLENTRYSIZE, pcm_buffer_size);
+                                }
+                                else
+                                {
+                                        printf("[1] Receiving failed on socket %d.%d error (%d/%d bytes) errno=%d:%s\n", client_index, lpClient->sockfd, result, sizeof(pcm_buffer_size), errno, strerror(errno));
+                                }
                                 bError = 1;
                         }
                 }
-                else
-                {
-                        if(result==sizeof(pcm_buffer_size))
-                        {
-                                printf("[1] Receiving will not fit pool (poolentrysize=%d != pcm_buffer_size=%d)\n", POOLENTRYSIZE, pcm_buffer_size);
-                        }
-                        else
-                        {
-                                printf("[1] Receiving failed on socket %d.%d error (%d/%d bytes) \n", client_index, lpClient->sockfd, result, sizeof(pcm_buffer_size));
-                        }
-                        bError = 1;
-                }
-        }
 
-        // Close socket
-        printf("Client thread %d.%d ending %s error\n", client_index, lpClient->sockfd, bError?"with":"without");
-        close(lpClient->sockfd);
+                pthread_mutex_lock(&lpClient->lpDevice->mutex);
+                if(client_index>=0) lpClient->lpDevice->clients[client_index].lives=0;
+                pthread_mutex_unlock(&lpClient->lpDevice->mutex);
+        }
 
         // Say goodbye
-
         pthread_mutex_lock(&lpClient->lpDevice->mutex);
-        if(client_index>=0) lpClient->lpDevice->clients[client_index].lives=0;
         lpClient->lpDevice->nb_clients--;
         pthread_mutex_unlock(&lpClient->lpDevice->mutex);
 
+        // Close socket
+        printf("Client thread %d.%d ending: %s\n", client_index, lpClient->sockfd, (bError?(errno==EAGAIN?"timeout":"error"):"no error"));
+        close_socket(lpClient->sockfd);
+
         // Free client data
         free(lpClient);
 
@@ -332,28 +321,32 @@
         {
                 int bError = 0;
                 int destroy_count = 0;
+                int satured = 0;
+                int ibytespersecond = 0;
+
                 // Connect to the A2DP device
                 LPA2DP lpA2dp = NULL;
                 char* pcm_buffer = pool_pop();
                 enum { NOSOUND, SOUND };
                 int state_previous = NOSOUND;
-
+                TIMERINFO TimerInfos;
+                memset(&TimerInfos, 0, sizeof(TimerInfos));
+                TimerInfos.fps = A2DPD_BLOCK_FREQUENCY;
                 printf("New connection to bluetooth\n");
 
                 // As long as we can send sound
                 while(!bSigINTReceived && !bError)
                 {
-                        static int ibytespersecond = 0;
                         int pcm_buffer_filed_size = 0;
-                        int sleepDelay = 1000;
                         char* pcm_buffers[MAXCLIENTSPERDEVICE];
                         int pcm_buffers_size[MAXCLIENTSPERDEVICE];
-                        int  state_current = NOSOUND;
+                        int state_current = NOSOUND;
                         memset(pcm_buffers,      0, sizeof(pcm_buffers));
                         memset(pcm_buffers_size, 0, sizeof(pcm_buffers_size));
 
                         // If there are BT data, send them
-                        //FIXME pthread_mutex_lock(&lpDevice->mutex);
+                        //FIXME 
+                        // pthread_mutex_lock(&lpDevice->mutex);
 
                         if(lpDevice->nb_clients>0)
                         {
@@ -372,7 +365,7 @@
                                                         // Tell client we got them
                                                         lpDevice->clients[i].ring[lpDevice->clients[i].ring_out] = NULL;
                                                         lpDevice->clients[i].ring_len[lpDevice->clients[i].ring_out] = 0;
-                                                        
+
                                                         // Move to next ring
                                                         int next_ring = ((lpDevice->clients[i].ring_out+1)%MAXCLIENTSRINGSIZE);
                                                         
@@ -388,32 +381,8 @@
                                         }
                                 }
                         }
-                        //FIXME pthread_mutex_unlock(&lpDevice->mutex);
-
-                        // Display some informations while running
-                        static int iframespersecond = 0;
-                        static struct timeval staticcounter = { 0, 0 };
-                        if(staticcounter.tv_usec==0 && staticcounter.tv_sec==0)
-                                gettimeofday(&staticcounter, NULL);
-                        
-                        // Calculate interval
-                        struct timeval timeofday, duration;
-                        gettimeofday(&timeofday, NULL);
-                        timersub(&timeofday, &staticcounter, &duration);
-                        
-                        // Display infos each second 
-                        if(duration.tv_sec>0)
-                        {
-                                printf("A2DPD: state=%s %s clients=%d freq=%d[%d ko/s]\n", (state_current==SOUND)?"playing":"silent", lpA2dp?"connected":"disconnected", lpDevice->nb_clients, iframespersecond, ibytespersecond);
-                                
-                                // Reset all variables used
-                                ibytespersecond=0;
-                                iframespersecond=0;
-                                gettimeofday(&staticcounter, NULL);
-                        }
-                        
-                        // Count this frame
-                        iframespersecond++;
+                        //FIXME 
+                        // pthread_mutex_unlock(&lpDevice->mutex);
 
                         // Send mixed audio stream to clients
                         switch(state_current)
@@ -421,41 +390,6 @@
                                 case SOUND:
                                 {
                                         /////////////////////////////////
-                                        // Try to synchronize sound to a 344blocks/s
-                                        /////////////////////////////////
-                                        struct timeval playtime, theoricaldate;
-                                
-                                        // sleeps a little bit to synchronize sound
-                                        // a2dp->sbc.channels*44100*2/(size*a2dp->frame_bytes);
-                                        // 344.53125=channels*freq*16 bits/sizeof(buf)
-                                        float fps=344.53125;
-                                        playtime.tv_sec=0;
-                                        playtime.tv_usec=(int)(1.0*1000.0*1000.0*iframespersecond/fps);
-                                        timeradd(&staticcounter, &playtime, &theoricaldate);
-                                
-                                        // Si la date théorique est supérieure à la date actuelle
-                                        if((theoricaldate.tv_sec>timeofday.tv_sec)
-                                                || (theoricaldate.tv_sec==timeofday.tv_sec && theoricaldate.tv_usec>timeofday.tv_usec)
-                                                )
-                                        {
-                                                // We're in advance, wait a little bit
-                                                timersub(&theoricaldate, &timeofday, &duration);
-                                                if(duration.tv_sec>0)
-                                                {
-                                                        printf("ERROR duration calculed more than one sec : { %d, %d }", (int)duration.tv_sec, (int)duration.tv_usec);
-                                                }
-                                                else
-                                                {
-                                                        sleepDelay = duration.tv_usec;
-                                                }
-                                        }
-                                        else
-                                        {
-                                                // We're late, do nothing
-                                                sleepDelay=0;
-                                        }
-
-                                        /////////////////////////////////
                                         // Mix what we got
                                         /////////////////////////////////
 
@@ -484,14 +418,25 @@
                                                 }
                                                 //printf("Value %08X|%08X %d|%d\n", channel_1, channel_2, channel_1, channel_2);
                                                 // Stay within 16 bits per channel range
-                                                if(channel_1>+32767) channel_1 = +32767;
-                                                if(channel_1<-32768) channel_1 = -32768;
-                                                if(channel_2>+32767) channel_2 = +32767;
-                                                if(channel_2<-32768) channel_2 = -32768;
+                                                if(channel_1>+32767) { channel_1 = +32767; satured++; }
+                                                if(channel_1<-32768) { channel_1 = -32768; satured++; }
+                                                if(channel_2>+32767) { channel_2 = +32767; satured++; }
+                                                if(channel_2<-32768) { channel_2 = -32768; satured++; }
+                                                
+                                                channel_1 *= lpDevice->mixer.volume_speaker_left;
+                                                channel_2 *= lpDevice->mixer.volume_speaker_right;
+                                                // yes this can be rewritten with << if we consider max volume of 2^x
+                                                // Isn't it already done by compiler
+                                                channel_1 /= A2DPD_VOLUME_MAX;
+                                                channel_2 /= A2DPD_VOLUME_MAX;
                                                 pBuffer[j] = (((channel_1&0x0000FFFF)<<16)|(channel_2&0x0000FFFF));
+                                                //FIXME We have a reverse stereo I don't know why
+                                                // The following line corrects the problem but I miss the cause so
+                                                // Do not uncomment it
+                                                //pBuffer[j] = (((channel_2&0x0000FFFF)<<16)|(channel_1&0x0000FFFF));
                                                 //pBuffer[j] = ( (channel_1 & 0xFFFF0000) | (channel_2 & 0x0000FFFF) );
                                         }
-                                        
+
                                         // Free no longer used audio blocks
                                         for(i=0; i<MAXCLIENTSPERDEVICE; i++)
                                         {
@@ -501,17 +446,17 @@
                                                         pool_push(pcm_buffers[i]);
                                                 }
                                         }
-                                        
+
                                         /////////////////////////////////
                                         // Transfer data to bluetooth
                                         /////////////////////////////////
 
                                         if(pcm_buffer && pcm_buffer_filed_size>0)
                                         {
-                                                // Transfer takes place by 512 bytes blocks
+                                                // Transfer takes place by A2DPD_BLOCK_SIZE bytes blocks
                                                 int blockstart = 0;
-                                                int blocksize = 512;
-                                                
+                                                int blocksize = A2DPD_BLOCK_SIZE;
+
                                                 // Allocate A2DP if we are not connected
                                                 if(!lpA2dp)
                                                 {
@@ -526,15 +471,16 @@
                                                         {
                                                                 int transfer;
 
-                                                                blocksize = (pcm_buffer_filed_size<512)?pcm_buffer_filed_size:512;
+                                                                blocksize = (pcm_buffer_filed_size<A2DPD_BLOCK_SIZE)?pcm_buffer_filed_size:A2DPD_BLOCK_SIZE;
 
                                                                 transfer = a2dp_transfer_raw(lpA2dp, pcm_buffer+blockstart, blocksize);
-                                                                
+
                                                                 if(transfer>=0)
                                                                 {
                                                                         destroy_count = 0;
                                                                         blockstart += blocksize;
                                                                         ibytespersecond += transfer;
+                                                                        a2dp_timer_notifyframe(&TimerInfos);
                                                                 }
                                                                 else
                                                                 {
@@ -548,24 +494,51 @@
                                 }
                                 case NOSOUND:
                                 {
+                                        if(state_previous == SOUND)
+                                        {
+                                                //printf("Sound stream ran dry!!!\n");
+                                        }
                                         break;
                                 }
                         }
 
                         // Free the A2DP device if needed
-                        if(lpA2dp && destroy_count>1000)
+                        // When destroy_count reaches 5000 we will destroy the A2DP link
+                        // However, destroy_count is reset whenever data are sent
+                        destroy_count++;
+                        if(lpA2dp && destroy_count>5000)
                         {
                                 printf("Destroying lpA2dp, destroy_count is %d\n", destroy_count);
                                 a2dp_destroy(lpA2dp);
                                 lpA2dp = NULL;
                         }
 
-                        // When destroy_count reaches 1000 we will destroy the A2DP link
-                        // However, destroy_count is reset whenever data are sent
-                        destroy_count++;
-
-                        if(sleepDelay)
-                                usleep(sleepDelay);
+                        // Wait must take place after sending a packet
+                        // This way, you will allow the plugin to send it's data
+                        // And you will collect the new data
+                        // Time reference floating because of 44100/1000 error in integer calculation
+                        a2dp_timer_sleep(&TimerInfos, A2DPTIMERPREDELAY);
+
+                        // Display infos each second
+                        if(TimerInfos.display>0)
+                        {
+                                /*
+                                char* lpszFormat = "A2DPD: [%d,%d|%d,%d] %s %s clients=%d freq=%d[%d b/s] sleep=%d satur=%d\n";
+                                if(satured==0) lpszFormat = "A2DPD: [%d,%d|%d,%d] %s %s clients=%d freq=%d[%d b/s]\n";
+                                printf(lpszFormat, 
+                                lpDevice->mixer.volume_speaker_left,
+                                lpDevice->mixer.volume_speaker_right,
+                                lpDevice->mixer.volume_micro_left,
+                                lpDevice->mixer.volume_micro_right,
+                                (state_current==SOUND)?"playing":"silent",
+                                lpA2dp?"connected":"disconnected", lpDevice->nb_clients, TimerInfos.display,
+                                ibytespersecond,
+                                satured);
+                                // Reset all variables used
+                                ibytespersecond=0;
+                                satured=0;
+                                */
+                        }
 
                         state_previous = state_current;
                 }
@@ -618,11 +591,7 @@
 
                                 printf("socket %d: Connection from %s, mtu=%d\n", new_fd, szRemote, iMTU);
 
-                                struct timeval t;
-                                t.tv_sec=0;
-                                t.tv_usec=10*1000; // ms
-                                setsockopt( new_fd, SOL_SOCKET, SO_SNDTIMEO, &t, sizeof(t));
-                                setsockopt( new_fd, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(t));
+                                setup_socket(new_fd);
 
                                 if(new_fd>0)
                                 {
@@ -656,7 +625,7 @@
                                                 while(iReceived>=0 || errno==EAGAIN);
                                                 free(lpFrame);
                                         }
-                                        close(new_fd);
+                                        close_socket(new_fd);
                                 }
                                 else
                                 {
@@ -664,7 +633,7 @@
                                 }
                         }
 
-                        close(sockfd);
+                        close_socket(sockfd);
                 }
 
                 // Sleep a little bit if we must retry
@@ -679,67 +648,73 @@
 // server processing loop
 void main_loop(char* addr)
 {
-        // Master socket
-        int sockfd = make_the_socket();
-
-        if(sockfd>0)
+        while(!bSigINTReceived)
         {
-                LPBTA2DPPERDEVICEDATA lpDevice = bta2dpdevicenew(addr);
-                // Set pthread stack size to decrease unused memory usage
-                pthread_attr_t tattr;
-                size_t size = PTHREAD_STACK_MIN;
-                int ret = pthread_attr_init(&tattr);
-                ret = pthread_attr_setstacksize(&tattr, size);
-                pthread_create(&lpDevice->thread, &tattr, bt_handler,  lpDevice);
-                pthread_create(&lpDevice->thread, &tattr, bt_receiver, lpDevice);
-
-                while(!bSigINTReceived)
-                {
-                        // Block until connections
-                        struct sockaddr_in peer_addr;
-                        int sin_size = sizeof(peer_addr);
-                        printf("Accepting incoming stream connection\n");
-                        int new_fd = accept(sockfd, (struct sockaddr *)&peer_addr, &sin_size);
-                        printf("Accepted %d\n", new_fd);
-
-                        // Handle connection if it is not the final dummy client
-                        if(!bSigINTReceived)
+                // Master socket
+                int sockfd = make_server_socket();
+        
+                if(sockfd>0)
+                {
+                        LPBTA2DPPERDEVICEDATA lpDevice = bta2dpdevicenew(addr);
+                        // Set pthread stack size to decrease unused memory usage
+                        pthread_attr_t tattr;
+                        size_t size = PTHREAD_STACK_MIN;
+                        int ret = pthread_attr_init(&tattr);
+                        ret = pthread_attr_setstacksize(&tattr, size);
+                        pthread_create(&lpDevice->thread, &tattr, bt_handler,  lpDevice);
+                        pthread_create(&lpDevice->thread, &tattr, bt_receiver, lpDevice);
+        
+                        while(!bSigINTReceived)
                         {
-                                LPA2DPDCLIENT lpClient = malloc(sizeof(A2DPDCLIENT));
-                                lpClient->lpDevice = lpDevice;
-                                lpClient->sockfd = new_fd;
-                                
-                                pthread_mutex_lock(&lpClient->lpDevice->mutex);
-                                lpClient->lpDevice->nb_clients++;
-                                pthread_mutex_unlock(&lpClient->lpDevice->mutex);
-                                
-                                pthread_create(&lpClient->thread, &tattr, client_handler, lpClient);
+                                int new_fd = -1;
+                                printf("Accepting incoming stream connection\n");
+                                new_fd=accept_socket(sockfd);
+                                printf("Accepted %d\n", new_fd);
+        
+                                // Handle connection if it is not the final dummy client
+                                if(!bSigINTReceived)
+                                {
+                                        LPA2DPDCLIENT lpClient = malloc(sizeof(A2DPDCLIENT));
+                                        lpClient->lpDevice = lpDevice;
+                                        lpClient->sockfd = new_fd;
+                                        
+                                        pthread_mutex_lock(&lpClient->lpDevice->mutex);
+                                        lpClient->lpDevice->nb_clients++;
+                                        pthread_mutex_unlock(&lpClient->lpDevice->mutex);
+                                        
+                                        pthread_create(&lpClient->thread, &tattr, client_handler, lpClient);
+                                }
+                                else
+                                {
+                                        close_socket(new_fd);
+                                }
+                                usleep(10000);
                         }
-                        usleep(10000);
+        
+                        close_socket(sockfd);
+        
+                        // Very minor race condition here
+                        // No dramatic consequences
+                        // But we Must wait all client termination
+                        // We will pthread_join one day
+                        int icount = 0;
+                        while(iThreadsRunning>0 && icount<30)
+                        {
+                                printf("A2DPD still %d clients running\n", iThreadsRunning);
+                                icount++;
+                                sleep(1);
+                        }
+        
+                        // Free informations on the device
+                        bta2dpdevicefree(lpDevice);
+                        pthread_attr_destroy(&tattr);
                 }
-
-                close(sockfd);
-                close(sockfd);
-
-                // Very minor race condition here
-                // No dramatic consequences
-                // But we Must wait all client termination
-                // We will pthread_join one day
-                int icount = 0;
-                while(iThreadsRunning>0 && icount<30)
+                else
                 {
-                        printf("A2DPD still %d clients running\n", iThreadsRunning);
-                        icount++;
-                        sleep(1);
+                        printf("Error %d: cannot get the socket errno=%d (%s)\n", sockfd, errno, strerror(errno));
                 }
 
-                // Free informations on the device
-                bta2dpdevicefree(lpDevice);
-                pthread_attr_destroy(&tattr);
-        }
-        else
-        {
-                printf("Error %d: cannot get the socket errno=%d (%s)\n", sockfd, errno, strerror(errno));
+                sleep(1);
         }
 }
 
@@ -748,12 +723,38 @@
 // main function
 int main(int argc, char *argv[])
 {
-        char* addr = "00:0D:44:2A:17:C7 [Default Address]";
-        
-        // Read command line argument
-        if(argc>1) addr = argv[1];
-        printf("%s addr=%s [%s %s]\n", argv[0], addr, __DATE__, __TIME__);
-
+        int i = 0;
+        struct timespec timer_resolution = { 0, 0 };
+        char* addr = "00:0A:56:00:C0:C2 Sonorix";
+        // C2:00:08:F4:30:07:64 IPhono
+        // 00:0D:44:2A:17:C7 HP
+        // If we can be realtime it will be better
+        struct sched_param schedparam = { sched_get_priority_max(SCHED_FIFO) };
+        int res = sched_setscheduler(0, SCHED_FIFO, &schedparam); 
+        int bTestThread = 0;
+        printf("setscheduler returns %d (errno=%d:%s)\n", res, errno, strerror(errno));
+	
+	// Parse command line parameters
+	for(i=1; i<argc && argv[i]!=NULL; i++)
+	{
+	       char c;
+	       // Search a glade file
+	       if(0==strcmp(argv[i], "-t"))
+	       {
+	               bTestThread = 1;
+	       }
+	       // Search a bluetooth addr
+	       else if(sscanf(argv[i], "%c%c:%c%c:%c%c:%c%c:%c%c:%c%c", &c, &c, &c, &c, &c, &c, &c, &c, &c, &c, &c, &c)==12)
+	       {
+	               addr=argv[i];
+	       }
+	       else
+	       {
+	               printf("Parameter not handled: %s\r\n", argv[i]);
+	       }
+	}
+        clock_getres(CLOCK_REALTIME, &timer_resolution);
+        printf("%s addr=%s timer=%d us [%s %s]\n", argv[0], addr, (int)(timer_resolution.tv_nsec/1000), __DATE__, __TIME__);
         // set up the handler
         signal(SIGINT, sigint_handler);
         signal(SIGTERM, sigint_handler);
Index: alsa-plugins/a2dpd_protocol.h
===================================================================
RCS file: alsa-plugins/a2dpd_protocol.h
diff -N alsa-plugins/a2dpd_protocol.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ alsa-plugins/a2dpd_protocol.h	28 Jul 2006 09:48:08 -0000
@@ -0,0 +1,54 @@
+/*
+*
+*  A2DPD - Bluetooth A2DP daemon for Linux
+*
+*  Copyright (C) 2006  Frédéric DALLEAU <frederic.dalleau@palmsource.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.
+*/
+
+#ifndef __A2DPD_PROTOCOL_H__
+#define __A2DPD_PROTOCOL_H__
+
+#include <stdint.h>
+
+
+// parameters used to describe device state
+typedef struct
+{
+        int16_t                     volume_speaker_right;
+        int16_t                     volume_speaker_left;
+        int16_t                     volume_micro_right;
+        int16_t                     volume_micro_left;
+} AUDIOMIXERDATA;
+
+#define INVALIDAUDIOMIXERDATA   { -1, -1, -1, -1 }
+
+// Different types of client plugin for the daemon
+#define INVALID_CLIENT_TYPE     0xFFFFFFFF
+#define A2DPD_PLUGIN_CTL_WRITE  0x00000001
+#define A2DPD_PLUGIN_CTL_READ   0x00000002
+#define A2DPD_PLUGIN_PCM_WRITE  0x00000003
+#define A2DPD_VOLUME_MIN        0
+#define A2DPD_VOLUME_MAX        15
+
+// a2dp->sbc.channels*44100*2/(size*a2dp->frame_bytes);
+// 344.53125=channels*freq*16 bits/sizeof(buf)
+#define A2DPD_BLOCK_FREQUENCY   (344.53125/1)
+#define A2DPD_BLOCK_SIZE        (512*1)
+#define A2DPD_FRAME_BYTES       4 // 16bits * 2 channels
+#define A2DPD_FRAME_RATE        44100
+
+#endif
Index: alsa-plugins/a2dplib.c
===================================================================
RCS file: /cvsroot/bluetooth-alsa/btsco/alsa-plugins/a2dplib.c,v
retrieving revision 1.1
diff -u -r1.1 a2dplib.c
--- alsa-plugins/a2dplib.c	12 Jul 2006 05:47:06 -0000	1.1
+++ alsa-plugins/a2dplib.c	28 Jul 2006 09:48:08 -0000
@@ -1,25 +1,25 @@
 /*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2004-2005  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
+*
+*  BlueZ - Bluetooth protocol stack for Linux
+*
+*  Copyright (C) 2004-2005  Marcel Holtmann <marcel@holtmann.org>
+*
+*
+*  This library is free software; you can redistribute it and/or
+*  modify it under the terms of the GNU Lesser General Public
+*  License as published by the Free Software Foundation; either
+*  version 2.1 of the License, or (at your option) any later version.
+*
+*  This library 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
+*  Lesser General Public License for more details.
+*
+*  You should have received a copy of the GNU Lesser General Public
+*  License along with this library; if not, write to the Free Software
+*  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*
+*/
 
 #ifdef HAVE_CONFIG_H
 #include <config.h>
@@ -45,16 +45,27 @@
 
 #include <pthread.h>
 
+
 #include "a2dplib.h"
+#include "a2dp_timer.h"
+#include "a2dp_ipc.h"
 #include "sbc.h"
 #include "../a2dp.h"
 
 #define NONSPECAUDIO 1
 #define BUFS 1024
+#define A2DPMAXIMUMTRANSFERUNITSIZE 678
+// In fact sbc blocks are 76 bytes long, so a group of them is either 608 or 684 bytes
+// So 650 or 678 makes no differences!
+// However some devices may have longer transfer unit up to I saw omtu=733?
 
 #define min(X, Y)  ((X) < (Y) ? (X) : (Y))
-#define DBG(fmt, arg...)  printf("DEBUG: %s: " fmt "\n" , __FUNCTION__ , ## arg)
+#define DBG(fmt, arg...) { if(errno!=0) printf("DEBUG: %s: (errno=%d:%s)" fmt "\n" , __FUNCTION__ , errno, strerror(errno), ## arg);\
+        else printf("DEBUG: %s: " fmt "\n" , __FUNCTION__ , ## arg); errno=0;}
+
+//#define DBG(fmt, arg...)  printf("DEBUG: %s: " fmt "\n" , __FUNCTION__ , ## arg)
 //#define DBG(D...)
+
 /*
 sdp_record_t*  g_recordP     = NULL;
 sdp_session_t* g_sdpSessionP = NULL;
@@ -69,74 +80,74 @@
 /*
 sdp_record_t* a2dp_advertise_sdp(sdp_session_t* sdpSessionP)
 {
-	sdp_record_t *recordP=NULL;
-	sdp_list_t *svclass=NULL, *rootlist=NULL, *protolist=NULL, *l2caplist=NULL, *avdtplist=NULL, *profileslist=NULL;
-	uuid_t rootuuid, svcuuid, l2capuuid, avdtpuuid;
-	sdp_profile_desc_t a2dpprofile;
-	int error = 0;
-
-	if(sdpSessionP)
-	{
-		// Generic service informations
-		recordP = sdp_record_alloc();
-		if (recordP)
-		{
-			sdp_set_info_attr(recordP, A2DP_SERVICE_NAME, NULL, NULL);
-
-			// Add to Public Browse Group
-			sdp_uuid16_create(&rootuuid, PUBLIC_BROWSE_GROUP);
-			rootlist = sdp_list_append(NULL, &rootuuid);
-			sdp_set_browse_groups(recordP, rootlist);
-
-			// Set service class
-			sdp_uuid16_create(&svcuuid, AUDIO_SOURCE_SVCLASS_ID);
-			svclass = sdp_list_append(NULL, &svcuuid);
-			sdp_set_service_classes(recordP, svclass);
-
-			// Set protocols informations
-			// L2CAP
-			sdp_uuid16_create(&l2capuuid, L2CAP_UUID);
-			l2caplist = sdp_list_append(NULL, &l2capuuid);
-
-			// AVDTP
-			sdp_uuid16_create(&avdtpuuid, AVDTP_UUID);
-			avdtplist = sdp_list_append(NULL, &avdtpuuid);
-
-			// add protocols
-			protolist = sdp_list_append(NULL, l2caplist);
-			sdp_list_append(protolist, avdtplist);
-			protolist = sdp_list_append(NULL, protolist);
-			sdp_set_access_protos(recordP, protolist);
-
-			// Set profiles informations
-			// A2DP
-			sdp_uuid16_create(&a2dpprofile.uuid, AUDIO_SOURCE_PROFILE_ID);
-			a2dpprofile.version = A2DP_VERSION;
-			profileslist = sdp_list_append(NULL, &a2dpprofile);
-
-			// add profiles
-			sdp_set_profile_descs(recordP, profileslist);
-
-			// Register the record in the sdp session
-			error = sdp_record_register(sdpSessionP, recordP, 0);
-			if (error)
-			{
-				DBG("Unable to advertise service (0x%04hX)", error);
-				sdp_record_free(recordP);
-				recordP = NULL;
-			}
-		}
-		else
-		{
-			DBG("Allocate for service description failed");
-		}
-	}
-	else
-	{
-		DBG("No local sdp session available");
-	}
+        sdp_record_t *recordP=NULL;
+        sdp_list_t *svclass=NULL, *rootlist=NULL, *protolist=NULL, *l2caplist=NULL, *avdtplist=NULL, *profileslist=NULL;
+        uuid_t rootuuid, svcuuid, l2capuuid, avdtpuuid;
+        sdp_profile_desc_t a2dpprofile;
+        int error = 0;
+
+        if(sdpSessionP)
+        {
+                // Generic service informations
+                recordP = sdp_record_alloc();
+                if (recordP)
+                {
+                        sdp_set_info_attr(recordP, A2DP_SERVICE_NAME, NULL, NULL);
+
+                        // Add to Public Browse Group
+                        sdp_uuid16_create(&rootuuid, PUBLIC_BROWSE_GROUP);
+                        rootlist = sdp_list_append(NULL, &rootuuid);
+                        sdp_set_browse_groups(recordP, rootlist);
+
+                        // Set service class
+                        sdp_uuid16_create(&svcuuid, AUDIO_SOURCE_SVCLASS_ID);
+                        svclass = sdp_list_append(NULL, &svcuuid);
+                        sdp_set_service_classes(recordP, svclass);
+
+                        // Set protocols informations
+                        // L2CAP
+                        sdp_uuid16_create(&l2capuuid, L2CAP_UUID);
+                        l2caplist = sdp_list_append(NULL, &l2capuuid);
+
+                        // AVDTP
+                        sdp_uuid16_create(&avdtpuuid, AVDTP_UUID);
+                        avdtplist = sdp_list_append(NULL, &avdtpuuid);
+
+                        // add protocols
+                        protolist = sdp_list_append(NULL, l2caplist);
+                        sdp_list_append(protolist, avdtplist);
+                        protolist = sdp_list_append(NULL, protolist);
+                        sdp_set_access_protos(recordP, protolist);
+
+                        // Set profiles informations
+                        // A2DP
+                        sdp_uuid16_create(&a2dpprofile.uuid, AUDIO_SOURCE_PROFILE_ID);
+                        a2dpprofile.version = A2DP_VERSION;
+                        profileslist = sdp_list_append(NULL, &a2dpprofile);
+
+                        // add profiles
+                        sdp_set_profile_descs(recordP, profileslist);
+
+                        // Register the record in the sdp session
+                        error = sdp_record_register(sdpSessionP, recordP, 0);
+                        if (error)
+                        {
+                                DBG("Unable to advertise service (0x%04hX)", error);
+                                sdp_record_free(recordP);
+                                recordP = NULL;
+                        }
+                }
+                else
+                {
+                        DBG("Allocate for service description failed");
+                }
+        }
+        else
+        {
+                DBG("No local sdp session available");
+        }
 
-	return recordP;
+        return recordP;
 }
 */
 
@@ -144,777 +155,578 @@
 void a2dp_init(void) __attribute__ ((constructor));
 void a2dp_exit(void) __attribute__ ((destructor));
 */
-void change_endian( void *buf, int size)
+void memcpy_changeendian( void* dst, const void *src, int size)
 {
-	int i;
-	char c;
-	char *ptr;
-
-	ptr = buf;
-	for(i = 0; i < size; i += 2) {
-		c = ptr[i];
-		ptr[i] = ptr[i+1];
-		ptr[i+1] = c;
-	}
+        int i;
+        uint16_t* ptrsrc=src;
+        uint16_t* ptrdst=dst;
+        for(i = 0; i < size/2; i ++)
+        {
+                *ptrdst++ = htons(*ptrsrc++);
+        }
 }
 
 // Prepare packet headers
 void init_request(struct avdtp_header * header, int request_id)
 {
-	static int transaction = 0;
+        static int transaction = 0;
 
-	header->packet_type = PACKET_TYPE_SINGLE;
-	header->message_type = MESSAGE_TYPE_COMMAND;
-	header->transaction_label = transaction;
-	header->signal_id = request_id;
+        header->packet_type = PACKET_TYPE_SINGLE;
+        header->message_type = MESSAGE_TYPE_COMMAND;
+        header->transaction_label = transaction;
+        header->signal_id = request_id;
 
-	// clear rfa bits
-	header->rfa0 = 0;
+        // clear rfa bits
+        header->rfa0 = 0;
 
-	transaction = (transaction + 1) & 0xf;
+        transaction = (transaction + 1) & 0xf;
 }
 
 // Analyse the SEIDs the sink has sent to us
 int process_seid(int s, struct acp_seid_info * get_seid_resp, unsigned short *psm, sbc_t *sbc)
 {
-	int v, size;
-	int seid = get_seid_resp->acp_seid;
-	struct getcap_req put_req;
-	struct getcap_resp cap_resp;
-	struct set_config s_config;
-	struct set_config_resp s_resp;
-	struct stream_cmd open_stream;
-	struct open_stream_rsp open_resp;
-	DBG("Begin");
-	DBG("SEID = %d", seid);
-
-	memset(&put_req, 0, sizeof(put_req));
-	init_request(&put_req.header, AVDTP_GET_CAPABILITIES);
-	put_req.acp_seid = seid;
-
-	if (write(s, &put_req, sizeof(put_req)) != sizeof(put_req)) {
-		DBG("Couldn't request capabilities for SEID = %d", seid);
-		return (-1);
-	}
-	else {
-		DBG("Requested Capabilities for SEID = %d",seid);
-	}
-	if (read(s, &cap_resp, sizeof(cap_resp)) < sizeof(cap_resp) ||
-			cap_resp.header.message_type == MESSAGE_TYPE_REJECT ||
-			cap_resp.media_type != AUDIO_MEDIA_TYPE ||
-			cap_resp.media_codec_type != SBC_MEDIA_CODEC_TYPE) {
-		DBG("Didn't receive SBC codec parameters (first) for SEID = %d", seid);
-		return (-1);
-	}
-
-	DBG("Got capabilities response");
-
-	memset(&s_config, 0, sizeof(s_config));
-	init_request(&s_config.header, AVDTP_SET_CONFIGURATION);
-	s_config.serv_cap = MEDIA_TRANSPORT_CATEGORY;
-	s_config.acp_seid = seid;
-	s_config.int_seid = 1;	// how should I choose the int_seid??
-	s_config.cap_type = MEDIA_CODEC;
-	s_config.length = 6;
-	s_config.media_type = AUDIO_MEDIA_TYPE;
-	s_config.media_codec_type = SBC_MEDIA_CODEC_TYPE;
-
-	switch(sbc->channels) {
-	case 1:
-		v = 8;
-		break;
-	case 2:
-	default:
-		v = 2;
-		break;
-	}
-	s_config.codec_elements.sbc_elements.channel_mode = v;
-
-	switch(sbc->rate) {
-	case 16000:
-		v = 8;
-		break;
-	case 32000:
-		v = 4;
-		break;
-	case 48000:
-		v = 1;
-		break;
-	case 44100:
-	default:
-		v = 2; 
-		break;
-	}
-	s_config.codec_elements.sbc_elements.frequency = v;
-	s_config.codec_elements.sbc_elements.allocation_method = 1 << 1;
-
-	switch(sbc->subbands) {
-	case 4:
-		v = 2;
-		break;
-	case 8:
-	default:
-		v = 1;
-		break;
-	}
-	s_config.codec_elements.sbc_elements.subbands = v;
-
-	switch(sbc->blocks) {
-	case 4:
-		v = 8;
-		break;
-	case 8:
-		v = 4;
-		break;
-	case 12:
-		v = 2;
-		break;
-	case 16:
-	default:
-		v = 1;
-		break;
-	}
-	s_config.codec_elements.sbc_elements.block_length = v;
-	s_config.codec_elements.sbc_elements.min_bitpool = cap_resp.codec_elements.sbc_elements.min_bitpool;
-	s_config.codec_elements.sbc_elements.max_bitpool = cap_resp.codec_elements.sbc_elements.max_bitpool;
-
-	if (!(cap_resp.codec_elements.sbc_elements.channel_mode & s_config.codec_elements.sbc_elements.channel_mode)) {
-		DBG("headset does not support this channel mode");
-	}
-
-	if (!(cap_resp.codec_elements.sbc_elements.frequency & s_config.codec_elements.sbc_elements.frequency)) {
-		DBG("headset does not support this frequency");
-	}
-
-	if (!(cap_resp.codec_elements.sbc_elements.allocation_method & s_config.codec_elements.sbc_elements.allocation_method)) {
-		DBG("headset does not support this allocation_method");
-	}
-
-	if (!(cap_resp.codec_elements.sbc_elements.subbands & s_config.codec_elements.sbc_elements.subbands)) {
-		DBG("headset does not support this subbands setting");
-	}
-
-	if (write(s, &s_config, sizeof(s_config)) != sizeof(s_config)) {
-		DBG("couldn't set config seid = %d", seid);
-		return (-1);
-	}
-
-	DBG("Sent set configurations command");
-	
-	size = read(s, &s_resp, sizeof(s_resp));
-	if (size == sizeof(s_resp) - 2) {
-		DBG("Set configurations command accepted");
-	} else {
-		DBG("Set configurations command rejected");
-	}
-	
-	memset(&open_stream, 0, sizeof(open_stream));
-	init_request(&open_stream.header, AVDTP_OPEN);
-	open_stream.acp_seid = seid;
-
-	if (write(s, &open_stream, sizeof(open_stream)) != sizeof(open_stream)) {
-		DBG("Couldn't open stream SEID = %d", seid);
-		return (-1);
-	}
-
-	DBG("Sent open stream command");
-
-	if (read(s, &open_resp, sizeof(open_resp)) < sizeof(open_resp) - 1 ||
-			open_resp.header.message_type == MESSAGE_TYPE_REJECT) {
-		DBG("Didn't receive open response confirm for SEID = %d", seid);
-		return (-1);
-	}
+        int v, size;
+        int seid = get_seid_resp->acp_seid;
+        struct getcap_req put_req;
+        struct getcap_resp cap_resp;
+        struct set_config s_config;
+        struct set_config_resp s_resp;
+        struct stream_cmd open_stream;
+        struct open_stream_rsp open_resp;
+        DBG("Begin SEID = %d", seid);
+
+        memset(&put_req, 0, sizeof(put_req));
+        init_request(&put_req.header, AVDTP_GET_CAPABILITIES);
+        put_req.acp_seid = seid;
+
+        if (write(s, &put_req, sizeof(put_req)) != sizeof(put_req)) {
+                DBG("Couldn't request capabilities for SEID = %d", seid);
+                return (-1);
+        }
+        else {
+                DBG("Requested Capabilities for SEID = %d",seid);
+        }
+        if (read(s, &cap_resp, sizeof(cap_resp)) < sizeof(cap_resp) ||
+                        cap_resp.header.message_type == MESSAGE_TYPE_REJECT ||
+                        cap_resp.media_type != AUDIO_MEDIA_TYPE ||
+                        cap_resp.media_codec_type != SBC_MEDIA_CODEC_TYPE) {
+                DBG("Didn't receive SBC codec parameters (first) for SEID = %d", seid);
+                return (-1);
+        }
+
+        DBG("Got capabilities response");
+
+        memset(&s_config, 0, sizeof(s_config));
+        init_request(&s_config.header, AVDTP_SET_CONFIGURATION);
+        s_config.serv_cap = MEDIA_TRANSPORT_CATEGORY;
+        s_config.acp_seid = seid;
+        s_config.int_seid = 1;	// how should I choose the int_seid??
+        s_config.cap_type = MEDIA_CODEC;
+        s_config.length = 6;
+        s_config.media_type = AUDIO_MEDIA_TYPE;
+        s_config.media_codec_type = SBC_MEDIA_CODEC_TYPE;
+
+        switch(sbc->channels) {
+        case 1:
+                v = 8;
+                break;
+        case 2:
+        default:
+                v = 2;
+                break;
+        }
+        s_config.codec_elements.sbc_elements.channel_mode = v;
+
+        switch(sbc->rate) {
+        case 16000:
+                v = 8;
+                break;
+        case 32000:
+                v = 4;
+                break;
+        case 48000:
+                v = 1;
+                break;
+        case 44100:
+        default:
+                v = 2; 
+                break;
+        }
+        s_config.codec_elements.sbc_elements.frequency = v;
+        s_config.codec_elements.sbc_elements.allocation_method = 1 << 1;
+
+        switch(sbc->subbands) {
+        case 4:
+                v = 2;
+                break;
+        case 8:
+        default:
+                v = 1;
+                break;
+        }
+        s_config.codec_elements.sbc_elements.subbands = v;
+
+        switch(sbc->blocks) {
+        case 4:
+                v = 8;
+                break;
+        case 8:
+                v = 4;
+                break;
+        case 12:
+                v = 2;
+                break;
+        case 16:
+        default:
+                v = 1;
+                break;
+        }
+        s_config.codec_elements.sbc_elements.block_length = v;
+        s_config.codec_elements.sbc_elements.min_bitpool = cap_resp.codec_elements.sbc_elements.min_bitpool;
+        s_config.codec_elements.sbc_elements.max_bitpool = cap_resp.codec_elements.sbc_elements.max_bitpool;
+
+        if (!(cap_resp.codec_elements.sbc_elements.channel_mode & s_config.codec_elements.sbc_elements.channel_mode)) {
+                DBG("headset does not support this channel mode");
+        }
+
+        if (!(cap_resp.codec_elements.sbc_elements.frequency & s_config.codec_elements.sbc_elements.frequency)) {
+                DBG("headset does not support this frequency");
+        }
 
-	DBG("Got open stream confirm");
+        if (!(cap_resp.codec_elements.sbc_elements.allocation_method & s_config.codec_elements.sbc_elements.allocation_method)) {
+                DBG("headset does not support this allocation_method");
+        }
 
-	*psm = 25;
-	return 0;
+        if (!(cap_resp.codec_elements.sbc_elements.subbands & s_config.codec_elements.sbc_elements.subbands)) {
+                DBG("headset does not support this subbands setting");
+        }
+
+        if (write(s, &s_config, sizeof(s_config)) != sizeof(s_config)) {
+                DBG("couldn't set config seid = %d", seid);
+                return (-1);
+        }
+
+        DBG("Sent set configurations command");
+        
+        size = read(s, &s_resp, sizeof(s_resp));
+        if (size == sizeof(s_resp) - 2) {
+                DBG("Set configurations command accepted");
+        } else {
+                DBG("Set configurations command rejected");
+        }
+        
+        memset(&open_stream, 0, sizeof(open_stream));
+        init_request(&open_stream.header, AVDTP_OPEN);
+        open_stream.acp_seid = seid;
+
+        if (write(s, &open_stream, sizeof(open_stream)) != sizeof(open_stream)) {
+                DBG("Couldn't open stream SEID = %d", seid);
+                return (-1);
+        }
+
+        DBG("Sent open stream command");
+
+        if (read(s, &open_resp, sizeof(open_resp)) < sizeof(open_resp) - 1 ||
+                        open_resp.header.message_type == MESSAGE_TYPE_REJECT) {
+                DBG("Didn't receive open response confirm for SEID = %d", seid);
+                return (-1);
+        }
+
+        DBG("Got open stream confirm");
+
+        *psm = 25;
+        return 0;
 
 }
 // Detect whether A2DP Sink is present at the destination or not
 int detect_a2dp(bdaddr_t *src, bdaddr_t *dst, unsigned short *psm, unsigned long *flags)
 {
-	sdp_session_t *sess;
-	sdp_list_t *attrid, *search, *seq, *next;
-	sdp_data_t *pdlist;
-	uuid_t group;
-	uint32_t range = 0x0000ffff;
-	int err;
-	int tries;
-
-	DBG("Begin");
-	tries = 0;
-	while(!(sess = sdp_connect(src, dst, SDP_RETRY_IF_BUSY))) {
-		DBG("retrying sdp connect: %s", strerror(errno));
-		sleep(1);
-		if(++tries > 10) {
-			break;
-		}
-	}
-	if (!sess) {
-		DBG( "Warning: failed to connect to SDP server: %s", strerror(errno));
-		if(psm) *psm = 25;
-		if(flags) *flags = 0;
-		return 0;
-	}
-
-	/* 0x1108->all? 0x1101->rf sink 0x111e->handsfree 0x1108->headset */
-	sdp_uuid16_create(&group, 0x110d);
-	search = sdp_list_append(0, &group);
-	attrid = sdp_list_append(0, &range);
-	err = sdp_service_search_attr_req(sess, search,
-					SDP_ATTR_REQ_RANGE, attrid, &seq);
-	sdp_list_free(search, 0);
-	sdp_list_free(attrid, 0);
-
-	if (err) {
-		DBG( "Service Search failed: %s", strerror(errno));
-		sdp_close(sess);
-		return -1;
-	}
-
-	for (; seq; seq = next) {
-		sdp_record_t *rec = (sdp_record_t *) seq->data;
-
-		DBG( "Found A2DP Sink");
-		if (psm)
-			*psm = 25;
-
-		next = seq->next;
-		free(seq);
-		sdp_record_free(rec);
-	}
-
-	sdp_uuid16_create(&group, PNP_INFO_SVCLASS_ID);
-	search = sdp_list_append(0, &group);
-	attrid = sdp_list_append(0, &range);
-	err = sdp_service_search_attr_req(sess, search,
-					SDP_ATTR_REQ_RANGE, attrid, &seq);
-	sdp_list_free(search, 0);
-	sdp_list_free(attrid, 0);
-
-	if (err)
-		goto done;
-
-	if (flags)
-		*flags = 0;
-
-	for (; seq; seq = next) {
-		sdp_record_t *rec = (sdp_record_t *) seq->data;
-		uint16_t vendor, product, version;
-
-		pdlist = sdp_data_get(rec, 0x0201);
-		vendor = pdlist ? pdlist->val.uint16 : 0x0000;
-
-		pdlist = sdp_data_get(rec, 0x0202);
-		product = pdlist ? pdlist->val.uint16 : 0x0000;
-
-		pdlist = sdp_data_get(rec, 0x0203);
-		version = pdlist ? pdlist->val.uint16 : 0x0000;
-
-		DBG( "Product ID %04x:%04x:%04x", vendor, product, version);
-
-		if (vendor == 0x1310 && product == 0x0100 && version == 0x0104) {
-			DBG( "Enabling GCT media payload workaround");
-			if (flags)
-				*flags |= NONSPECAUDIO;
-		}
-
-		next = seq->next;
-		free(seq);
-		sdp_record_free(rec);
-	}
+        sdp_session_t *sess;
+        sdp_list_t *attrid, *search, *seq, *next;
+        sdp_data_t *pdlist;
+        uuid_t group;
+        uint32_t range = 0x0000ffff;
+        int err;
+        int tries;
+
+        DBG("Begin");
+        tries = 0;
+        while(!(sess = sdp_connect(src, dst, SDP_RETRY_IF_BUSY))) {
+                DBG("retrying sdp connect: %s", strerror(errno));
+                sleep(1);
+                if(++tries > 2) {
+                        break;
+                }
+        }
+        if (!sess) {
+                DBG( "Warning: failed to connect to SDP server: %s", strerror(errno));
+                if(psm) *psm = 25;
+                if(flags) *flags = 0;
+                return 0;
+        }
+
+        /* 0x1108->all? 0x1101->rf sink 0x111e->handsfree 0x1108->headset */
+        sdp_uuid16_create(&group, 0x110d);
+        search = sdp_list_append(0, &group);
+        attrid = sdp_list_append(0, &range);
+        err = sdp_service_search_attr_req(sess, search,
+                                        SDP_ATTR_REQ_RANGE, attrid, &seq);
+        sdp_list_free(search, 0);
+        sdp_list_free(attrid, 0);
+
+        if (err) {
+                DBG( "Service Search failed: %s", strerror(errno));
+                sdp_close(sess);
+                return -1;
+        }
+
+        for (; seq; seq = next) {
+                sdp_record_t *rec = (sdp_record_t *) seq->data;
+
+                DBG( "Found A2DP Sink");
+                if (psm)
+                        *psm = 25;
+
+                next = seq->next;
+                free(seq);
+                sdp_record_free(rec);
+        }
+
+        sdp_uuid16_create(&group, PNP_INFO_SVCLASS_ID);
+        search = sdp_list_append(0, &group);
+        attrid = sdp_list_append(0, &range);
+        err = sdp_service_search_attr_req(sess, search,
+                                        SDP_ATTR_REQ_RANGE, attrid, &seq);
+        sdp_list_free(search, 0);
+        sdp_list_free(attrid, 0);
+
+        if (err)
+                goto done;
+
+        if (flags)
+                *flags = 0;
+
+        for (; seq; seq = next) {
+                sdp_record_t *rec = (sdp_record_t *) seq->data;
+                uint16_t vendor, product, version;
+
+                pdlist = sdp_data_get(rec, 0x0201);
+                vendor = pdlist ? pdlist->val.uint16 : 0x0000;
+
+                pdlist = sdp_data_get(rec, 0x0202);
+                product = pdlist ? pdlist->val.uint16 : 0x0000;
+
+                pdlist = sdp_data_get(rec, 0x0203);
+                version = pdlist ? pdlist->val.uint16 : 0x0000;
+
+                DBG( "Product ID %04x:%04x:%04x", vendor, product, version);
+
+                if (vendor == 0x1310 && product == 0x0100 && version == 0x0104) {
+                        DBG( "Enabling GCT media payload workaround");
+                        if (flags)
+                                *flags |= NONSPECAUDIO;
+                }
+
+                next = seq->next;
+                free(seq);
+                sdp_record_free(rec);
+        }
 
 done:
-	sdp_close(sess);
-	return 0;
+        sdp_close(sess);
+        return 0;
 }
 // Connecting on PSM 25
 int do_connect(bdaddr_t *src, bdaddr_t *dst, unsigned short psm, uint16_t *mtu)
 {
-	struct sockaddr_l2 addr;
-	struct l2cap_options opts;
-	int sk;
-	unsigned int opt;
-	int tries;
-	
-	DBG("Begin");
-	sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
-	if (sk < 0) {
-		DBG( "Can't create socket. %s(%d)",
-			strerror(errno), errno);
-		return -1;
-	}
-
-	DBG( "Connecting to bluetooth");
-
-	memset(&addr, 0, sizeof(addr));
-	addr.l2_family = AF_BLUETOOTH;
-	bacpy(&addr.l2_bdaddr, src);
-	if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		DBG( "Can't bind socket. %s(%d)",
-						strerror(errno), errno);
-		return -1;
-	}
-
-	/* Get default options */
-	opt = sizeof(opts);
-	if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, &opt) < 0) {
-		DBG( "Can't get default L2CAP options. %s(%d)",
-						strerror(errno), errno);
-		return -1;
-	}
-
-	/* Set new options */
-	if(mtu && *mtu) {
-		opts.omtu = *mtu;
-		//opts.imtu = *mtu;
-	}
-	if (setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, opt) < 0) {
-		DBG( "Can't set L2CAP options. %s(%d)",
-						strerror(errno), errno);
-		return -1;
-	}
-
-	memset(&addr, 0, sizeof(addr));
-	addr.l2_family = AF_BLUETOOTH;
-	bacpy(&addr.l2_bdaddr, dst);
-	addr.l2_psm = htobs(psm);
-
-	tries = 0;
-	while (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		DBG("Can't connect to %s on psm %d. %s(%d)",
-				batostr(&addr.l2_bdaddr), psm, strerror(errno), errno);
-		sleep(1);
-		++tries;
-		if(++tries > 10) {
-			close(sk);
-			return -1;
-		}
-	}
-	opt = sizeof(opts);
-	if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, &opt) < 0) {
-		DBG( "Can't get L2CAP options. %s(%d)",
-						strerror(errno), errno);
-		close(sk);
-		return -1;
-	}
+        struct sockaddr_l2 addr;
+        struct l2cap_options opts;
+        int sk;
+        unsigned int opt;
+        int tries;
+        
+        DBG("Begin");
+        sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
+        if (sk < 0) {
+                DBG( "Can't create socket. %s(%d)",
+                        strerror(errno), errno);
+                return -1;
+        }
 
-	DBG( "Connected [imtu %d, omtu %d, flush_to %d]",
-					opts.imtu, opts.omtu, opts.flush_to);
+        DBG( "Connecting to bluetooth");
 
-	if (mtu)
-		*mtu = opts.omtu;
+        memset(&addr, 0, sizeof(addr));
+        addr.l2_family = AF_BLUETOOTH;
+        bacpy(&addr.l2_bdaddr, src);
+        if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+                DBG( "Can't bind socket. %s(%d)",
+                                                strerror(errno), errno);
+                return -1;
+        }
 
-	return sk;
-}
+        /* Get default options */
+        opt = sizeof(opts);
+        if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, &opt) < 0) {
+                DBG( "Can't get default L2CAP options. %s(%d)",
+                                                strerror(errno), errno);
+                return -1;
+        }
 
-int connect_stream(bdaddr_t *src, bdaddr_t *dst, int *cmdfd_return, sbc_t *sbc, int* seid_return)
-{
-	int cmdfd=-1;
-	struct getcap_req put_req;
-	struct sepd_resp get_resp;
-	struct stream_cmd start_stream;
-	struct start_stream_rsp start_resp;
-	int seid, last_seid_index;
-	int size;
-	int i;
-	unsigned short psm_cmd,psm_stream;
-	unsigned long flags = 0;
-	static int streamfd;
-	uint16_t mtu = 0;
-	int tries;
-
-	DBG("Begin");
-	DBG( "Using address: %s", batostr(dst));
-
-	if (detect_a2dp(src, dst, &psm_cmd, &flags) < 0) {
-		DBG( "could not find A2DP services on device %s", batostr(dst));
-		return -1;
-	}
-	else {
-		DBG( "Found A2DP Sink at the destination");
-	}
-
-	psm_cmd=25;	
-	cmdfd = do_connect(src, dst, psm_cmd, NULL);
-	if (cmdfd < 0) {
-		DBG( "cannot open psm_cmd = %d", psm_cmd);
-		return -1;
-	}
-
-	// avdt_discover_req
-	memset(&put_req, 0, sizeof(put_req));
-	init_request(&put_req.header, AVDTP_DISCOVER);
-
-	if (write(cmdfd, &put_req, sizeof(put_req)) != sizeof(put_req)) {
-		DBG("couldn't send avdtp_discover");
-		close(cmdfd);
-		return -1;
-	}
-	else {
-		DBG("Sent the Stream End Point Discovery Command");
-	}
-	tries = 0;
-	while((size = read(cmdfd, &get_resp, sizeof(get_resp))) < 0) {
-		DBG("retrying discover response read...");
-		sleep(1);
-		if(++tries > 10) {
-			break;
-		}
-	}
-	if (size < sizeof(get_resp) - MAX_ADDITIONAL_CODEC_OCTETS) {
-		DBG("couldn't get avdtp_discover");
-		close(cmdfd);
-		return -1;
-	}
-	else {
-		DBG("Got a Stream End Point Discovery Response");
-	}
-	seid = -1;
-	last_seid_index = MAX_ADDITIONAL_CODEC - ((sizeof(get_resp)-size)/sizeof(struct acp_seid_info));
-
-	DBG("received %d capabilities", last_seid_index + 1);
-
-	for(i=0; i <= last_seid_index; i++) {
-		if (process_seid(cmdfd, &get_resp.infos[i], &psm_stream, sbc) == 0) {
-			seid = get_resp.infos[i].acp_seid;
-			break;
-		}
-	}
-
-	if(seid == -1) {
-		//We have not found the seid that we want
-		DBG("couldn't locate the correct seid");
-		return -1;
-	}
-
-	// open the stream
-
-	streamfd = do_connect(src, dst, psm_stream, &mtu);
-	if (streamfd < 0) {
-		DBG("cannot open psm_stream = %d", psm_stream);
-		return -1;
-	}
-	
-	// start the stream
-
-	memset(&start_stream, 0, sizeof(start_stream));
-	init_request(&start_stream.header, AVDTP_START);
-	start_stream.acp_seid = seid;
-
-	if (write(cmdfd, &start_stream, sizeof(start_stream)) != sizeof(start_stream)) {
-		DBG("couldn't send start_stream");
-		close(streamfd);
-		close(cmdfd);
-		return -1;
-	}
-
-	DBG("Sent stream start");
-
-	if (read(cmdfd, &start_resp, sizeof(start_resp)) < sizeof(start_resp) - 2 ||start_resp.header.message_type == MESSAGE_TYPE_REJECT) {
-		DBG("didn't receive start_resp confirm for seid = %d", seid);
-		close(streamfd);
-		close(cmdfd);
-		return (-1);
-	}
-
-	DBG("Got start stream confirm");
-
-	*seid_return = seid;
-	*cmdfd_return = cmdfd;
-	return streamfd;
-}
+        /* Set new options */
+        if(mtu && *mtu) {
+                opts.omtu = *mtu;
+                //opts.imtu = *mtu;
+        }
+        if (setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, opt) < 0) {
+                DBG( "Can't set L2CAP options. %s(%d)",
+                                                strerror(errno), errno);
+                return -1;
+        }
 
-typedef struct snd_pcm_a2dp {
-	//snd_pcm_ioplug_t io;
-	int refcnt;
-	int timeout;
-	unsigned long state;
-	bdaddr_t src;
-	bdaddr_t dst;
-	int sk;
-	int control_sk;
-	sbc_t sbc;
-	int/*snd_pcm_sframes_t */num;
-	unsigned char buf[1024]; // contain sbc encoded data, incrementally filled
-	unsigned int len; // number of valid bytes in buf
-	unsigned int frame_bytes; // fixed when initializing
-	int use_rfcomm;
-	
-	char bufe[BUFS]; // temporary encoding buffer
-		
-	int lenbufe;//=0;
-	unsigned long nbytes;//=0;
-	struct timeval tsend;
-		  
-	time_t timestamp;//=0;
-	uint16_t seq_num;//=1;
-	int frame_count;//=0;
-	int transfer_num;
-
-	int seid;
-	
-	// Used to control stream from headset
-	int stop_writing;// = 0;
-	int pause_writing;// = 0;
-	pthread_t hListenThread;
-} snd_pcm_a2dp_t;
-/*
-void inline a2dp_get(snd_pcm_a2dp_t *a2dp)
-{
-	a2dp->refcnt++;
-	a2dp->timeout = 0;
-}
+        memset(&addr, 0, sizeof(addr));
+        addr.l2_family = AF_BLUETOOTH;
+        bacpy(&addr.l2_bdaddr, dst);
+        addr.l2_psm = htobs(psm);
+
+        tries = 0;
+        while (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+                DBG("Can't connect to %s on psm %d. %s(%d)",
+                                batostr(&addr.l2_bdaddr), psm, strerror(errno), errno);
+                sleep(1);
+                if(++tries > 2) {
+                        close(sk);
+                        return -1;
+                }
+        }
+        opt = sizeof(opts);
+        if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, &opt) < 0) {
+                DBG( "Can't get L2CAP options. %s(%d)",
+                                                strerror(errno), errno);
+                close(sk);
+                return -1;
+        }
 
-void inline a2dp_put(snd_pcm_a2dp_t *a2dp)
-{
-	a2dp->refcnt--;
+        DBG( "Connected psm=%d sk=%d [imtu %d, omtu %d, flush_to %d]", psm, sk,
+                                        opts.imtu, opts.omtu, opts.flush_to);
+
+        if (mtu)
+                *mtu = opts.omtu;
 
-	if (a2dp->refcnt <= 0)
-		a2dp->timeout = 2;
+        return sk;
 }
 
-int a2dp_start(snd_pcm_ioplug_t *io)
-{
-	snd_pcm_a2dp_t *a2dp = io->private_data;
+int connect_stream(bdaddr_t *src, bdaddr_t *dst, int *cmdfd_return, sbc_t *sbc, int* seid_return, int* omtu)
+{
+        int cmdfd=-1;
+        struct sepd_req discover_req;
+        struct sepd_resp discover_resp;
+        struct stream_cmd start_stream;
+        struct start_stream_rsp start_resp;
+        int seid, nb_seid;
+        int size;
+        int i;
+        unsigned short psm_cmd,psm_stream=25;
+        unsigned long flags = 0;
+        int streamfd = -1;
+        uint16_t mtu = 0;
+        int tries, res;
+
+        DBG("Begin");
+        DBG( "Using address: %s", batostr(dst));
+
+        if (detect_a2dp(src, dst, &psm_cmd, &flags) < 0) {
+                DBG( "could not find A2DP services on device %s", batostr(dst));
+                return -1;
+        }
+        else {
+                DBG( "Found A2DP Sink at the destination (psm_cmd=%d)", psm_cmd);
+        }
 
-	DBG("a2dp %p", a2dp);
+        psm_cmd=25;	
+        cmdfd = do_connect(src, dst, psm_cmd, &mtu);
+        if (cmdfd < 0) {
+                DBG( "cannot open psm_cmd = %d", psm_cmd);
+                return -1;
+        }
 
-	a2dp->len = 13;
+        // avdt_discover_req
+        memset(&discover_req, 0, sizeof(discover_req));
+        init_request(&discover_req.header, AVDTP_DISCOVER);
+
+        res=write(cmdfd, &discover_req, sizeof(discover_req));
+        if (res != sizeof(discover_req)) {
+                DBG("couldn't send avdtp_discover (res=%d)", res);
+                close(cmdfd);
+                return -1;
+        }
+        else {
+                DBG("Sent the Stream End Point Discovery Command");
+        }
+        tries = 0;
+        memset(&discover_resp, 0, sizeof(discover_resp));
 
-	return 0;
-}
+        // SONORIX sends us a discover signal we should answer but we will discard
+        while(tries<10)
+        {
+                size = read(cmdfd, &discover_resp, sizeof(discover_resp));
+                tries++;
+                if(size>0)
+                {
+                        if((discover_resp.header.message_type == MESSAGE_TYPE_ACCEPT)
+                         &&(discover_resp.header.signal_id == AVDTP_DISCOVER)
+                          )
+                        {
+                                break;
+                        }
+                        else
+                        {
+                                DBG("Invalid response read, rejected...");
+                                if(discover_resp.header.message_type == MESSAGE_TYPE_COMMAND)
+                                {
+                                        discover_resp.header.message_type = MESSAGE_TYPE_REJECT;
+                                        write(cmdfd, &discover_resp, sizeof(discover_resp.header));
+                                }
+                                
+                                DBG("retrying discover response read...");
+                                // Discard what is not an answer
+                                usleep(100);
+                        }
+                }
+                else
+                {
+                        DBG("retrying discover response read...");
+                        // Discard what is not an answer
+                        usleep(100);
+                }
+        }
 
-snd_pcm_sframes_t a2dp_pointer(snd_pcm_ioplug_t *io)
-{
-	snd_pcm_a2dp_t *a2dp = io->private_data;
+        if (size > sizeof(discover_resp.header))
+        {
+                DBG("Got a Stream End Point Discovery (%d bytes) Response (msgtype=%d,pkttype=%d,lbl=%d,sig=%d,rfa=%d)", 
+                size,
+                discover_resp.header.message_type,
+                discover_resp.header.packet_type,
+                discover_resp.header.transaction_label,
+                discover_resp.header.signal_id,
+                discover_resp.header.rfa0);
+                for(i=0; i<size; i++)
+                        printf("%02X", (int)(*(((char*)&discover_resp)+i)));
+                printf("\n");
+        }
+        else
+        {
+                DBG("couldn't get avdtp_discover (size=%d, min=%d, max=%d)", size, sizeof(discover_resp.header), sizeof(discover_resp));
+                close(cmdfd);
+                return -1;
+        }
 
-	return a2dp->num;
-}
+        seid = -1;
+        nb_seid = (size-sizeof(discover_resp.header))/sizeof(struct acp_seid_info);
 
-void sleeptill(struct timeval *t, struct timeval *dt)
-{
-	struct timeval tc,dtc;
-	struct timezone tz;
-	int i;
-
-   	i=gettimeofday(&tc,&tz);
-	if timercmp(t, &tc, <){ // too late to wait
-		timeradd(&tc, dt, t);
-		return;
-	}
-	usleep(1); //sinchronize with usleep cycle
-   	i=gettimeofday(&tc,&tz);
-	timersub(t, &tc, &dtc);
-	if (dtc.tv_sec==0){	timeradd(t, dt, t);}
-	else {timeradd(&tc, dt, t);return; } //more than a second to sleep, possibly error
-	if (dtc.tv_usec<=2000)  return; //too late to sleep
-	usleep(dtc.tv_usec-2000); // wake up somewhere in the middle of 4ms
-	return;
-}
-*/
-/*
-// returns time to wait ie difference between tsend and current time
-// if time has come, advances tsend
-int time_to_wait(struct timeval *tsend, struct timeval *dt)
-{
-	struct timeval tc,dtc,t2,dt2;
-	struct timezone tz;
-	int i;
-	dt2.tv_sec=0;
-	dt2.tv_usec=2000;// middle of 4ms
-   	i=gettimeofday(&tc,&tz);
-
-	timeradd(&tc, &dt2, &t2);
-	
-	if timercmp(tsend, &t2, <){ // time has come
-		timeradd(tsend, dt, tsend);
-		if timercmp(tsend, &tc, <)	timeradd(&tc, dt, tsend); //if tsend<tc; tsend=tc+dt
-		return 0;
-	}
-	timersub(tsend, &tc, &dtc);
-	return dtc.tv_usec;
-}
+        DBG("received %d capabilities", nb_seid);
 
-// transfers around correct time postions
-snd_pcm_sframes_t a2dp_transfer(snd_pcm_ioplug_t *io, const snd_pcm_channel_area_t *areas, snd_pcm_uframes_t offset, snd_pcm_uframes_t size)
-{
-	snd_pcm_a2dp_t *a2dp = io->private_data;
-	char *buf;
-	int len;
-	struct media_packet_header packet_header;
-	struct media_payload_header payload_header;
-	int codesize,datatoread;
-	unsigned long sleeptime;
-	struct timeval dt;
-	
-
-	codesize=a2dp->sbc.subbands*a2dp->sbc.blocks*a2dp->sbc.channels*2; // size of data encoded by sbc_encode in one call
-	datatoread=min(codesize,size*a2dp->frame_bytes); // amount of data to read
-	buf = (char *) areas->addr + (areas->first + areas->step * offset) / 8;
-    if(a2dp->lenbufe<codesize && a2dp->lenbufe+datatoread<sizeof(a2dp->bufe))
-	{
-		// if not enough data in bufe to encode and there is space in bufe
-		memcpy(a2dp->bufe+a2dp->lenbufe,buf,datatoread);// we read data to bufe
-		a2dp->lenbufe+=datatoread;
-	}
-	else{
-		datatoread=0; //nothing has been read
-	}
-
-	// Encode
-	if(a2dp->lenbufe>=codesize && a2dp->len + a2dp->sbc.len < 678)
-	{
-		// if enough data in bufe to encode and not enough frame to fill up mtu: encoding
-		change_endian(a2dp->bufe,codesize); // changing the endianness
-		len = sbc_encode(&(a2dp->sbc), a2dp->bufe, codesize); //encode
-		memmove(a2dp->bufe, a2dp->bufe + len, a2dp->lenbufe - len); //shift the bufe                                 
-		a2dp->lenbufe-=len;
-		a2dp->nbytes+=len;
-		sleeptime += a2dp->sbc.duration;
-		if (len <= 0)
-			return len;
-		a2dp->frame_count++;
-		memcpy(a2dp->buf + a2dp->len, a2dp->sbc.data, a2dp->sbc.len); // copy encoded frames into a2dp->buf
-		a2dp->len+=a2dp->sbc.len;
-		if (a2dp->state == BT_CONNECTED)
-			a2dp->num += len / a2dp->frame_bytes; //update pointer
-			a2dp->num %=io->buffer_size;
-	}		
-
-	// Transfer
-	if(a2dp->len + a2dp->sbc.len > 678)
-	{
-		// if packet is formed
-		dt.tv_usec=1000000*a2dp->sbc.subbands*a2dp->sbc.blocks*a2dp->frame_count/io->rate; // time interval between transmitions
-		dt.tv_sec=0;
-		if(time_to_wait(&a2dp->tsend, &dt)==0)
-		{
-			// time to send data
-			memset(&payload_header, 0, sizeof(payload_header)); // fill up the headers
-			memset(&packet_header, 0, sizeof(packet_header)); //---
-			payload_header.frame_count=a2dp->frame_count;
-			packet_header.v = 2;
-			packet_header.pt = 1;
-			packet_header.sequence_number = htons(a2dp->seq_num);
-			packet_header.timestamp = htonl(a2dp->timestamp);
-			packet_header.ssrc = htonl(1);
-			a2dp->timestamp += (a2dp->sbc.blocks + 1)*4 * (a2dp->sbc.subbands + 1)*4;
-			memcpy(a2dp->buf, &packet_header, sizeof(packet_header)); //copy the headers to buf
-			memcpy(a2dp->buf + sizeof(packet_header), &payload_header, sizeof(payload_header));//---
-			write(a2dp->sk,a2dp->buf,a2dp->len); // sending the packet
-			a2dp->len = sizeof(packet_header)+sizeof(payload_header); //inital position in buf, just after headers
-			a2dp->frame_count=0;
-			sleeptime=0;
-			a2dp->seq_num++;
-		}
-		else
-		{
-			usleep(1);
-		}
-	}
-	return datatoread / a2dp->frame_bytes;
-}
+        for(i=0; i < nb_seid; i++)
+        {
+                if (process_seid(cmdfd, &discover_resp.infos[i], &psm_stream, sbc) == 0)
+                {
+                        seid = discover_resp.infos[i].acp_seid;
+                        break;
+                }
+        }
+
+        if(seid == -1) {
+                //We have not found the seid that we want
+                DBG("couldn't locate the correct seid");
+                return -1;
+        }
+
+        // open the stream
+        streamfd = do_connect(src, dst, psm_stream, &mtu);
+        if (streamfd < 0) {
+                DBG("cannot open psm_stream = %d", psm_stream);
+                return -1;
+        }
+
+        // start the stream
+
+        memset(&start_stream, 0, sizeof(start_stream));
+        init_request(&start_stream.header, AVDTP_START);
+        start_stream.acp_seid = seid;
+
+        if (write(cmdfd, &start_stream, sizeof(start_stream)) != sizeof(start_stream)) {
+                DBG("couldn't send start_stream");
+                close(streamfd);
+                close(cmdfd);
+                return -1;
+        }
+
+        DBG("Sent stream start(seid=%d)", seid);
+
+        if (read(cmdfd, &start_resp, sizeof(start_resp)) < sizeof(start_resp) - 2 ||start_resp.header.message_type == MESSAGE_TYPE_REJECT) {
+                DBG("didn't receive start_resp confirm for seid = %d", seid);
+                close(streamfd);
+                close(cmdfd);
+                return (-1);
+        }
+
+        DBG("Got start stream confirm");
+
+        *seid_return = seid;
+        *cmdfd_return = cmdfd;
+        return streamfd;
+}
+
+typedef struct snd_pcm_a2dp
+{
+        bdaddr_t src;
+        bdaddr_t dst;
+        int sk;
+        int control_sk;
+        sbc_t sbc;
+        unsigned char buf[1024]; // contain sbc encoded data, incrementally filled
+        unsigned int len; // number of valid bytes in buf
+        unsigned int frame_bytes; // fixed when initializing
+        
+        char bufe[BUFS]; // temporary encoding buffer
+        int lenbufe;//=0;
+ 
+        time_t timestamp;//=0;
+        uint16_t seq_num;//=1;
+        int frame_count;//=0; // Number of sbc frames in one AVDTP packet
+ 
+        int mtu;//=A2DPMAXIMUMTRANSFERUNITSIZE
+        int seid;
+
+        // Used to control stream from headset
+        int stop_writing;// = 0;
+        int pause_writing;// = 0;
+        pthread_t hListenThread;
+        
+} snd_pcm_a2dp_t;
 
-// also works but sleeps between transfers
-snd_pcm_sframes_t a2dp_transfer2(snd_pcm_ioplug_t *io, const snd_pcm_channel_area_t *areas, snd_pcm_uframes_t offset, snd_pcm_uframes_t size)
-{
-	snd_pcm_a2dp_t *a2dp = io->private_data;
-	char *buf;
-	int len;
-	struct media_packet_header packet_header;
-	struct media_payload_header payload_header;
-	int codesize,datatoread;
-	unsigned long sleeptime;
-	int written;
-	
-	struct timeval dt;
-
-	codesize=a2dp->sbc.subbands*a2dp->sbc.blocks*a2dp->sbc.channels*2;
-	datatoread=min(codesize,size*a2dp->frame_bytes);
-
-	struct timeval timeofday;
-	gettimeofday(&timeofday, NULL);
-	
-	buf = (char *) areas->addr + (areas->first + areas->step * offset) / 8;
-    	if(a2dp->lenbufe<codesize){
-		memcpy(a2dp->bufe+a2dp->lenbufe,buf,datatoread);
-		a2dp->lenbufe+=datatoread;
-	}  
-	else{datatoread=0;}
-
-	if(a2dp->lenbufe>=codesize){ //enough data to encode
-		change_endian(a2dp->bufe,codesize); // changing the endianness
-		len = sbc_encode(&(a2dp->sbc), a2dp->bufe, codesize); //encode
-		memmove(a2dp->bufe, a2dp->bufe + len, a2dp->lenbufe - len); //shift the bufe                                 
-		a2dp->lenbufe-=len;
-		a2dp->nbytes+=len;
-		sleeptime += a2dp->sbc.duration;
-		if (len <= 0)
-			return len;
-		if(a2dp->len + a2dp->sbc.len > 678)	{ // time to prepare and send the packet
-			dt.tv_sec=0;
-			dt.tv_usec=1000000*a2dp->sbc.subbands*a2dp->sbc.blocks*a2dp->frame_count/io->rate;
-			memset(&payload_header, 0, sizeof(payload_header));
-			memset(&packet_header, 0, sizeof(packet_header));
-			payload_header.frame_count=a2dp->frame_count;
-			packet_header.v = 2;
-			packet_header.pt = 1;
-			packet_header.sequence_number = htons(a2dp->seq_num);
-			packet_header.timestamp = htonl(a2dp->timestamp);
-			packet_header.ssrc = htonl(1);
-			a2dp->timestamp += (a2dp->sbc.blocks + 1)*4 * (a2dp->sbc.subbands + 1)*4;
-			memcpy(a2dp->buf, &packet_header, sizeof(packet_header));
-			memcpy(a2dp->buf + sizeof(packet_header), &payload_header, sizeof(payload_header));
-			sleeptill(&a2dp->tsend, &dt);
-			if((written = write(a2dp->sk,a2dp->buf,a2dp->len)) != a2dp->len) {
-				DBG("Wrote %d not %d bytes; errno %s(%d)", written, a2dp->len,
-					strerror(errno), errno);
-			}
-			a2dp->len = sizeof(packet_header)+sizeof(payload_header);
-			a2dp->frame_count=0;
-			sleeptime=0;
-			a2dp->seq_num++;
-		}
-		a2dp->frame_count++;
-		memcpy(a2dp->buf + a2dp->len, a2dp->sbc.data, a2dp->sbc.len);
-		a2dp->len+=a2dp->sbc.len;
-		if (a2dp->state == BT_CONNECTED)
-			a2dp->num += len / a2dp->frame_bytes;
-	}
-	return datatoread / a2dp->frame_bytes;
-}
-*/
 // We have pcm data to send through bluetooth
 int a2dp_transfer_raw(LPA2DP a2dp, const char* pcm_buffer, int pcm_buffer_size)
 {
         // No error
-	int result = 0;
-	struct media_packet_header packet_header;
-	struct media_payload_header payload_header;
-	int codesize,datatoread;
-	unsigned long sleeptime;
-	int written;
-	struct timeval dt;
+        int result = 0;
+        struct media_packet_header packet_header;
+        struct media_payload_header payload_header;
+        int codesize,datatoread;
+        int written;
 
         // Check parameter
-	if(a2dp==0 || pcm_buffer==0 || pcm_buffer_size==0) return EINVAL;
-
-        //if(a2dp->transfer_num%1000==0) DBG("Transfer %d", a2dp->transfer_num);
+        if(a2dp==0 || pcm_buffer==0 || pcm_buffer_size==0) return EINVAL;
 
         // How much data can be encoded by sbc at a time?
         codesize=a2dp->sbc.subbands*a2dp->sbc.blocks*a2dp->sbc.channels*2;
         // 16 bits * 2 channels * 16 blocks * 8 subbands = 4096bits = 512 o
         datatoread=min(codesize,pcm_buffer_size);
 
-        //if(a2dp->transfer_num%1000==0) DBG("Codec encode blocks of %d bytes, we read %d bytes of %d incoming", codesize, datatoread, pcm_buffer_size);
-
         // Enqueue data in bufe
-        if(a2dp->lenbufe<codesize)
+        if(a2dp->lenbufe+datatoread < BUFS)
         {
                 // Append data to bufe, for sbc encoding
-                memcpy(a2dp->bufe+a2dp->lenbufe, pcm_buffer, datatoread);
+                memcpy_changeendian(a2dp->bufe+a2dp->lenbufe, pcm_buffer, datatoread);
                 a2dp->lenbufe+=datatoread;
         }
         else
@@ -922,32 +734,24 @@
                 datatoread=0;
         }
 
+
         // If bufe is full, encode
         if(a2dp->lenbufe>=codesize)
         {
                 // Enough data to encode (sbc wants 1k blocks)
                 int encoded;
-                change_endian(a2dp->bufe,codesize); // changing the endianness
                 encoded = sbc_encode(&(a2dp->sbc), a2dp->bufe, codesize); //encode
 
                 if (encoded <= 0)
                         return encoded;
 
-                //if(a2dp->transfer_num%1000==0) DBG("Compressed SBC %d encoded bytes / %d bytes really encoded / %d bytes wanted", a2dp->sbc.len, encoded, codesize);
                 memmove(a2dp->bufe, a2dp->bufe + encoded, a2dp->lenbufe - encoded); // Shift the bufe
-                a2dp->lenbufe-=encoded;
-                a2dp->nbytes+=encoded;
-                //if(a2dp->transfer_num%1000==0) DBG("Shifted SBC (bufe, bufe+encoded=%d, lenbufe=%d-encoded=%d)", encoded, a2dp->lenbufe, a2dp->lenbufe - encoded);
-
-                sleeptime += a2dp->sbc.duration;
+                a2dp->lenbufe -= encoded;
 
                 // Send data through bluetooth
-                if(a2dp->len + a2dp->sbc.len > 678)
+                if(a2dp->len + a2dp->sbc.len >= a2dp->mtu)
                 {
-                        //if(a2dp->transfer_num%1000==0) DBG("Ready to send a2dp->len = %d + a2dp->sbc.len = %d = %d > 678", a2dp->len, a2dp->sbc.len, a2dp->len + a2dp->sbc.len);
                         // time to prepare and send the packet
-                        dt.tv_sec=0;
-                        dt.tv_usec=1000000*a2dp->sbc.subbands*a2dp->sbc.blocks*a2dp->frame_count/48000;
                         memset(&payload_header, 0, sizeof(payload_header));
                         memset(&packet_header, 0, sizeof(packet_header));
                         payload_header.frame_count=a2dp->frame_count;
@@ -959,7 +763,7 @@
                         a2dp->timestamp += (a2dp->sbc.blocks + 1)*4 * (a2dp->sbc.subbands + 1)*4;
                         memcpy(a2dp->buf, &packet_header, sizeof(packet_header));
                         memcpy(a2dp->buf + sizeof(packet_header), &payload_header, sizeof(payload_header));
-                        //sleeptill(&a2dp->tsend, &dt);
+                        // Send our data
                         if((written = write(a2dp->sk,a2dp->buf,a2dp->len)) != a2dp->len)
                         {
                                 // Error while sending data
@@ -970,662 +774,360 @@
                         result = written;
 
                         // Reset buffer of data to send
-                        a2dp->len = sizeof(packet_header)+sizeof(payload_header);
+                        a2dp->len = sizeof(struct media_packet_header)+sizeof(struct media_payload_header);
                         a2dp->frame_count=0;
                         a2dp->seq_num++;
-                        sleeptime=0;
                 }
 
-                // Append sbc encoded data to buf, until buf reaches 678 to send
+                // Append sbc encoded data to buf, until buf reaches A2DPMAXIMUMTRANSFERUNITSIZE to send
                 a2dp->frame_count++;
                 memcpy(a2dp->buf + a2dp->len, a2dp->sbc.data, a2dp->sbc.len);
                 a2dp->len+=a2dp->sbc.len;
         }
 
-        a2dp->transfer_num++;
-
-	return result;
-}
-/*
-int a2dp_close(snd_pcm_ioplug_t *io)
-{
-	snd_pcm_a2dp_t *a2dp = io->private_data;
-	struct stream_cmd close_stream;
-	struct close_stream_rsp close_resp;
-
-	DBG("a2dp Destroying %p", a2dp);
-	memset(&close_stream, 0, sizeof(close_stream));
-	memset(&close_resp, 0, sizeof(close_resp));
-
-	// the stream-close used to make the iTech headset lock up and require it to be powercycled
-	// should be tested again now that we drain the queue properly
-
-	init_request(&close_stream.header, AVDTP_CLOSE);
-	close_stream.acp_seid = a2dp->seid;
-	if (write(a2dp->control_sk, &close_stream, sizeof(close_stream)) != sizeof(close_stream))
-	{
-		printf("Couldn't send close_stream (errno=%d:%s)\n", errno, strerror(errno));
-		close(a2dp->control_sk);
-		a2dp->control_sk = -1;
-		close(a2dp->sk);
-		a2dp->sk = -1;
-	}
-
-	a2dp->len = 0;
-	a2dp->len = 0;
-
-	a2dp_put(a2dp);
-
-	return 0;
-}
-
-int a2dp_params(snd_pcm_ioplug_t *io, snd_pcm_hw_params_t *params)
-{
-	snd_pcm_a2dp_t *a2dp = io->private_data;
-	unsigned int period_bytes;
-
-	DBG("a2dp %p", a2dp);
-
-	a2dp->frame_bytes = (snd_pcm_format_physical_width(io->format) * io->channels) / 8;
-
-	period_bytes = io->period_size * a2dp->frame_bytes;
-
-	DBG("format %s rate %d channels %d", snd_pcm_format_name(io->format), io->rate, io->channels);
-
-	DBG("frame_bytes %d period_bytes %d period_size %ld buffer_size %ld",
-		a2dp->frame_bytes, period_bytes, io->period_size, io->buffer_size);
-
-	return 0;
+        return result;
 }
 
-int a2dp_prepare(snd_pcm_ioplug_t *io)
-{
-	snd_pcm_a2dp_t *a2dp = io->private_data;
-
-	DBG("a2dp %p", a2dp);
-
-	a2dp->len = 13;
-
-	a2dp->num = 0;
-
-	a2dp->sbc.rate = io->rate;
-	a2dp->sbc.channels = io->channels;
-	a2dp->sbc.subbands = 8; // safe default
-	a2dp->sbc.blocks = 16; // safe default
-	a2dp->sbc.bitpool = 32; // recommended value 53, safe default is 32
-
-	return 0;
-}
-
-int a2dp_drain(snd_pcm_ioplug_t *io)
-{
-	snd_pcm_a2dp_t *a2dp = io->private_data;
-
-	DBG("a2dp %p", a2dp);
-
-	a2dp->len = 0;
-
-	return 0;
-}
-
-int a2dp_descriptors_count(snd_pcm_ioplug_t *io)
-{
-	snd_pcm_a2dp_t *a2dp = io->private_data;
-
-	if (a2dp->state == BT_CLOSED)
-		return 0;
-
-	return 1;
-}
-
-int a2dp_descriptors(snd_pcm_ioplug_t *io, struct pollfd *pfds, unsigned int space)
-{
-	snd_pcm_a2dp_t *a2dp = io->private_data;
-
-	if (a2dp->state == BT_CLOSED)
-		return 0;
-
-	if (space < 1) {
-		SNDERR("Can't fill in descriptors");
-		return 0;
-	}
-
-	pfds[0].fd = a2dp->sk;
-	pfds[0].events = POLLOUT;
-
-	return 1;
-}
-
-int a2dp_poll(snd_pcm_ioplug_t *io, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
-{
-	snd_pcm_a2dp_t *a2dp = io->private_data;
-
-	*revents = pfds[0].revents;
-
-	if (a2dp->state == BT_CLOSED)
-		return 0;
-
-	if (pfds[0].revents & POLLHUP) {
-		a2dp->state = BT_CLOSED;
-		snd_pcm_ioplug_reinit_status(&a2dp->io);
-	}
-
-	return 0;
-}
-*/
 static void init_response(struct avdtp_header * header, int response_type)
 {
-	// leave signal_id and transaction label since we are reusing the request
-	header->packet_type = PACKET_TYPE_SINGLE;
-	header->message_type = response_type;
+        // leave signal_id and transaction label since we are reusing the request
+        header->packet_type = PACKET_TYPE_SINGLE;
+        header->message_type = response_type;
 
-	// clear rfa bits
-	header->rfa0 = 0;
+        // clear rfa bits
+        header->rfa0 = 0;
 }
 
 // monitor the control connection for pause/play signals from headset
 // note this signaling is in the avdtp core; avrcp signaling is different
-static void* listen_thread(void* param) 
+static void* listen_thread(void* param)
 {
-	snd_pcm_a2dp_t* a2dp = (snd_pcm_a2dp_t*)param;
+        snd_pcm_a2dp_t* a2dp = (snd_pcm_a2dp_t*)param;
 
-	printf("Listen thread running\n");
+        DBG("Listen thread running\n");
 
-	// Set a timeout to close thread
-	struct timeval t = { 5, 0 };
-	setsockopt( a2dp->control_sk, SOL_SOCKET, SO_SNDTIMEO, &t, sizeof(t));
-	setsockopt( a2dp->control_sk, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(t));
-
-	// Loop until end of writing
-	while(!a2dp->stop_writing)
-	{
-		struct stream_cmd cmd;
-		int size = read(a2dp->control_sk, &cmd, sizeof(cmd));
-		if(size == sizeof(cmd))
-		{
-			printf("Received signal %d from set\n", cmd.header.signal_id);
-			if(cmd.header.signal_id == AVDTP_SUSPEND)
-			{
-				a2dp->pause_writing = 1;
-			}
-			else if(cmd.header.signal_id == AVDTP_START)
-			{
-				a2dp->pause_writing = 0;
-			}
-			else
-			{
-				printf("Unexpected headset directive %d\n", cmd.header.signal_id);
-			}
-			// ack the command regardless
-			// take a shortcut and reuse the command struct (knock one byte off length)
-			init_response(&cmd.header, MESSAGE_TYPE_ACCEPT);
-			if (write(a2dp->control_sk, &cmd, sizeof(cmd)-1) != sizeof(cmd)-1)
-			{
-				printf("Couldn't ack %d\n", cmd.header.signal_id);
-			}
-		}
-		else
-		{
-			if(errno!=EAGAIN)
-				printf("Error while receiving %d (errno=%d:%s)\n", size, errno, strerror(errno));
-			if(errno!=EINTR)
-				break;
-		}
-	}
+        // Set a timeout to close thread
+        struct timeval t = { 5, 0 };
+        setsockopt( a2dp->control_sk, SOL_SOCKET, SO_SNDTIMEO, &t, sizeof(t));
+        setsockopt( a2dp->control_sk, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(t));
 
-	return NULL;
+        // Loop until end of writing
+        while(!a2dp->stop_writing)
+        {
+                struct stream_cmd cmd;
+                int size = read(a2dp->control_sk, &cmd, sizeof(cmd));
+                if(size == sizeof(cmd))
+                {
+                        DBG("Received signal %d from set\n", cmd.header.signal_id);
+                        if(cmd.header.signal_id == AVDTP_SUSPEND)
+                        {
+                                a2dp->pause_writing = 1;
+                        }
+                        else if(cmd.header.signal_id == AVDTP_START)
+                        {
+                                a2dp->pause_writing = 0;
+                        }
+                        else
+                        {
+                                DBG("Unexpected headset directive %d\n", cmd.header.signal_id);
+                        }
+                        // ack the command regardless
+                        // take a shortcut and reuse the command struct (knock one byte off length)
+                        init_response(&cmd.header, MESSAGE_TYPE_ACCEPT);
+                        if (write(a2dp->control_sk, &cmd, sizeof(cmd)-1) != sizeof(cmd)-1)
+                        {
+                                DBG("Couldn't ack %d\n", cmd.header.signal_id);
+                        }
+                }
+                else
+                {
+                        if(errno!=EAGAIN)
+                                DBG("Error while receiving %d (errno=%d:%s)\n", size, errno, strerror(errno));
+                        if(errno!=EINTR)
+                                break;
+                }
+        }
+
+        return NULL;
 }
 
 int a2dp_connect(snd_pcm_a2dp_t *a2dp)
 {
-	struct sockaddr_rc addr;
-	socklen_t len;
-	int sk;
-	int control_sk = -1;
-
-	DBG("a2dp %p", a2dp);
-
-	if(a2dp->use_rfcomm) {
-		sk = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
-		if (sk < 0)
-			return -errno;
-		
-		memset(&addr, 0, sizeof(addr));
-		addr.rc_family = AF_BLUETOOTH;
-		bacpy(&addr.rc_bdaddr, &a2dp->src);
-		
-		if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-			close(sk);
-			return -errno;
-		}
-		
-		memset(&addr, 0, sizeof(addr));
-		addr.rc_family = AF_BLUETOOTH;
-		bacpy(&addr.rc_bdaddr, &a2dp->dst);
-		addr.rc_channel = 1;
-		
-		if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-			close(sk);
-			return -errno;
-		}
-
-		memset(&addr, 0, sizeof(addr));
-		len = sizeof(addr);
-		
-		if (getsockname(sk, (struct sockaddr *) &addr, &len) < 0) {
-			close(sk);
-			return -errno;
-		}
-
-		bacpy(&a2dp->src, &addr.rc_bdaddr);
-
-		//fcntl(sk, F_SETFL, fcntl(sk, F_GETFL) | O_NONBLOCK);
-	} else {
-		sk = connect_stream(&a2dp->src, &a2dp->dst, &control_sk, &a2dp->sbc, &a2dp->seid);
-	}
-
-	a2dp->sk = sk;
-	a2dp->control_sk = control_sk;
-
-	// Start listen thread
-	a2dp->pause_writing = 0;
-	a2dp->stop_writing = 0;
+        //struct sockaddr_rc addr;
+        //socklen_t len;
+        int sk = -1;
+        int control_sk = -1;
+        errno=0;
+        DBG("a2dp %p", a2dp);
+        /*
+        if(a2dp->use_rfcomm) {
+                sk = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
+                if (sk < 0)
+                        return -errno;
+                
+                memset(&addr, 0, sizeof(addr));
+                addr.rc_family = AF_BLUETOOTH;
+                bacpy(&addr.rc_bdaddr, &a2dp->src);
+                
+                if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+                        close(sk);
+                        return -errno;
+                }
+                
+                memset(&addr, 0, sizeof(addr));
+                addr.rc_family = AF_BLUETOOTH;
+                bacpy(&addr.rc_bdaddr, &a2dp->dst);
+                addr.rc_channel = 1;
+                
+                if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+                        close(sk);
+                        return -errno;
+                }
+
+                memset(&addr, 0, sizeof(addr));
+                len = sizeof(addr);
+                
+                if (getsockname(sk, (struct sockaddr *) &addr, &len) < 0) {
+                        close(sk);
+                        return -errno;
+                }
+
+                bacpy(&a2dp->src, &addr.rc_bdaddr);
+
+                //fcntl(sk, F_SETFL, fcntl(sk, F_GETFL) | O_NONBLOCK);
+        } else {*/
+                sk = connect_stream(&a2dp->src, &a2dp->dst, &control_sk, &a2dp->sbc, &a2dp->seid, &a2dp->mtu);
+        //}
+
+        a2dp->sk = sk;
+        a2dp->control_sk = control_sk;
+
+        // Start listen thread
+        a2dp->pause_writing = 0;
+        a2dp->stop_writing = 0;
         
         // Set pthread stack size to decrease unused memory usage
         pthread_attr_t tattr;
         size_t size = PTHREAD_STACK_MIN;
         int ret = pthread_attr_init(&tattr);
         ret = pthread_attr_setstacksize(&tattr, size);
-	pthread_create(&a2dp->hListenThread, &tattr, listen_thread, (void*)a2dp);
+        pthread_create(&a2dp->hListenThread, &tattr, listen_thread, (void*)a2dp);
         pthread_attr_destroy(&tattr);
-	return 0;
+        return 0;
 }
 
-/*
-#define MAX_CONNECTIONS 10
-
-static snd_pcm_a2dp_t *connections[MAX_CONNECTIONS];
-
-static snd_timer_t *timer = NULL;
-
-static volatile sig_atomic_t __locked = 0;
-
-void a2dp_lock(void)
-{
-	while (__locked)
-		usleep(100);
-
-	__locked = 1;
-}
-
-void a2dp_unlock(void)
-{
-	__locked = 0;
-}
-*/
 snd_pcm_a2dp_t *a2dp_alloc(void)
 {
-	snd_pcm_a2dp_t *a2dp;
-	DBG("Begin");
-	a2dp = malloc(sizeof(*a2dp));
-	if (!a2dp)
-		return NULL;
-
-	memset(a2dp, 0, sizeof(*a2dp));
-	a2dp->refcnt = 1;
-	a2dp->seq_num = 1;
-	a2dp->state = BT_OPEN;
-	sbc_init(&a2dp->sbc, 0L);
+        snd_pcm_a2dp_t *a2dp;
+        DBG("Begin");
+        a2dp = malloc(sizeof(*a2dp));
+        if (!a2dp)
+                return NULL;
+
+        memset(a2dp, 0, sizeof(*a2dp));
+        a2dp->seq_num = 1;
+        a2dp->mtu = A2DPMAXIMUMTRANSFERUNITSIZE;
+        a2dp->len = sizeof(struct media_packet_header)+sizeof(struct media_payload_header);
+        sbc_init(&a2dp->sbc, 0L);
 
-	return a2dp;
+        return a2dp;
 }
 
 void a2dp_free(snd_pcm_a2dp_t *a2dp)
 {
-	DBG("Begin");
-	if (a2dp->sk > fileno(stderr))
-		close(a2dp->sk);
-	if (a2dp->control_sk > fileno(stderr))
-		close(a2dp->control_sk);
+        DBG("Begin");
+        if (a2dp->sk > 0)
+                close(a2dp->sk);
+        if (a2dp->control_sk > 0)
+                close(a2dp->control_sk);
 
-	sbc_finish(&a2dp->sbc);
+        sbc_finish(&a2dp->sbc);
 
-	free(a2dp);
+        free(a2dp);
 }
-/*
-void a2dp_timer(snd_async_handler_t *async)
-{
-	snd_timer_t *handle = snd_async_handler_get_timer(async);
-	snd_timer_read_t tr;
-	int i, ticks = 0;
-
-	while (snd_timer_read(handle, &tr, sizeof(tr)) == sizeof(tr))
-		ticks += tr.ticks;
-
-	a2dp_lock();
-
-	for (i = 0; i < MAX_CONNECTIONS; i++) {
-		snd_pcm_a2dp_t *a2dp = connections[i];
-
-		if (a2dp && a2dp->refcnt <= 0) {
-			a2dp->timeout = ((a2dp->timeout * 1000) - ticks) / 1000;
-			if (a2dp->timeout <= 0) {
-				connections[i] = NULL;
-				a2dp_free(a2dp);
-			}
-		}
-	}
 
-	a2dp_unlock();
-}
-*/
 static void sighand(int signo)
 {
-  printf("Thread in signal handler %d\n", signo);
-  return;
+        return;
 }
 
 void a2dp_init(void)
-{/*
-	snd_async_handler_t *async;
-	
-	snd_timer_info_t *info;
-	snd_timer_params_t *params;
-	long resolution;
-	char timername[64];
-	int err, i;
-*/
-	// set up thread signal handler
-	memset(&actions, 0, sizeof(actions));
-	sigemptyset(&actions.sa_mask);
-	actions.sa_flags = 0;
-	actions.sa_handler = sighand;
-	sigaction(SIGALRM,&actions,NULL);
-/*
-	a2dp_lock();
-
-	for (i = 0; i < MAX_CONNECTIONS; i++)
-		connections[i] = NULL;
-
-	a2dp_unlock();
-
-	snd_timer_info_alloca(&info);
-	snd_timer_params_alloca(&params);
-
-	sprintf(timername, "hw:CLASS=%i,SCLASS=%i,CARD=%i,DEV=%i,SUBDEV=%i",
-		SND_TIMER_CLASS_GLOBAL, SND_TIMER_CLASS_NONE, 0,
-					SND_TIMER_GLOBAL_SYSTEM, 0);
-
-	err = snd_timer_open(&timer, timername, SND_TIMER_OPEN_NONBLOCK);
-	if (err < 0) {
-		SNDERR("Can't open global timer");
-		return;
-	}
-
-	err = snd_timer_info(timer, info);
-	if (err < 0) {
-		SNDERR("Can't get global timer info");
-		return;
-	}
-
-	snd_timer_params_set_auto_start(params, 1);
-
-	resolution = snd_timer_info_get_resolution(info);
-	snd_timer_params_set_ticks(params, 1000000000 / resolution);
-	if (snd_timer_params_get_ticks(params) < 1)
-		snd_timer_params_set_ticks(params, 1);
-
-	err = snd_timer_params(timer, params);
-	if (err < 0) {
-		SNDERR("Can't set global timer parameters");
-		snd_timer_close(timer);
-		return;
-	}
-
-	err = snd_async_add_timer_handler(&async, timer, a2dp_timer, NULL);
-	if (err < 0) {
-		SNDERR("Can't create global async callback");
-		snd_timer_close(timer);
-		return;
-	}
-*/
-	// Start sdp advertising
-	/*
-	g_sdpSessionP = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, SDP_RETRY_IF_BUSY);
-	g_recordP = a2dp_advertise_sdp(g_sdpSessionP);
-	*/
-    /*
-	err = snd_timer_start(timer);*/
+{
+        // set up thread signal handler
+        memset(&actions, 0, sizeof(actions));
+        sigemptyset(&actions.sa_mask);
+        actions.sa_flags = 0;
+        actions.sa_handler = sighand;
+        sigaction(SIGALRM,&actions,NULL);
+        
+        // Start sdp advertising
+        /*
+        g_sdpSessionP = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, SDP_RETRY_IF_BUSY);
+        g_recordP = a2dp_advertise_sdp(g_sdpSessionP);
+        */
 }
 
 void a2dp_exit(void)
 {
-//	int err, i;
-
-	// Stop advertising A2DP
-	/*
-	if (g_recordP)
-		sdp_record_free(g_recordP);
-	g_recordP = NULL;
-	if (g_sdpSessionP)
-		sdp_close(g_sdpSessionP);
-	g_sdpSessionP = NULL;
-	*/
-	/*
-	err = snd_timer_stop(timer);
-
-	err = snd_timer_close(timer);
-
-	a2dp_lock();
-
-	for (i = 0; i < MAX_CONNECTIONS; i++) {
-		snd_pcm_a2dp_t *a2dp = connections[i];
-
-		if (a2dp) {
-			connections[i] = NULL;
-			a2dp_free(a2dp);
-		}
-	}
-
-	a2dp_unlock();*/
 }
 
 LPA2DP a2dp_new(char* addr)
 {
-	snd_pcm_a2dp_t *a2dp = NULL;
-	bdaddr_t src, dst;
-	int err, /*pos = -1, */use_rfcomm = 0;
-
-	DBG("Begin");
-	bacpy(&src, BDADDR_ANY);
-	bacpy(&dst, BDADDR_ANY);
-	DBG("bdaddr/dest is %s", addr);
-	str2ba(addr, &dst);
-
-/*
-	a2dp_lock();
-	for (n = 0; n < MAX_CONNECTIONS; n++) {
-		if (connections[n]) {
-			if (!bacmp(&connections[n]->dst, &dst) &&
-					(!bacmp(&connections[n]->src, &src) ||
-						!bacmp(&src, BDADDR_ANY))) {
-				a2dp = connections[n];
-				a2dp_get(a2dp);
-				break;
-			}
-		} else if (pos < 0)
-			pos = n;
-	}
-
-	if (!a2dp) {
-		if (pos < 0) {
-			DBG("Too many connections");
-			return NULL;
-		}
-*/
-	if (!a2dp) {
-		a2dp = a2dp_alloc();
-		if (!a2dp) {
-			DBG("Can't allocate");
-			return NULL;
-		}
-
-		//connections[pos] = a2dp;
-
-		a2dp->state  = BT_CONNECT;
-
-		bacpy(&a2dp->src, &src);
-		bacpy(&a2dp->dst, &dst);
-		a2dp->use_rfcomm = use_rfcomm;
-	}
-
-	//a2dp_unlock();
-
-	if (a2dp->state != BT_CONNECTED) {
-		err = a2dp_connect(a2dp);
-		if (err < 0) {
-			DBG("Can't connect");
-			goto error;
-		}
+        snd_pcm_a2dp_t *a2dp = NULL;
+        bdaddr_t src, dst;
+        int err; //, pos = -1, use_rfcomm = 0;
+
+        DBG("Begin");
+        bacpy(&src, BDADDR_ANY);
+        bacpy(&dst, BDADDR_ANY);
+        DBG("bdaddr/dest is %s", addr);
+        str2ba(addr, &dst);
+        
+        a2dp = a2dp_alloc();
+        if (!a2dp) {
+                DBG("Can't allocate");
+                return NULL;
+        }
 
-		a2dp->state = BT_CONNECTED;
-	}
+        bacpy(&a2dp->src, &src);
+        bacpy(&a2dp->dst, &dst);
+        //a2dp->use_rfcomm = use_rfcomm;
+
+        err = a2dp_connect(a2dp);
+        if (err < 0) {
+                DBG("Can't connect");
+                goto error;
+        }
 
-	return a2dp;
+        return a2dp;
 
 error:
-	a2dp_free(a2dp);
-	return NULL;
+        a2dp_free(a2dp);
+        return NULL;
 }
 
 void a2dp_destroy(LPA2DP a2dp)
 {
-	struct stream_cmd close_stream;
-	struct close_stream_rsp close_resp;
-
-	DBG("Begin");
-	DBG("Destroying %p", a2dp);
+        struct stream_cmd close_stream;
+        struct close_stream_rsp close_resp;
 
-	DBG("Listen thread terminating");
-	a2dp->stop_writing = 1;
-	pthread_kill(a2dp->hListenThread, SIGALRM);
-	pthread_join(a2dp->hListenThread, NULL);
-	DBG("Listen thread terminated");
+        DBG("Begin");
+        a2dp->stop_writing = 1;
+        pthread_kill(a2dp->hListenThread, SIGALRM);
+        pthread_join(a2dp->hListenThread, NULL);
 
         memset(&close_stream, 0, sizeof(close_stream));
-	memset(&close_resp, 0, sizeof(close_resp));
+        memset(&close_resp, 0, sizeof(close_resp));
 
-	// the stream-close used to make the iTech headset lock up and require it to be powercycled
-	// should be tested again now that we drain the queue properly
+        // the stream-close used to make the iTech headset lock up and require it to be powercycled
+        // should be tested again now that we drain the queue properly
 
-	init_request(&close_stream.header, AVDTP_CLOSE);
-	close_stream.acp_seid = a2dp->seid;
-	if (write(a2dp->control_sk, &close_stream, sizeof(close_stream)) != sizeof(close_stream))
-	{
-		printf("Couldn't send close_stream (errno=%d:%s)\n", errno, strerror(errno));
-        }
-
-	DBG("a2dp_free(%p)", a2dp);
-	a2dp_free(a2dp);
-	DBG("a2dp_free(%p) OK", a2dp);
-	DBG("a2dp_destroy(%p) OK", a2dp);
+        init_request(&close_stream.header, AVDTP_CLOSE);
+        close_stream.acp_seid = a2dp->seid;
+        if (write(a2dp->control_sk, &close_stream, sizeof(close_stream)) != sizeof(close_stream))
+        {
+                DBG("Couldn't send close_stream (errno=%d:%s)\n", errno, strerror(errno));
+        }
+
+        a2dp_free(a2dp);
+        DBG("a2dp_destroy(%p) OK", a2dp);
 }
 
 int a2dp_make_listen_socket(unsigned short psm)
 {
-	DBG("Begin");
-	char* lpszError = NULL;
-	int sockfd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
-	
-	if (sockfd >= 0)
-	{
-		struct sockaddr_l2 addr;
-		memset(&addr, 0, sizeof(addr));
-		addr.l2_family = AF_BLUETOOTH;
-		bacpy(&addr.l2_bdaddr, BDADDR_ANY);
-		addr.l2_psm=htobs(psm);
-		if (bind(sockfd, (struct sockaddr *) &addr, sizeof(addr)) >= 0)
-		{
-			/*
-			struct l2cap_options opts;
-			unsigned int iOptSize = sizeof(opts);
-			// Get default options
-			if (getsockopt(sockfd, SOL_L2CAP, L2CAP_OPTIONS, &opts, &opt) >= 0)
-			{
-				if (setsockopt(sockfd, SOL_L2CAP, L2CAP_OPTIONS, &opts, opt) >= 0)
-				{
-			*/
-					if(listen(sockfd,5)>=0)
-					{
-					}
-					else
-					{
-						lpszError = "Can't listen.";
-					}
-			/*
-				}
-				else
-				{
-					lpszError = "Can't get default L2CAP options.";
-				}
-			}
-			else
-			{
-				lpszError = "Can't set L2CAP options.";
-			}
-			*/
-		}
-		else
-		{
-			lpszError = "Can't bind socket (already used?).";
-		}
-	}
-	else
-	{
-		lpszError = "Can't create socket.";
-	}
-
-	if(lpszError)
-	{
-		printf("%s %s(%d)\n", lpszError, strerror(errno), errno);
-		close(sockfd);
-		sockfd=-1;
-	}
-	
-	return sockfd;
+        DBG("Begin");
+        char* lpszError = NULL;
+        int sockfd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
+        
+        if (sockfd >= 0)
+        {
+                struct sockaddr_l2 addr;
+                memset(&addr, 0, sizeof(addr));
+                addr.l2_family = AF_BLUETOOTH;
+                bacpy(&addr.l2_bdaddr, BDADDR_ANY);
+                addr.l2_psm=htobs(psm);
+                if (bind(sockfd, (struct sockaddr *) &addr, sizeof(addr)) >= 0)
+                {
+                        /*
+                        struct l2cap_options opts;
+                        unsigned int iOptSize = sizeof(opts);
+                        // Get default options
+                        if (getsockopt(sockfd, SOL_L2CAP, L2CAP_OPTIONS, &opts, &opt) >= 0)
+                        {
+                                if (setsockopt(sockfd, SOL_L2CAP, L2CAP_OPTIONS, &opts, opt) >= 0)
+                                {
+                        */
+                                        if(listen(sockfd,5)>=0)
+                                        {
+                                        }
+                                        else
+                                        {
+                                                lpszError = "Can't listen.";
+                                        }
+                        /*
+                                }
+                                else
+                                {
+                                        lpszError = "Can't get default L2CAP options.";
+                                }
+                        }
+                        else
+                        {
+                                lpszError = "Can't set L2CAP options.";
+                        }
+                        */
+                }
+                else
+                {
+                        lpszError = "Can't bind socket (already used?).";
+                }
+        }
+        else
+        {
+                lpszError = "Can't create socket.";
+        }
+
+        if(lpszError)
+        {
+                DBG("%s %s(%d)\n", lpszError, strerror(errno), errno);
+                close(sockfd);
+                sockfd=-1;
+        }
+        
+        return sockfd;
 }
 
 int a2dp_wait_connection( int sockfd, char* szRemote, int iRemoteSize, uint16_t *mtu)
 {
-	// Wait client connection
-	struct sockaddr_l2 addr;
-	socklen_t addrlen = sizeof(addr);
-	int new_fd = accept(sockfd, (struct sockaddr *) &addr, &addrlen);
-
-	DBG("Begin");
-	if (szRemote) *szRemote='\0';
-
-	if(new_fd >= 0)
-	{
-		// Get default options
-		struct l2cap_options opts;
-		unsigned int iOptSize = sizeof(opts);
-		if (getsockopt(sockfd, SOL_L2CAP, L2CAP_OPTIONS, &opts, &iOptSize) >= 0)
-		{
-			if (mtu && opts.imtu)
-				*mtu = opts.imtu;
-			if (mtu && opts.omtu)
-				*mtu = opts.omtu;
-			if (!(*mtu))
-				*mtu=678;
-		}
-		printf( "Connected [imtu %d, omtu %d, flush_to %d]\n", opts.imtu, opts.omtu, opts.flush_to);
-
-		if (szRemote) 
-		{
-			strncpy(szRemote, batostr(&addr.l2_bdaddr), iRemoteSize);
-			szRemote[iRemoteSize-1] = '\0';
-		}
-	}
-	return new_fd;
+        // Wait client connection
+        struct sockaddr_l2 addr;
+        socklen_t addrlen = sizeof(addr);
+        int new_fd = accept(sockfd, (struct sockaddr *) &addr, &addrlen);
+
+        DBG("Begin");
+        if (szRemote) *szRemote='\0';
+
+        if(new_fd >= 0)
+        {
+                // Get default options
+                struct l2cap_options opts;
+                unsigned int iOptSize = sizeof(opts);
+                if (getsockopt(sockfd, SOL_L2CAP, L2CAP_OPTIONS, &opts, &iOptSize) >= 0)
+                {
+                        if (mtu && opts.imtu)
+                                *mtu = opts.imtu;
+                        if (mtu && opts.omtu)
+                                *mtu = opts.omtu;
+                        if (!(*mtu))
+                                *mtu=A2DPMAXIMUMTRANSFERUNITSIZE;
+                }
+                DBG("Connected [imtu %d, omtu %d, flush_to %d]\n", opts.imtu, opts.omtu, opts.flush_to);
+
+                if (szRemote) 
+                {
+                        strncpy(szRemote, batostr(&addr.l2_bdaddr), iRemoteSize);
+                        szRemote[iRemoteSize-1] = '\0';
+                }
+        }
+        return new_fd;
 }
Index: alsa-plugins/a2dplib.h
===================================================================
RCS file: /cvsroot/bluetooth-alsa/btsco/alsa-plugins/a2dplib.h,v
retrieving revision 1.1
diff -u -r1.1 a2dplib.h
--- alsa-plugins/a2dplib.h	12 Jul 2006 05:47:06 -0000	1.1
+++ alsa-plugins/a2dplib.h	28 Jul 2006 09:48:08 -0000
@@ -32,37 +32,6 @@
 
 typedef struct snd_pcm_a2dp* LPA2DP;
 
-/*
-void a2dp_init(void) __attribute__ ((constructor));
-void a2dp_exit(void) __attribute__ ((destructor));
-void change_endian( void *buf, int size);
-// Prepare packet headers
-void init_request(struct avdtp_header * header, int request_id);
-// Analyse the SEIDs the sink has sent to us
-int process_seid(int s, struct acp_seid_info * get_seid_resp, unsigned short *psm, sbc_t *sbc);
-// Detect whether A2DP Sink is present at the destination or not
-int detect_a2dp(bdaddr_t *src, bdaddr_t *dst, unsigned short *psm, unsigned long *flags);
-// Connecting on PSM 25
-int do_connect(bdaddr_t *src, bdaddr_t *dst, unsigned short psm, uint16_t *mtu);
-int connect_stream(bdaddr_t *src, bdaddr_t *dst, int *cmdfd_return, sbc_t *sbc);
-*/
-/*
-snd_pcm_sframes_t a2dp_pointer(snd_pcm_ioplug_t *io);
-void sleeptill(struct timeval *t, struct timeval *dt);
-// returns time to wait ie difference between tsend and current time
-// if time has come, advances tsend
-int time_to_wait(struct timeval *tsend, struct timeval *dt);
-int a2dp_close(snd_pcm_ioplug_t *io);
-int a2dp_params(snd_pcm_ioplug_t *io, snd_pcm_hw_params_t *params);
-int a2dp_prepare(snd_pcm_ioplug_t *io);
-int a2dp_drain(snd_pcm_ioplug_t *io);
-int a2dp_descriptors_count(snd_pcm_ioplug_t *io);
-int a2dp_descriptors(snd_pcm_ioplug_t *io, struct pollfd *pfds, unsigned int space);
-int a2dp_poll(snd_pcm_ioplug_t *io, struct pollfd *pfds, unsigned int nfds, unsigned short *revents);
-int a2dp_connect(snd_pcm_a2dp_t *a2dp);
-int a2dp_constraint(snd_pcm_a2dp_t *a2dp);
-void a2dp_timer(snd_async_handler_t *async);
-*/
 // Global library initialisation
 extern void a2dp_init( void);
 extern void a2dp_exit( void);
@@ -71,7 +40,7 @@
 extern LPA2DP a2dp_new( char* bdaddr);
 extern void a2dp_destroy( LPA2DP a2dp);
 
-// transfers around correct time postions
+// compress and transfers data
 extern int a2dp_transfer_raw( LPA2DP a2dp, const char* pcm_buffer, int pcm_buffer_size);
 
 // a2dp server functions
Index: alsa-plugins/a2dplib.o
===================================================================
RCS file: alsa-plugins/a2dplib.o
diff -N alsa-plugins/a2dplib.o
Binary files /tmp/cvsL1OoEg and /dev/null differ
Index: alsa-plugins/ctl_a2dpd.c
===================================================================
RCS file: alsa-plugins/ctl_a2dpd.c
diff -N alsa-plugins/ctl_a2dpd.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ alsa-plugins/ctl_a2dpd.c	28 Jul 2006 09:48:08 -0000
@@ -0,0 +1,330 @@
+/*
+* Bluetooth Headset ALSA Plugin
+*
+* Copyright (c) 2006 by Fabien Chevalier
+* 
+* This library is free software; you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+*/
+
+#include <syslog.h>
+#include <signal.h>
+#include <alsa/asoundlib.h>
+#include <alsa/control_external.h>
+
+#include "a2dp_ipc.h"
+#include "a2dpd_protocol.h"
+
+/* Defines */
+
+#define HS_SPEAKER    0
+#define HS_MICROPHONE 1
+
+#define MINVOL 0
+#define MAXVOL 15
+
+/* Debug */
+
+#define NDEBUG
+#ifdef NDEBUG
+        #define DBG(fmt, arg...)
+#else
+        #define DBG(fmt, arg...)  printf("DEBUG: %s: " fmt "\n" , __FUNCTION__ , ## arg)
+#endif
+
+typedef enum {SPEAKER, MICROPHONE} volume_t;
+
+typedef struct snd_ctl_a2dpd {
+        snd_ctl_ext_t ext;
+} snd_ctl_a2dpd_t;
+
+static const char* vol_devices[] = { 
+        "A2DPD0 Playback Volume",
+        "A2DPD1 Capture Volume"
+};
+
+// Signal handler, there is a SIGPIPE sent when using tcp when the daemon is not running
+// We catch it to not quit
+void sighand(int signo)
+{
+        //printf("A2DPD CTL in signal handler %d\n", signo);
+        return;
+}
+
+static void a2dpd_ctl_close(snd_ctl_ext_t *ext)
+{
+        snd_ctl_a2dpd_t *a2dpd = ext->private_data;
+        close_socket(ext->poll_fd);
+        free(a2dpd);
+}
+
+static int a2dpd_ctl_elem_count(snd_ctl_ext_t *ext)
+{
+        DBG("");
+        return 2;
+}
+
+static int a2dpd_ctl_elem_list(snd_ctl_ext_t *ext, unsigned int offset, snd_ctl_elem_id_t *id)
+{
+        DBG("%d", offset);
+
+        snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
+        if (offset < 2) {
+                snd_ctl_elem_id_set_name(id, vol_devices[offset]);
+                DBG("=> %s", vol_devices[offset]);
+                return 0;
+        }
+        else {
+                return -EINVAL;
+        }
+}
+
+static snd_ctl_ext_key_t a2dpd_ctl_find_elem(snd_ctl_ext_t *ext,
+                                const snd_ctl_elem_id_t *id)
+{
+        const char *name = snd_ctl_elem_id_get_name(id);
+        DBG("%s", name);
+
+        if(strcmp(name, vol_devices[0]) == 0) {
+                return HS_SPEAKER;
+        }
+        else if(strcmp(name, vol_devices[1]) == 0) {
+                return HS_MICROPHONE;
+        }
+        else {
+                return SND_CTL_EXT_KEY_NOT_FOUND;
+        }
+}
+
+static int a2dpd_ctl_get_attribute(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key,
+                        int *type, unsigned int *acc, unsigned int *count)
+{
+        DBG("");
+        *type  = SND_CTL_ELEM_TYPE_INTEGER;
+        *acc   = SND_CTL_EXT_ACCESS_READWRITE;
+        *count = 1;
+        return 0;
+}
+
+static int a2dpd_ctl_get_integer_info(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key,
+                                long *imin, long *imax, long *istep)
+{
+        DBG("");
+        *istep = 1;
+        *imin  = MINVOL;
+        *imax  = MAXVOL;
+        return 0;
+}
+
+static int a2dpd_ctl_read_integer(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, long *value)
+{
+        AUDIOMIXERDATA AudioMixerData = INVALIDAUDIOMIXERDATA;
+        DBG("");
+
+        if(!value) return 0;
+
+        *value = 8;
+
+        int client_type=A2DPD_PLUGIN_CTL_READ;
+        int sockfd=make_client_socket();
+
+        if(send_socket(sockfd, &client_type, sizeof(client_type)) == sizeof(client_type))
+        {
+                if(recv_socket(sockfd, &AudioMixerData, sizeof(AudioMixerData)) == sizeof(AudioMixerData))
+                {
+                        if(key == HS_SPEAKER)
+                        {
+                                if(AudioMixerData.volume_speaker_right!=-1 && AudioMixerData.volume_speaker_left!=-1)
+                                        *value = (AudioMixerData.volume_speaker_right+AudioMixerData.volume_speaker_left)/2;
+                        }
+                        else if(key == HS_MICROPHONE)
+                        {
+                                if(AudioMixerData.volume_micro_right!=-1 && AudioMixerData.volume_micro_left!=-1)
+                                        *value = (AudioMixerData.volume_micro_right+AudioMixerData.volume_micro_left)/2;
+                        }
+                }
+                else
+                {
+                        DBG("Unable to receive new volume value from server");
+                }
+        }
+        else
+        {
+                DBG("Unable to request new volume value to server");
+        }
+        close_socket(sockfd);
+
+        return 0;
+}
+
+static int a2dpd_ctl_write_integer(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, long *value)
+{
+        int iResult = 0;
+        long curvalue;
+
+        DBG("");
+
+        a2dpd_ctl_read_integer(ext, key, &curvalue);
+
+        if(value && *value != curvalue)
+        {
+                AUDIOMIXERDATA AudioMixerData = INVALIDAUDIOMIXERDATA;
+                int client_type=A2DPD_PLUGIN_CTL_WRITE;
+                int sockfd=make_client_socket();
+
+                if(send_socket(sockfd, &client_type, sizeof(client_type)) == sizeof(client_type))
+                {
+                        if(key == HS_SPEAKER)
+                        {
+                                AudioMixerData.volume_speaker_right = *value;
+                                AudioMixerData.volume_speaker_left = *value;
+                        }
+                        else if(key == HS_MICROPHONE)
+                        {
+                                AudioMixerData.volume_micro_right = *value;
+                                AudioMixerData.volume_micro_left = *value;
+                        }
+
+                        if(send_socket(sockfd, &AudioMixerData, sizeof(AudioMixerData)) == sizeof(AudioMixerData))
+                        {
+                                iResult=1;
+                        }
+                        else
+                        {
+                                DBG("Unable to send new volume value to server");
+                        }
+                }
+                else
+                {
+                        DBG("Unable to set new volume value to server");
+                }
+                close_socket(sockfd);
+        }
+
+        iResult=1;
+        return iResult;
+}
+
+static int a2dpd_ctl_read_event(snd_ctl_ext_t *ext, snd_ctl_elem_id_t *id,
+                        unsigned int *event_mask)
+{
+        AUDIOMIXERDATA AudioMixerData = INVALIDAUDIOMIXERDATA;
+//	snd_ctl_a2dpd_t *a2dpd = ext->private_data;
+
+        DBG("");
+        syslog(LOG_INFO, "%s", __FUNCTION__);
+        if(recv_socket(ext->poll_fd, &AudioMixerData, sizeof(AudioMixerData)) == sizeof(AudioMixerData))
+        {
+                snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
+
+                if(AudioMixerData.volume_speaker_right!=-1 || AudioMixerData.volume_speaker_left!=-1)
+                        snd_ctl_elem_id_set_name(id, vol_devices[HS_SPEAKER]);
+                else if(AudioMixerData.volume_micro_right!=-1 || AudioMixerData.volume_micro_left!=-1)
+                        snd_ctl_elem_id_set_name(id, vol_devices[HS_MICROPHONE]);
+
+                *event_mask = SND_CTL_EVENT_MASK_VALUE;
+                return 1;
+        }
+        else
+        {
+                syslog(LOG_INFO, "error %s", __FUNCTION__);
+                DBG("Unable to receive volume notification from server");
+                return -errno;
+        }
+        return -EINVAL;
+        /*
+        if(recv(a2dpd->serverfd, &pkt, sizeof(pkt), MSG_DONTWAIT) == sizeof(pkt)) {
+                if(pkt.type == PKT_TYPE_CTL_NTFY) {
+                        snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
+                        snd_ctl_elem_id_set_name(id, pkt.voltype == SPEAKER ? vol_devices[HS_SPEAKER] : vol_devices[HS_MICROPHONE]);
+                        *event_mask = SND_CTL_EVENT_MASK_VALUE;
+                        return 1;
+                }
+                else {
+                        SNDERR("Unexpected packet type %d received!", pkt.type);
+                        return -EAGAIN;
+                }
+        }
+        else {
+                return -errno;
+        }*/
+}
+
+static snd_ctl_ext_callback_t a2dpd_ext_callback = {
+        .close            = a2dpd_ctl_close,
+        .elem_count       = a2dpd_ctl_elem_count,
+        .elem_list        = a2dpd_ctl_elem_list,
+        .find_elem        = a2dpd_ctl_find_elem,
+        .get_attribute    = a2dpd_ctl_get_attribute,
+        .get_integer_info = a2dpd_ctl_get_integer_info,
+        .read_integer     = a2dpd_ctl_read_integer,
+        .write_integer    = a2dpd_ctl_write_integer,
+        .read_event       = a2dpd_ctl_read_event,
+};
+
+SND_CTL_PLUGIN_DEFINE_FUNC(a2dpd)
+{
+        snd_config_iterator_t it, next;
+        int err = 0;
+        snd_ctl_a2dpd_t *a2dpd = 0;
+
+        // set up thread signal handler
+        signal(SIGPIPE, sighand);
+
+        DBG("");
+        snd_config_for_each(it, next, conf) {
+                snd_config_t *n = snd_config_iterator_entry(it);
+                const char *id;
+                if (snd_config_get_id(n, &id) < 0)
+                        continue;
+
+                if (!strcmp(id, "comment") || !strcmp(id, "type"))
+                //if (snd_pcm_conf_generic_id(id)) // Alsa-lib 1.0.11
+                        continue;
+                SNDERR("Unknown field %s", id);
+                return -EINVAL;
+        }
+
+        a2dpd = malloc(sizeof(*a2dpd));
+        if(a2dpd == NULL)
+        {
+                err=ENOMEM;
+                goto error;
+        }
+
+        a2dpd->ext.version = SND_CTL_EXT_VERSION;
+        a2dpd->ext.card_idx = 0; //FIXME
+        strncpy(a2dpd->ext.id, "A2DPD CTL ID", sizeof(a2dpd->ext.id) - 1);
+        strncpy(a2dpd->ext.driver, "A2DPD CTL Bluetooth Headset Driver", sizeof(a2dpd->ext.driver) - 1);
+        strncpy(a2dpd->ext.name, "A2DPD CTL Headset Name", sizeof(a2dpd->ext.name) - 1);
+        strncpy(a2dpd->ext.longname, "A2DPD CTL Headset Long Name", sizeof(a2dpd->ext.longname) - 1);
+        strncpy(a2dpd->ext.mixername, "A2DPD CTL Headset Mixer Name", sizeof(a2dpd->ext.mixername) - 1);
+        a2dpd->ext.callback = &a2dpd_ext_callback;
+        a2dpd->ext.poll_fd = make_udp_socket();
+        a2dpd->ext.private_data = a2dpd;
+
+        err = snd_ctl_ext_create(&a2dpd->ext, name, mode);
+        if (err < 0)
+                goto error;
+
+        *handlep = a2dpd->ext.handle;
+        return 0;
+
+error:
+        if(a2dpd->ext.poll_fd!=-1) close_socket(a2dpd->ext.poll_fd);
+        if(a2dpd != NULL) free(a2dpd);
+        return err;
+}
+
+SND_CTL_PLUGIN_SYMBOL(a2dpd);
Index: alsa-plugins/pcm_a2dpd.c
===================================================================
RCS file: /cvsroot/bluetooth-alsa/btsco/alsa-plugins/pcm_a2dpd.c,v
retrieving revision 1.1
diff -u -r1.1 pcm_a2dpd.c
--- alsa-plugins/pcm_a2dpd.c	12 Jul 2006 05:47:07 -0000	1.1
+++ alsa-plugins/pcm_a2dpd.c	28 Jul 2006 09:48:08 -0000
@@ -32,24 +32,16 @@
 #include <sys/ioctl.h>
 #include <sys/socket.h>
 #include <sys/time.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/rfcomm.h>
-#include <bluetooth/l2cap.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
+#include <syslog.h>
 
 #include <alsa/asoundlib.h>
 #include <alsa/pcm_external.h>
 #include <alsa/timer.h>
 
-#include <netinet/in.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-
-#include <syslog.h>
+#include "a2dpd_protocol.h"
+#include "a2dp_timer.h"
+#include "a2dp_ipc.h"
 
-#include "sbc.h"
 #include "../a2dp.h"
 
 #define NONSPECAUDIO 1
@@ -59,285 +51,168 @@
 #define DBG(fmt, arg...)  printf("DEBUG: %s: (errno=%d:%s)" fmt "\n" , __FUNCTION__ , errno, strerror(errno), ## arg)
 //#define DBG(D...)
 
-static void a2dp_init(void) __attribute__ ((constructor));
-static void a2dp_exit(void) __attribute__ ((destructor));
+
+// Signal handler, there is a strange SIGPIPE when the daemon is not running
+// We catch it to not quit
+void sighand(int signo)
+{
+        printf("A2DPD CTL in signal handler %d\n", signo);
+        return;
+}
 
 typedef struct snd_pcm_a2dp {
         snd_pcm_ioplug_t io;
-        int refcnt;
-        int timeout;
-        unsigned long state;
-        bdaddr_t src;
-        bdaddr_t dst;
         int sk;
-        int control_sk;
-        sbc_t sbc;
+        int rate;
+        int channels;
         snd_pcm_sframes_t num;
-        unsigned char buf[1024];
-        unsigned int len;
         unsigned int frame_bytes;
-        int use_rfcomm;
-
-        char bufe[BUFS];
-        int lenbufe;//=0;
-
-        unsigned long nbytes;//=0;
-        struct timeval tsend;
-
-        time_t timestamp;//=0;
-        uint16_t seq_num;//=1;
-        int frame_count;//=0;
-
+        TIMERINFO TimerInfos;
 } snd_pcm_a2dp_t;
 
-static void inline a2dp_get(snd_pcm_a2dp_t *a2dp)
+static int a2dp_disconnect(snd_pcm_a2dp_t *a2dp)
 {
-        a2dp->refcnt++;
-        a2dp->timeout = 0;
+        close_socket(a2dp->sk);
+        a2dp->sk = -1;
+        return 0;
 }
 
-static void inline a2dp_put(snd_pcm_a2dp_t *a2dp)
+static int a2dp_connect(snd_pcm_a2dp_t *a2dp)
 {
-        a2dp->refcnt--;
-
-        if (a2dp->refcnt <= 0)
-                a2dp->timeout = 2;
+        if(a2dp->sk <= 0)
+        {
+                int sockfd = make_client_socket();
+                a2dp->sk = -1;
+                if(sockfd>0)
+                {
+                        int32_t client_type = A2DPD_PLUGIN_PCM_WRITE;
+                        if(send_socket(sockfd, &client_type, sizeof(client_type))==sizeof(client_type))
+                        {
+                                a2dp->sk = sockfd;
+                                syslog(LOG_INFO, "Connected a2dp %p, sk %d", a2dp, a2dp->sk);
+                        }
+                        else
+                        {
+                                close_socket(sockfd);
+                                syslog(LOG_WARNING, "Connected a2dp %p, sk %d, Authorisation failed", a2dp, a2dp->sk);
+                        }
+                }
+                else
+                {
+                        syslog(LOG_ERR, "Socket failed a2dp %p, sk %d", a2dp, a2dp->sk);
+                }
+        }
+        return 0;
 }
 
-static int a2dp_start(snd_pcm_ioplug_t *io)
+static inline snd_pcm_a2dp_t *a2dp_alloc(void)
 {
-        snd_pcm_a2dp_t *a2dp = io->private_data;
-
-        DBG("a2dp %p", a2dp);
+        snd_pcm_a2dp_t *a2dp;
+        DBG("Init");
+        a2dp = malloc(sizeof(*a2dp));
+        if (!a2dp)
+                return NULL;
+        memset(a2dp, 0, sizeof(*a2dp));
+        a2dp->sk = -1;
+        a2dp->TimerInfos.fps = A2DPD_BLOCK_FREQUENCY;
+        DBG("OK");
+        return a2dp;
+}
 
-        a2dp->len = 13;
+static inline void a2dp_free(snd_pcm_a2dp_t *a2dp)
+{
+        DBG("Finishing");
+        a2dp_disconnect(a2dp);
+        free(a2dp);
+        DBG("OK");
+}
 
+static int a2dp_start(snd_pcm_ioplug_t *io)
+{
+        //snd_pcm_a2dp_t *a2dp = io->private_data;
+        //FIXME
         return 0;
 }
 
 static int a2dp_stop(snd_pcm_ioplug_t *io)
 {
-        snd_pcm_a2dp_t *a2dp = io->private_data;
-
-        DBG("a2dp %p", a2dp);
-
-        a2dp->len = 0;
-
+        //snd_pcm_a2dp_t *a2dp = io->private_data;
         return 0;
 }
 
 static snd_pcm_sframes_t a2dp_pointer(snd_pcm_ioplug_t *io)
 {
         snd_pcm_a2dp_t *a2dp = io->private_data;
-
         return a2dp->num;
 }
 
-static int a2dp_disconnect(snd_pcm_a2dp_t *a2dp)
+// This is the main transfer func which does the transfer and sleep job
+static snd_pcm_sframes_t a2dp_transfer2(snd_pcm_ioplug_t *io,
+                        char* buf,
+                        int32_t datatoread)
 {
-        if(a2dp->sk > fileno(stderr))
-        {
-                DBG("a2dp %p", a2dp);
+        snd_pcm_a2dp_t* a2dp = io->private_data;
+        int transfer = 0;
 
-                close(a2dp->sk);
-                a2dp->sk = -1;
-                a2dp->state = BT_CLOSED;
-        }
-        else
-        {
-                //DBG("INVALID DISCONNECT a2dp %p, sk %d", a2dp, a2dp->sk);
-        }
-        return 0;
-}
+        // Connect if needed and send
+        a2dp_connect(a2dp);
+        if(transfer>=0) transfer=send_socket(a2dp->sk, &datatoread, sizeof(datatoread));
+        if(transfer>=0) transfer=send_socket(a2dp->sk, buf, datatoread);
 
-static int a2dp_connect(snd_pcm_a2dp_t *a2dp)
-{
-        if(a2dp->sk <= fileno(stderr))
-        {
-                //DBG("a2dp %p", a2dp);
+        // Disconnect if error detected
+        if(transfer<0) a2dp_disconnect(a2dp);
 
-                int sockfd = socket(PF_INET, SOCK_STREAM, 0);
-                if(sockfd>0)
-                {
-                        struct sockaddr_in my_addr;
-                        memset(&my_addr, 0, sizeof(my_addr));
-                        my_addr.sin_family = AF_INET;
-                        my_addr.sin_port = htons(0);
-                        my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+        // The data are sent to the daemon that act as a proxy thus we double transfer delay to compensate latency
+        a2dp_timer_notifyframe(&a2dp->TimerInfos);
+        a2dp_timer_sleep(&a2dp->TimerInfos, 4*A2DPTIMERPREDELAY); 
 
-                        if(bind(sockfd, (struct sockaddr*)&my_addr, sizeof(my_addr)) == 0)
-                        {
-                                struct timeval t;
-                                t.tv_sec=0;
-                                t.tv_usec=100*1000; // 100 ms
-                                setsockopt( sockfd, SOL_SOCKET, SO_SNDTIMEO, &t, sizeof(t));
-                                setsockopt( sockfd, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(t));
-                                
-                                struct sockaddr_in peer_addr;
-                                peer_addr.sin_family = AF_INET;
-                                peer_addr.sin_port = htons(21453);
-                                peer_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
-                                
-                                // Make connection
-                                if(connect(sockfd, (struct sockaddr*)&peer_addr, sizeof(peer_addr)) == 0)
-                                {
-                                        a2dp->sk = sockfd;
-                                        a2dp->state = BT_CONNECTED;
-                                        syslog(LOG_INFO, "Connected a2dp %p, sk %d", a2dp, a2dp->sk);
-                                }
-                                else
-                                {
-                                        // Clean socket
-                                        a2dp->sk = -1;
-                                        //DBG("Connect failed a2dp %p, sk %d", a2dp, a2dp->sk);
-                                        syslog(LOG_WARNING, "Connect failed a2dp %p, sk %d", a2dp, a2dp->sk);
-                                        close(sockfd);
-                                }
-                        }
-                        else
-                        {
-                                DBG("Bind failed a2dp %p, sk %d", a2dp, a2dp->sk);
-                                syslog(LOG_WARNING, "Bind failed a2dp %p, sk %d", a2dp, a2dp->sk);
-                                a2dp->sk = -1;
-                                close(sockfd);
-                        }
-                }
-                else
-                {
-                        DBG("Socket failed a2dp %p, sk %d", a2dp, a2dp->sk);
-                        syslog(LOG_WARNING, "Socket failed a2dp %p, sk %d", a2dp, a2dp->sk);
-                }
-        }
-        return 0;
-}
-
-int a2dp_send(snd_pcm_a2dp_t* a2dp, void* buf, int len)
-{
-        int result = -1;
-        int ioffset = 0;
-        
-        if(a2dp->sk>fileno(stderr))
+        // Stats
+        if(a2dp->TimerInfos.display>0)
         {
-                // The system may split 512 bytes of data so we loop
-                while(ioffset<len)
-                {
-                        result=send(a2dp->sk, ((char*)buf)+ioffset, len-ioffset, 0);
-                        //DBG("[2] send(sk, buf+%d, %d-%d=%d) == %d", ioffset, datatoread, ioffset, datatoread-ioffset, result);
-                        if(result>0)
-                        {
-                                ioffset += result;
-                        }
-                        else
-                        {
-                                break;
-                        }
-                }
-                
-                if(result<0)
+                if(errno != 0 || transfer <= 0)
                 {
-                        if(errno != EAGAIN)
-                        {
-                                DBG("[2] send() failed with value = %d, (errno=%d:%s)", result, errno, strerror(errno));
-                                // Disconnect on error, we will reconnect later
-                                a2dp_disconnect(a2dp);
-                        }
+                        syslog( LOG_INFO, "send_socket(%d bytes)=%d (errno=%d:%s)", datatoread, transfer, errno, strerror(errno));
                 }
         }
 
-        return result;
+        // update pointer, tell alsa we're done
+        a2dp->num += datatoread / a2dp->frame_bytes;
+
+        return datatoread / a2dp->frame_bytes;
 }
 
 // also works but sleeps between transfers
 // This is the main transfer func which does the transfer and sleep job
-static snd_pcm_sframes_t a2dp_transfer2(snd_pcm_ioplug_t *io,
+static snd_pcm_sframes_t a2dp_transfer_all(snd_pcm_ioplug_t *io,
                         const snd_pcm_channel_area_t *areas,
                         snd_pcm_uframes_t offset, snd_pcm_uframes_t size)
 {
-        snd_pcm_a2dp_t *a2dp = io->private_data;
-        int codesize=a2dp->sbc.subbands*a2dp->sbc.blocks*a2dp->sbc.channels*2;
-        int datatoread=min(codesize,size*a2dp->frame_bytes);
-        int transfer = 0;
-        int display = 0;
-        char* buf = (char *) areas->addr + (areas->first + areas->step * offset) / 8;
-
-        // Time reference
-        static struct timeval staticcounter = {0,0};
-        static int icount = 0;
-        if(staticcounter.tv_sec==0)
+        snd_pcm_a2dp_t* a2dp = io->private_data;
+        int i = 0;
+        snd_pcm_sframes_t totaltransfered = 0;
+        while(i++<1 && totaltransfered < size)
         {
-                gettimeofday(&staticcounter, NULL);
-        }
-
-        struct timeval timeofday, duration, playtime, theoricaldate;
-        gettimeofday(&timeofday, NULL);
-        timersub(&timeofday, &staticcounter, &duration);
-
-        // Display data once per second
-        if(duration.tv_sec>0)
-        {
-                gettimeofday(&staticcounter, NULL);
-                display=icount;
-                icount=1;
-        }
-
-        // sleeps a little bit to synchronize sound
-        // a2dp->sbc.channels*44100*2/(size*a2dp->frame_bytes);
-        // 344.53125=channels*freq*16 bits/sizeof(buf)
-        float fps=344.53125;
-        playtime.tv_sec=0;//ipart(icount/fps);
-        playtime.tv_usec=(int)(1.0*1000.0*1000.0*icount/fps);
-        timeradd(&staticcounter, &playtime, &theoricaldate);
-
-        // Si la date théorique est supérieure à la date actuelle
-        if((theoricaldate.tv_sec>timeofday.tv_sec)
-                || (theoricaldate.tv_sec==timeofday.tv_sec && theoricaldate.tv_usec>timeofday.tv_usec)
-                )
-        {
-                // We're in advance, wait a little bit
-                timersub(&theoricaldate, &timeofday, &duration);
-                if(duration.tv_sec>0)
+                char* buf = (char *) areas->addr + (areas->first + areas->step * offset) / 8;
+                int datatoread=min(A2DPD_BLOCK_SIZE,size*a2dp->frame_bytes);
+                snd_pcm_sframes_t transfered = a2dp_transfer2(io, buf, datatoread);
+                if(transfered>0)
                 {
-                        DBG("ERROR duration calculed more than one sec : { %d, %d }", (int)duration.tv_sec, (int)duration.tv_usec);
+                        offset += transfered;
+                        totaltransfered += transfered;
                 }
                 else
                 {
-                        usleep(duration.tv_usec);
+                        break;
                 }
         }
-        else
-        {
-                // We're late, do nothing
-        }
-
-        // Connect if needed and send
-        a2dp_connect(a2dp);
-        if(transfer>=0) transfer=a2dp_send(a2dp, &datatoread, sizeof(datatoread));
-        if(transfer>=0) transfer=a2dp_send(a2dp, buf, datatoread);
-        if(display>0 && transfer >=0)
-        {
-                DBG("a2dp_send(%d * %d = %d bytes of data) returned %d (%d fps)", (int)size, (int)a2dp->frame_bytes, datatoread, transfer, display);
-        }
-
-        icount++;
-
-        // update pointer, tells alsa we're done
-        a2dp->num += datatoread / a2dp->frame_bytes;
-
-        return datatoread / a2dp->frame_bytes;
+        return totaltransfered;
 }
 
 static int a2dp_close(snd_pcm_ioplug_t *io)
 {
         snd_pcm_a2dp_t *a2dp = io->private_data;
-
-        DBG("a2dp %p", a2dp);
-
         a2dp_disconnect(a2dp);
-
-        a2dp->len = 0;
-
-        a2dp_put(a2dp);
-
+        a2dp_free(a2dp);
         return 0;
 }
 
@@ -364,51 +239,27 @@
 static int a2dp_prepare(snd_pcm_ioplug_t *io)
 {
         snd_pcm_a2dp_t *a2dp = io->private_data;
-
         DBG("a2dp %p", a2dp);
-
-        a2dp->len = 13;
-
         a2dp->num = 0;
-
-        a2dp->sbc.rate = io->rate;
-        a2dp->sbc.channels = io->channels;
-        a2dp->sbc.subbands = 8; // safe default
-        a2dp->sbc.blocks = 16; // safe default
-        a2dp->sbc.bitpool = 32; // recommended value 53, safe default is 32
-
+        a2dp->rate = io->rate;
+        a2dp->channels = io->channels;
         return 0;
 }
 
 static int a2dp_drain(snd_pcm_ioplug_t *io)
 {
         snd_pcm_a2dp_t *a2dp = io->private_data;
-
         DBG("a2dp %p", a2dp);
-
-        a2dp->len = 0;
-
         return 0;
 }
 
 static int a2dp_descriptors_count(snd_pcm_ioplug_t *io)
 {
-        // snd_pcm_a2dp_t *a2dp = io->private_data;
-
-        //DBG("Descriptor count = %d (state=%lu)", (a2dp->state != BT_CLOSED)?1:0, a2dp->state);
-
-        return 1; //(a2dp->state != BT_CLOSED)?1:0;
+        return 1;
 }
 
 static int a2dp_descriptors(snd_pcm_ioplug_t *io, struct pollfd *pfds, unsigned int space)
 {
-//	snd_pcm_a2dp_t *a2dp = io->private_data;
-
-/*
-        // We won't reconnect if we do not have data
-        if (a2dp->state == BT_CLOSED)
-                return 0;
-*/
         if (space < 1)
         {
                 DBG("Can't fill in descriptors");
@@ -417,14 +268,9 @@
         }
 
         // Alsa does make sure writing now will not block
-        // If we have a valid socket, poll the socket
-        // Else poll stdout, so that Alsa do not block.
-        // We use sockets with low timeouts
-        pfds[0].fd = /*(a2dp->state == BT_CONNECTED)?(a2dp->sk):*/fileno(stdout);
+        // So give him an always writable socket!
+        pfds[0].fd = fileno(stdout);
         pfds[0].events = POLLOUT;
-
-        // DBG("Descriptor filling=%d state=%lu fd = %d", (a2dp->state != BT_CLOSED)?1:0, a2dp->state, pfds[0].fd);
-
         return 1;
 }
 
@@ -432,12 +278,9 @@
                         unsigned int nfds, unsigned short *revents)
 {
         snd_pcm_a2dp_t *a2dp = io->private_data;
-
-        //DBG("Descriptor polling = %d (state=%lu)", (a2dp->state != BT_CLOSED)?1:0, a2dp->state);
-
         *revents = pfds[0].revents;
 
-        if (a2dp->state == BT_CLOSED)
+        if (a2dp->sk<=0)
                 return 0;
 
         if (pfds[0].revents & POLLHUP) {
@@ -449,21 +292,22 @@
 }
 
 static snd_pcm_ioplug_callback_t a2dp_callback = {
-        .start			= a2dp_start, //FDOK
-        .stop			= a2dp_stop,//FDOK
-        .pointer		= a2dp_pointer,//FDOK
-        .transfer		= a2dp_transfer2,
-        .close			= a2dp_close,//FDOK
-        .hw_params		= a2dp_params,//FDOK
-        .prepare		= a2dp_prepare,//FDOK
-        .drain			= a2dp_drain,//FDOK
-
-        .poll_descriptors_count	= a2dp_descriptors_count,//FDOK
-        .poll_descriptors	= a2dp_descriptors,//FDOK
-        .poll_revents		= a2dp_poll,//FDOK
+        .start			= a2dp_start,
+        .stop			= a2dp_stop,
+        .pointer		= a2dp_pointer,
+        .transfer		= a2dp_transfer_all,
+        .close			= a2dp_close,
+        .hw_params		= a2dp_params,
+        .prepare		= a2dp_prepare,
+        .drain			= a2dp_drain,
+
+        .poll_descriptors_count	= a2dp_descriptors_count,
+        .poll_descriptors	= a2dp_descriptors,
+        .poll_revents		= a2dp_poll,
 };
 
-// Force alsa to give use the 44100 or 48000 hz sound
+// Force alsa to give use the 44100 hz sound
+// Or say alsa we will accept only 44100hz?
 static int a2dp_constraint(snd_pcm_a2dp_t *a2dp)
 {
         snd_pcm_ioplug_t *io = &a2dp->io;
@@ -474,7 +318,7 @@
         unsigned int format[2], channel[2], rate[2];
         int err;
 
-        DBG("[build %s %s] a2dp %p", __DATE__, __TIME__, a2dp);
+        syslog(LOG_INFO, "[build %s %s] a2dp %p", __DATE__, __TIME__, a2dp);
 
         err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_ACCESS, 2, access_list);
         if (err < 0)
@@ -493,10 +337,10 @@
         if (err < 0)
                 return err;
 
-        rate[0] = 44100;
-        rate[1] = 48000;
+        rate[0] = A2DPD_FRAME_RATE;
+        //rate[1] = 48000;
 
-        err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_RATE, 2, rate);
+        err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_RATE, 1, rate);
         if (err < 0)
                 return err;
 
@@ -511,184 +355,20 @@
         return 0;
 }
 
-#define MAX_CONNECTIONS 10
-
-static snd_pcm_a2dp_t *connections[MAX_CONNECTIONS];
-
-//static snd_timer_t *timer = NULL;
-
-static volatile sig_atomic_t __locked = 0;
-
-static inline void a2dp_lock(void)
-{
-        while (__locked)
-                usleep(100);
-
-        __locked = 1;
-}
-
-static inline void a2dp_unlock(void)
-{
-        __locked = 0;
-}
-
-static inline snd_pcm_a2dp_t *a2dp_alloc(void)
-{
-        snd_pcm_a2dp_t *a2dp;
-        DBG("Init");
-        a2dp = malloc(sizeof(*a2dp));
-        if (!a2dp)
-                return NULL;
-
-        memset(a2dp, 0, sizeof(*a2dp));
-
-        a2dp->sk = -1;
-        a2dp->refcnt = 1;
-        a2dp->seq_num = 1;
-        a2dp->state = BT_OPEN;
-
-        sbc_init(&a2dp->sbc, 0L);
-
-        DBG("OK");
-        return a2dp;
-}
-
-static inline void a2dp_free(snd_pcm_a2dp_t *a2dp)
-{
-        DBG("Finishing");
-        a2dp_disconnect(a2dp);
-        
-        sbc_finish(&a2dp->sbc);
-
-        free(a2dp);
-        DBG("OK");
-}
-/*
-// Le timer gère la déconnexion 
-static void a2dp_timer(snd_async_handler_t *async)
-{
-        snd_timer_t *handle = snd_async_handler_get_timer(async);
-        snd_timer_read_t tr;
-        int i, ticks = 0;
-
-        while (snd_timer_read(handle, &tr, sizeof(tr)) == sizeof(tr))
-                ticks += tr.ticks;
-
-        a2dp_lock();
-
-        for (i = 0; i < MAX_CONNECTIONS; i++) {
-                snd_pcm_a2dp_t *a2dp = connections[i];
-
-                if (a2dp && a2dp->refcnt <= 0) {
-                        a2dp->timeout = ((a2dp->timeout * 1000) - ticks) / 1000;
-                        if (a2dp->timeout <= 0) {
-                                connections[i] = NULL;
-                                a2dp_free(a2dp);
-                        }
-                }
-        }
-
-        a2dp_unlock();
-}
-*/
-static void a2dp_init(void)
-{/*
-        snd_async_handler_t *async;
-        snd_timer_info_t *info;
-        snd_timer_params_t *params;
-        long resolution;
-        char timername[64];
-        int err, i;
-
-        a2dp_lock();
-
-        for (i = 0; i < MAX_CONNECTIONS; i++)
-                connections[i] = NULL;
-
-        a2dp_unlock();
-
-        snd_timer_info_alloca(&info);
-        snd_timer_params_alloca(&params);
-
-        sprintf(timername, "hw:CLASS=%i,SCLASS=%i,CARD=%i,DEV=%i,SUBDEV=%i",
-                SND_TIMER_CLASS_GLOBAL, SND_TIMER_CLASS_NONE, 0,
-                                        SND_TIMER_GLOBAL_SYSTEM, 0);
-
-        err = snd_timer_open(&timer, timername, SND_TIMER_OPEN_NONBLOCK);
-        if (err < 0) {
-                SNDERR("Can't open global timer");
-                return;
-        }
-
-        err = snd_timer_info(timer, info);
-        if (err < 0) {
-                SNDERR("Can't get global timer info");
-                return;
-        }
-
-        snd_timer_params_set_auto_start(params, 1);
-
-        resolution = snd_timer_info_get_resolution(info);
-        snd_timer_params_set_ticks(params, 1000000000 / resolution);
-        if (snd_timer_params_get_ticks(params) < 1)
-                snd_timer_params_set_ticks(params, 1);
-
-        err = snd_timer_params(timer, params);
-        if (err < 0) {
-                SNDERR("Can't set global timer parameters");
-                snd_timer_close(timer);
-                return;
-        }
-
-        err = snd_async_add_timer_handler(&async, timer, a2dp_timer, NULL);
-        if (err < 0) {
-                SNDERR("Can't create global async callback");
-                snd_timer_close(timer);
-                return;
-        }
-
-        err = snd_timer_start(timer);
-*/
-}
-
-static void a2dp_exit(void)
-{/*
-        int err, i;
-
-        err = snd_timer_stop(timer);
-
-        err = snd_timer_close(timer);
-
-        a2dp_lock();
-
-        for (i = 0; i < MAX_CONNECTIONS; i++) {
-                snd_pcm_a2dp_t *a2dp = connections[i];
-
-                if (a2dp) {
-                        connections[i] = NULL;
-                        a2dp_free(a2dp);
-                }
-        }
-
-        a2dp_unlock();
-*/
-}
-
 SND_PCM_PLUGIN_DEFINE_FUNC(a2dpd)
 {
         snd_pcm_a2dp_t *a2dp = NULL;
         snd_config_iterator_t i, next;
-        bdaddr_t src, dst;
-        int err, n, pos = -1, use_rfcomm = 0;
+        int err = 0;
 
         DBG("name %s mode %d", name, mode);
 
-        bacpy(&src, BDADDR_ANY);
-        bacpy(&dst, BDADDR_ANY);
+        // set up thread signal handler
+        signal(SIGPIPE,sighand);
 
         snd_config_for_each(i, next, conf) {
                 snd_config_t *n = snd_config_iterator_entry(i);
-                const char *id, *addr;
+                const char *id;
 
                 if (snd_config_get_id(n, &id) < 0)
                         continue;
@@ -696,90 +376,24 @@
                 if (!strcmp(id, "comment") || !strcmp(id, "type"))
                         continue;
 
-                if (!strcmp(id, "bdaddr") || !strcmp(id, "dst")) {
-                        if (snd_config_get_string(n, &addr) < 0) {
-                                SNDERR("Invalid type for %s", id);
-                                return -EINVAL;
-                        }
-                        DBG("bdaddr/dest is %s", addr);
-                        str2ba(addr, &dst);
-                        continue;
-                }
-
-                if (!strcmp(id, "local") || !strcmp(id, "src")) {
-                        if (snd_config_get_string(n, &addr) < 0) {
-                                SNDERR("Invalid type for %s", id);
-                                return -EINVAL;
-                        }
-                        str2ba(addr, &src);
-                        continue;
-                }
-
-                if (!strcmp(id, "use_rfcomm")) {
-                        if ((err = snd_config_get_bool(n)) < 0) {
-                                SNDERR("The field use_rfcomm must be a boolean type");
-                                return err;
-                        }
-                        use_rfcomm = err;
+                // Ignore old options
+                if (strstr("ipaddr bdaddr port src dst use_rfcomm", id))
                         continue;
-                }
 
                 SNDERR("Unknown field %s", id);
                 return -EINVAL;
         }
 
-        a2dp_lock();
-
-        for (n = 0; n < MAX_CONNECTIONS; n++) {
-                if (connections[n]) {
-                        if (!bacmp(&connections[n]->dst, &dst) &&
-                                        (!bacmp(&connections[n]->src, &src) ||
-                                                !bacmp(&src, BDADDR_ANY))) {
-                                a2dp = connections[n];
-                                a2dp_get(a2dp);
-                                break;
-                        }
-                } else if (pos < 0)
-                        pos = n;
-        }
-
-        if (!a2dp) {
-                if (pos < 0) {
-                        SNDERR("Too many connections");
-                        return -ENOMEM;
-                }
-
-                a2dp = a2dp_alloc();
-                if (!a2dp) {
-                        SNDERR("Can't allocate");
-                        return -ENOMEM;
-                }
-
-                connections[pos] = a2dp;
-
-                a2dp->state  = BT_CONNECT;
-
-                bacpy(&a2dp->src, &src);
-                bacpy(&a2dp->dst, &dst);
-                a2dp->use_rfcomm = use_rfcomm;
+        a2dp = a2dp_alloc();
+        if (!a2dp)
+        {
+                SNDERR("Can't allocate plugin data");
+                return -ENOMEM;
         }
 
-        a2dp_unlock();
-/*
-        if (a2dp->state != BT_CONNECTED) {
-                err = a2dp_connect(a2dp);
-                if (err < 0) {
-                        DBG("Can't connect");
-                        SNDERR("Can't connect");
-                        goto error;
-                }
-
-                a2dp->state = BT_CONNECTED;
-        }
-*/
         // Connect
         a2dp_connect(a2dp);
-        
+
         // Notify plugin
         a2dp->io.version      = SND_PCM_IOPLUG_VERSION;
         a2dp->io.name         = "Bluetooth Advanced Audio Distribution";
@@ -802,7 +416,7 @@
 
 error:
         a2dp_disconnect(a2dp);
-        a2dp_put(a2dp);
+        a2dp_free(a2dp);
 
         return err;
 }

[-- Attachment #3: Type: text/plain, Size: 348 bytes --]

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

[-- Attachment #4: Type: text/plain, Size: 164 bytes --]

_______________________________________________
Bluez-devel mailing list
Bluez-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bluez-devel

             reply	other threads:[~2006-07-28 10:26 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-07-28 10:26 Frédéric DALLEAU [this message]
2006-07-28 22:02 ` [Bluez-devel] New A2DP related progress 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=44C9E670.70105@palmsource.com \
    --to=frederic.dalleau@palmsource.com \
    --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.