linux-bluetooth.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [Bluez-devel] New A2DP related progress
@ 2006-07-28 10:26 Frédéric DALLEAU
  2006-07-28 22:02 ` Brad Midgley
  0 siblings, 1 reply; 2+ messages in thread
From: Frédéric DALLEAU @ 2006-07-28 10:26 UTC (permalink / raw)
  To: BlueZ development

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

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2006-07-28 22:02 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-07-28 10:26 [Bluez-devel] New A2DP related progress Frédéric DALLEAU
2006-07-28 22:02 ` Brad Midgley

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).