* [Bluez-devel] Big patch to a2dpd
2006-08-30 14:45 ` Brad Midgley
@ 2006-08-31 16:04 ` Frédéric DALLEAU
2006-09-01 12:57 ` andy
` (2 more replies)
0 siblings, 3 replies; 27+ messages in thread
From: Frédéric DALLEAU @ 2006-08-31 16:04 UTC (permalink / raw)
To: BlueZ development
[-- Attachment #1: Type: text/plain, Size: 678 bytes --]
Hi Brad,
>
> I looked over Matthew's patches and applied them. I applied your "small
> patch" which turns out to be bigger than it sounds :)
>
This one is more than bigger!
Reindent,
Alsa output redirection,
New on-the-fly in-play switch from bt to alsa and reverse
Changing bdaddr in play too.
More options described in sample.a2dprc
I removed the line LIBS= from Makefile.am as suggested. This line was
making tons of compilation problems. As a2dpd finally links to alsa, it
is no longer needed.
Please give it a try before submitting (Matthew and RUI if you read that).
Wrote a doc : http://fdalleau.free.fr/a2dp_doc.pdf ideas welcome!
Frédéric
[-- Attachment #2: patch_btsco_alsaredirect --]
[-- Type: text/plain, Size: 196899 bytes --]
? Doxyfile
? Makefile.in
? aclocal.m4
? autom4te.cache
? btsco.kdevelop
? btsco.kdevelop.pcs
? btsco.kdevses
? compile
? config.guess
? config.h.in
? config.sub
? configure
? depcomp
? install-sh
? missing
? alsa-plugins/Makefile.in
? avdtp/Makefile.in
? sbc/Makefile.in
Index: alsa-plugins/BUILD
===================================================================
RCS file: /cvsroot/bluetooth-alsa/btsco/alsa-plugins/BUILD,v
retrieving revision 1.2
diff -u -r1.2 BUILD
--- alsa-plugins/BUILD 12 Aug 2006 01:51:54 -0000 1.2
+++ alsa-plugins/BUILD 31 Aug 2006 15:58:56 -0000
@@ -26,4 +26,3 @@
Note that this device will not automatically appear in the list of alsa devices.
The alsa folks did this by design but they added a new api for clients to
enumerate plugin devices.
-
Index: alsa-plugins/Makefile.am
===================================================================
RCS file: /cvsroot/bluetooth-alsa/btsco/alsa-plugins/Makefile.am,v
retrieving revision 1.6
diff -u -r1.6 Makefile.am
--- alsa-plugins/Makefile.am 6 Aug 2006 05:23:43 -0000 1.6
+++ alsa-plugins/Makefile.am 31 Aug 2006 15:58:56 -0000
@@ -4,8 +4,6 @@
if ALSAPLUGIN
-#LIBS =
-
alsadir = $(libdir)/alsa-lib
alsa_LTLIBRARIES = libasound_module_pcm_a2dp.la libasound_module_pcm_a2dpd.la libasound_module_ctl_a2dpd.la libasound_module_pcm_sco.la libasound_module_ctl_sco.la
@@ -31,9 +29,10 @@
libasound_module_ctl_sco_la_LIBADD = @ALSA_LIBS@
bin_PROGRAMS = a2dpd
-a2dpd_SOURCES = a2dpd.c a2dplib.c
+a2dpd_SOURCES = a2dpd.c a2dplib.c alsalib.c
+a2dpd_CFLAGS = $(AM_CFLAGS)
#a2dp_timer.c a2dp_ipc.c
-a2dpd_LDADD = a2dp_timer.o a2dp_ipc.o @BLUEZ_LIBS@ -lsbc -lpthread -lrt
+a2dpd_LDADD = a2dp_timer.o a2dp_ipc.o @ALSA_LIBS@ @BLUEZ_LIBS@ -lsbc -lpthread -lrt
AM_CFLAGS = @ALSA_CFLAGS@ @BLUEZ_CFLAGS@ -pthread
AM_LDFLAGS = -module -avoid-version -export-dynamic
Index: alsa-plugins/a2dp_ipc.c
===================================================================
RCS file: /cvsroot/bluetooth-alsa/btsco/alsa-plugins/a2dp_ipc.c,v
retrieving revision 1.3
diff -u -r1.3 a2dp_ipc.c
--- alsa-plugins/a2dp_ipc.c 17 Aug 2006 14:06:27 -0000 1.3
+++ alsa-plugins/a2dp_ipc.c 31 Aug 2006 15:58:56 -0000
@@ -36,7 +36,11 @@
void close_socket(int sockfd)
{
- if(sockfd>0) close(sockfd);
+ if(sockfd>0)
+ {
+ shutdown(sockfd, SHUT_RDWR);
+ close(sockfd);
+ }
}
int make_udp_socket()
@@ -98,7 +102,7 @@
{
if(bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr))==0)
{
- if(listen(sockfd, 10)==0)
+ if(listen(sockfd, 0)==0)
{
// No error
}
Index: alsa-plugins/a2dp_timer.c
===================================================================
RCS file: /cvsroot/bluetooth-alsa/btsco/alsa-plugins/a2dp_timer.c,v
retrieving revision 1.2
diff -u -r1.2 a2dp_timer.c
--- alsa-plugins/a2dp_timer.c 17 Aug 2006 14:06:27 -0000 1.2
+++ alsa-plugins/a2dp_timer.c 31 Aug 2006 15:58:56 -0000
@@ -26,104 +26,93 @@
#include <unistd.h>
#include <syslog.h>
-void sleeptodate(LPTIMERINFO lpTimerInfo, struct timeval* date, int predelay)
+void sleeptodate(LPTIMERINFO lpTimerInfo, struct timeval *date, int predelay)
{
- struct timeval now;
- struct timeval resolutionval={0, predelay + (int)(lpTimerInfo->timer_resolution.tv_nsec/1000)};
+ 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
- }
+ // 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, int predelay)
{
- struct timeval playtime, theoricaldate;
+ struct timeval playtime, theoricaldate;
- //FIXME It is not necessary to use unsigned long if we reset periodically the value of itotalcount (see MAXTOTALCOUNT)
- // if MAXTOTALCOUNT < 700000, we will fit in signed 32bit and reset no more than every 36 mins.
- // Resetting that value might cause a small sound break.
- // Setting MAXTOTALCOUNT to lpTimerInfo->fps will reset every second (useful for testing purposes)
- playtime.tv_sec=((unsigned long)((1.0*(lpTimerInfo->itotalcount)/lpTimerInfo->fps)));
- playtime.tv_usec=((unsigned long)((1.0*1000.0*1000.0/lpTimerInfo->fps)*(lpTimerInfo->itotalcount)))%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);
- }
+ //FIXME It is not necessary to use unsigned long if we reset periodically the value of itotalcount (see MAXTOTALCOUNT)
+ // if MAXTOTALCOUNT < 700000, we will fit in signed 32bit and reset no more than every 36 mins.
+ // Resetting that value might cause a small sound break.
+ // Setting MAXTOTALCOUNT to lpTimerInfo->fps will reset every second (useful for testing purposes)
+ playtime.tv_sec = ((unsigned long) ((1.0 * (lpTimerInfo->itotalcount) / lpTimerInfo->fps)));
+ playtime.tv_usec = ((unsigned long) ((1.0 * 1000.0 * 1000.0 / lpTimerInfo->fps) * (lpTimerInfo->itotalcount))) % 1000000;
+ timeradd(&lpTimerInfo->totalcounter, &playtime, &theoricaldate);
+
+ // If calculated date is higher than current date
+ 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);
+ 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);
+ gettimeofday(&lpTimerInfo->timeofday, NULL);
- // Initialize timers
- if(lpTimerInfo->staticcounter.tv_sec==0)
- gettimeofday(&lpTimerInfo->staticcounter, NULL);
- if(lpTimerInfo->totalcounter.tv_sec==0 || lpTimerInfo->itotalcount>MAXTOTALCOUNT)
- {
- 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;
- }
+ // Initialize timers
+ if (lpTimerInfo->staticcounter.tv_sec == 0)
+ gettimeofday(&lpTimerInfo->staticcounter, NULL);
+ if (lpTimerInfo->totalcounter.tv_sec == 0 || lpTimerInfo->itotalcount > MAXTOTALCOUNT) {
+ 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, predelay);
+ keepfreqtotal(lpTimerInfo, predelay);
- lpTimerInfo->icount++;
- lpTimerInfo->itotalcount++;
+ lpTimerInfo->icount++;
+ lpTimerInfo->itotalcount++;
}
-
Index: alsa-plugins/a2dpair
===================================================================
RCS file: alsa-plugins/a2dpair
diff -N alsa-plugins/a2dpair
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ alsa-plugins/a2dpair 31 Aug 2006 15:58:57 -0000
@@ -0,0 +1,129 @@
+#!/bin/sh
+
+#
+# Discovery
+#
+echo "Discovery in progress..."
+I=0
+SCANFILE=/tmp/hci_scan
+declare -a ARRAYADDR
+declare -a ARRAYNAME
+
+# We need this file because else there is a problem with arrays in shell
+# The while loop is run in a subshell
+hcitool scan > $SCANFILE
+
+while read BTADDR BTDESC ; do
+ if expr match "$BTADDR" "..:..:..:..:..:.." > /dev/null ; then
+ # Truc
+ echo "$I) [$BTADDR] $BTDESC"
+ I=`expr $I + 1`
+ ARRAYADDR[$I]="$BTADDR"
+ ARRAYNAME[$I]="$BTDESC"
+ fi
+done < $SCANFILE
+rm -f $SCANFILE
+
+if [ $I -le 0 ] ; then
+ echo "Found $I devices"
+ exit -1
+fi
+
+#
+# Device selection
+#
+SELECTION=
+I=`expr $I - 1`
+while [ -z $SELECTION ] || [ $SELECTION -gt $I ] ; do
+ echo "Choose device (0-$I)"
+ read SELECTION
+done
+# sh uses 1 based arrays
+SELECTION=`expr $SELECTION + 1`
+ADDRESS=${ARRAYADDR[$SELECTION]}
+NAME=${ARRAYNAME[$SELECTION]}
+#
+# Pairing
+#
+echo "Pair device $NAME (y/N)?"
+read CANPAIR
+
+if [ "$CANPAIR" = "y" ] ; then
+
+ # Device passkey
+ SELECTION=
+ while [ -z $SELECTION ] ; do
+ echo "Enter passkey for $NAME"
+ read SELECTION
+ done
+ PASSKEY=$SELECTION
+
+ # Prefetch password
+ sudo echo "Pairing in progress..."
+
+ # passkey agent
+ if sudo passkey-agent --default $PASSKEY & PASSPID=$! ; then
+
+ #echo "Registered passkey-agent pid=$PASSPID"
+
+ # pairing
+ ANYTEXTISFAILURE=`sudo hcitool cc $ADDRESS 2>&1`
+
+ if [ -z "$ANYTEXTISFAILURE" ] ; then
+ echo "Pairing successfull"
+ RESULT=0
+ else
+ echo "$ANYTEXTISFAILURE"
+ echo "Pairing failed"
+ fi
+
+ #echo "Killing pid=$PASSPID"
+ # Kill bg process
+ sudo kill $PASSPID
+ fi
+fi
+
+#
+# A2DP Setting
+#
+echo "Select device for a2dp (y/N)?"
+read A2PARAM
+
+if [ "$A2PARAM" = "y" ] ; then
+ echo "Writing ~/.a2dprc"
+ if [ -f ~/.a2dprc ] ; then
+ mv -f ~/.a2dprc ~/.a2dprc~
+ cat ~/.a2dprc~ | while read LINE ; do
+ # Address line
+ if expr "$LINE" : "address=.*" > /dev/null; then
+ echo "address=$ADDRESS" >> ~/.a2dprc
+ else
+ echo "$LINE" >> ~/.a2dprc
+ fi
+ done
+ else
+ echo "[A2DPD]" > ~/.a2dprc
+ echo "address=$ADDRESS" >> ~/.a2dprc
+ fi
+fi
+
+
+#
+# A2DP Daemon
+#
+echo "Start a2dp daemon (y/N)?"
+read A2DAEMON
+if [ "$A2DAEMON" = "y" ] ; then
+ while killall a2dpd 2> /dev/null ; do
+ echo -n .
+ sleep 1
+ done
+ a2dpd -d +v
+fi
+
+#
+# Ending
+#
+exit 0
+
+############
Index: alsa-plugins/a2dpd.c
===================================================================
RCS file: /cvsroot/bluetooth-alsa/btsco/alsa-plugins/a2dpd.c,v
retrieving revision 1.7
diff -u -r1.7 a2dpd.c
--- alsa-plugins/a2dpd.c 30 Aug 2006 14:43:21 -0000 1.7
+++ alsa-plugins/a2dpd.c 31 Aug 2006 15:58:57 -0000
@@ -37,6 +37,7 @@
#include <linux/uinput.h>
#include "a2dplib.h"
+#include "alsalib.h"
#include "a2dpd_protocol.h"
#include "a2dp_timer.h"
#include "a2dp_ipc.h"
@@ -51,16 +52,18 @@
#define UINPUT_DEVICE "/dev/input/uinput"
#define A2DPD_CONFIG_FILE ".a2dpdrc"
-
-static char g_sOutputFilename [512];
-static char g_srcfilename [512];
-static char g_sCmdPlay [512];
-static char g_sCmdPause [512];
-static char g_sCmdPrev [512];
-static char g_sCmdNext [512];
-static char g_sCmdNew [512];
-static int g_nbdeviceconnected = 0;
-static int uinput_fd = -1;
+static char g_sOutputFilename[512];
+static char g_srcfilename[512];
+static char g_sCmdPlay[512];
+static char g_sCmdPause[512];
+static char g_sCmdPrev[512];
+static char g_sCmdNext[512];
+static char g_sCmdNew[512];
+static int g_nbdeviceconnected = 0;
+static int uinput_fd = -1;
+static int g_bavrcp = 0;
+static int g_brereadconfig = 0;
+static int g_breversestereo = 0;
// This function is needed to destroy zombies processes
// On Unix, any forked process which terminate before its parent create a zombie until parent call waitpid()
@@ -69,56 +72,49 @@
// http://www.erlenstar.demon.co.uk/unix/faq_2.html
void ignore_child_processes_return_values()
{
- struct sigaction sa;
- sa.sa_handler = SIG_IGN;
- #ifdef SA_NOCLDWAIT
- sa.sa_flags = SA_NOCLDWAIT;
- #else
- sa.sa_flags = 0;
- #endif
- sigemptyset(&sa.sa_mask);
- sigaction(SIGCHLD, &sa, NULL);
+ struct sigaction sa;
+ sa.sa_handler = SIG_IGN;
+#ifdef SA_NOCLDWAIT
+ sa.sa_flags = SA_NOCLDWAIT;
+#else
+ sa.sa_flags = 0;
+#endif
+ sigemptyset(&sa.sa_mask);
+ sigaction(SIGCHLD, &sa, NULL);
}
-void make_daemon_process(int bFork, int bVerbose, char*output_file_name)
+void make_daemon_process(int bFork, int bVerbose, char *output_file_name)
{
- // Fork to background process if needed
- if (bFork == 1)
- {
- switch (fork())
- {
- case -1:
- exit(-1);
- case 0:
- break;
- default:
- exit(0);
- }
-
- setsid();
- chdir("/");
- }
-
- // Redirect output to file (default /dev/null) in silent mode, verbose will print output to stdin/out/err
- if(!bVerbose)
- {
- int fd;
- if ((fd = open(output_file_name, O_CREAT|O_APPEND|O_RDWR, 0)) != -1)
- {
- fchmod(fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
- (void) dup2(fd, STDIN_FILENO);
- (void) dup2(fd, STDOUT_FILENO);
- (void) dup2(fd, STDERR_FILENO);
- if (fd > 2)
- (void) close(fd);
- }
- else
- {
- printf("a2dpd: Couldn't redirect output to '%s' (errno=%d:%s)", output_file_name, errno, strerror(errno));
- }
- }
+ // Fork to background process if needed
+ if (bFork == 1) {
+ switch (fork()) {
+ case -1:
+ exit(-1);
+ case 0:
+ break;
+ default:
+ exit(0);
+ }
- printf("a2dpd [%s %s] starting ...", __DATE__, __TIME__);
+ setsid();
+ chdir("/");
+ }
+ // Redirect output to file (default /dev/null) in silent mode, verbose will print output to stdin/out/err
+ if (!bVerbose) {
+ int fd;
+ if ((fd = open(output_file_name, O_CREAT | O_APPEND | O_RDWR, 0)) != -1) {
+ fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
+ (void) dup2(fd, STDIN_FILENO);
+ (void) dup2(fd, STDOUT_FILENO);
+ (void) dup2(fd, STDERR_FILENO);
+ if (fd > 2)
+ (void) close(fd);
+ } else {
+ printf("a2dpd: Couldn't redirect output to '%s' (errno=%d:%s)", output_file_name, errno, strerror(errno));
+ }
+ }
+
+ printf("a2dpd [%s %s] starting ...", __DATE__, __TIME__);
}
static int lock_fd(int fd)
@@ -141,54 +137,52 @@
// Prepare packet headers
static void init_response(struct avctp_header *header)
{
- header->ipid = 0;
- header->cr = AVCTP_RESPONSE_FRAME;
- header->packet_type = PACKET_TYPE_SINGLE;
+ header->ipid = 0;
+ header->cr = AVCTP_RESPONSE_FRAME;
+ header->packet_type = PACKET_TYPE_SINGLE;
}
-static int init_uinput ()
+static int init_uinput()
{
int fd, i;
struct uinput_user_dev dev = {
.id = {
- .bustype = BUS_BLUETOOTH,
- .version = 0x0001,
- }
+ .bustype = BUS_BLUETOOTH,
+ .version = 0x0001,
+ }
};
- if((fd = open(UINPUT_DEVICE, O_WRONLY)) < 0)
- {
+ if ((fd = open(UINPUT_DEVICE, O_WRONLY)) < 0) {
perror("Cannot open " UINPUT_DEVICE);
goto shutdown;
}
- if(write(fd, &dev, sizeof(dev)) < sizeof(dev))
- {
+ if (write(fd, &dev, sizeof(dev)) < sizeof(dev)) {
perror("Cannot create a uinput device");
goto release;
}
- if(ioctl(fd, UI_SET_EVBIT, EV_KEY))
+ if (ioctl(fd, UI_SET_EVBIT, EV_KEY))
goto release;
- for(i = 0; i <= KEY_MAX; i++)
- if(ioctl(fd, UI_SET_KEYBIT, i))
+ for (i = 0; i <= KEY_MAX; i++)
+ if (ioctl(fd, UI_SET_KEYBIT, i))
goto release;
- if(ioctl(fd, UI_DEV_CREATE))
+ if (ioctl(fd, UI_DEV_CREATE))
goto release;
uinput_fd = fd;
return 0;
- release:
+ release:
ioctl(fd, UI_DEV_DESTROY);
- shutdown:
+ shutdown:
close(fd);
return 1;
}
-static void kill_uinput ()
+static void kill_uinput()
{
if (uinput_fd == -1)
return;
@@ -197,99 +191,93 @@
close(uinput_fd);
}
-static void send_key (unsigned short code)
+static void send_key(unsigned short code)
{
struct input_event ev = {
.type = EV_KEY,
.code = code,
- .time = {0, }
+ .time = {0,}
};
if (uinput_fd == -1)
return;
- if(code > KEY_MAX)
+ if (code > KEY_MAX)
return;
-
- ev.value = 1; // press...
+
+ ev.value = 1; // press...
write(uinput_fd, &ev, sizeof(ev));
- ev.value = 0; // then release
+ ev.value = 0; // then release
write(uinput_fd, &ev, sizeof(ev));
}
// This function handle the bluetooth connection
int a2dp_handle_avrcp_message(int sockfd)
{
- char lpFrame [A2DPMAXIMUMTRANSFERUNITSIZE];
- int iReceived = recv(sockfd, lpFrame, sizeof(lpFrame), 0);
- if(iReceived>0)
- {
- struct avc_frame frame = *((struct avc_frame*)lpFrame);
-
- // Handle message
- if(frame.ctype == CMD_PASSTHROUGH)
- {
- switch (frame.operand0)
- {
- case PLAY_OP:
- printf("[play] %s\n", g_sCmdPlay);
- if(g_sCmdPlay[0]) async_run_process(g_sCmdPlay);
- send_key (KEY_PLAY);
- break;
- case PAUSE_OP:
- printf("[pause] %s\n", g_sCmdPause);
- if(g_sCmdPause[0]) async_run_process(g_sCmdPause);
- send_key (KEY_PAUSE);
- break;
- case NEXT_OP:
- printf("[next] %s\n", g_sCmdNext);
- if(g_sCmdNext[0]) async_run_process(g_sCmdNext);
- send_key (KEY_NEXTSONG);
- break;
- case PREV_OP:
- printf("[previous] %s\n", g_sCmdPrev);
- if(g_sCmdPrev[0]) async_run_process(g_sCmdPrev);
- send_key (KEY_PREVIOUSSONG);
- break;
- default:
- printf("received passthrough %d bytes:\n", iReceived);
- //dump_packet(&frame, iReceived);
- }
- }
- else
- {
- printf("received %d bytes:\n", iReceived);
- //dump_packet(&frame, iReceived);
- }
- // Send response
- if(iReceived > 0)
- {
- if(frame.ctype == CMD_ACCEPTED)
- {
- printf("(ack)\n");
- }
- else
- if(frame.ctype == CMD_PASSTHROUGH)
- {
- init_response(&frame.header);
- frame.ctype = CMD_ACCEPTED;
- write(sockfd, &frame, iReceived);
- }
- else
- {
- printf("only passthrough ctype command is implemented. doh!\n");
- // ierk!!! exit(0);
- }
- }
- }
- else
- {
- if(errno!=EAGAIN)
- printf("socket %d: Receive failed %d (error %d:%s)\n", sockfd, iReceived, errno, strerror(errno));
- }
+ char lpFrame[A2DPMAXIMUMTRANSFERUNITSIZE];
+ int iReceived = recv(sockfd, lpFrame, sizeof(lpFrame), 0);
+ if (iReceived > 0) {
+ struct avc_frame frame = *((struct avc_frame *) lpFrame);
+
+ // Handle message
+ if (frame.ctype == CMD_PASSTHROUGH) {
+ switch (frame.operand0) {
+ case PLAY_OP:
+ printf("[play] %s\n", g_sCmdPlay);
+ if (g_sCmdPlay[0])
+ async_run_process(g_sCmdPlay);
+ else
+ send_key(KEY_PLAY);
+ break;
+ case PAUSE_OP:
+ printf("[pause] %s\n", g_sCmdPause);
+ if (g_sCmdPause[0])
+ async_run_process(g_sCmdPause);
+ else
+ send_key(KEY_PAUSE);
+ break;
+ case NEXT_OP:
+ printf("[next] %s\n", g_sCmdNext);
+ if (g_sCmdNext[0])
+ async_run_process(g_sCmdNext);
+ else
+ send_key(KEY_NEXTSONG);
+ break;
+ case PREV_OP:
+ printf("[previous] %s\n", g_sCmdPrev);
+ if (g_sCmdPrev[0])
+ async_run_process(g_sCmdPrev);
+ else
+ send_key(KEY_PREVIOUSSONG);
+ break;
+ default:
+ printf("received passthrough %d bytes:\n", iReceived);
+ //dump_packet(&frame, iReceived);
+ }
+ } else {
+ printf("received %d bytes:\n", iReceived);
+ //dump_packet(&frame, iReceived);
+ }
+ // Send response
+ if (iReceived > 0) {
+ if (frame.ctype == CMD_ACCEPTED) {
+ printf("(ack)\n");
+ } else if (frame.ctype == CMD_PASSTHROUGH) {
+ init_response(&frame.header);
+ frame.ctype = CMD_ACCEPTED;
+ write(sockfd, &frame, iReceived);
+ } else {
+ printf("only passthrough ctype command is implemented. doh!\n");
+ // ierk!!! exit(0);
+ }
+ }
+ } else {
+ if (errno != EAGAIN)
+ printf("socket %d: Receive failed %d (error %d:%s)\n", sockfd, iReceived, errno, strerror(errno));
+ }
- return iReceived;
+ return iReceived;
}
//////////////////////////////////////////
@@ -306,738 +294,709 @@
#define max(x,y) ((x)>(y)?(x):(y))
-char* pool_pop()
+char *pool_pop()
{
- return malloc(POOLENTRYSIZE);
+ return malloc(POOLENTRYSIZE);
}
-void pool_push(char* pool)
+void pool_push(char *pool)
{
- free(pool);
+ 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];
+typedef struct {
+ 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;
- AUDIOMIXERDATA mixer;
- int nb_clients;
- BTA2DPPERCLIENTDATA clients[MAXCLIENTSPERDEVICE];
+typedef struct {
+ char addr[20];
+ char plug[20];
+ pthread_t thread;
+ pthread_t receiverthread;
+ pthread_mutex_t mutex;
+ AUDIOMIXERDATA mixer;
+ int nb_clients;
+ int bredirectalsa;
+ BTA2DPPERCLIENTDATA clients[MAXCLIENTSPERDEVICE];
} BTA2DPPERDEVICEDATA, *LPBTA2DPPERDEVICEDATA;
// Data needed per Audio Streaming Client
-typedef struct
-{
- LPBTA2DPPERDEVICEDATA lpDevice;
- int sockfd;
- pthread_t thread;
+typedef struct {
+ LPBTA2DPPERDEVICEDATA lpDevice;
+ int sockfd;
+ pthread_t thread;
} A2DPDCLIENT, *LPA2DPDCLIENT;
// Allocate a new device
-LPBTA2DPPERDEVICEDATA bta2dpdevicenew(char* addr)
+LPBTA2DPPERDEVICEDATA bta2dpdevicenew(char *addr)
{
- int i = 0;
- LPBTA2DPPERDEVICEDATA lpDevice = malloc(sizeof(BTA2DPPERDEVICEDATA));
- if(lpDevice)
- {
- 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++)
- {
- pthread_mutex_init(&lpDevice->clients[i].mutex, NULL);
- }
- }
- return lpDevice;
+ int i = 0;
+ LPBTA2DPPERDEVICEDATA lpDevice = malloc(sizeof(BTA2DPPERDEVICEDATA));
+ if (lpDevice) {
+ 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++) {
+ pthread_mutex_init(&lpDevice->clients[i].mutex, NULL);
+ }
+ }
+ return lpDevice;
}
// Free a device
void bta2dpdevicefree(LPBTA2DPPERDEVICEDATA lpDevice)
{
- int i = 0;
- if(lpDevice)
- {
- for(i=0;i<MAXCLIENTSPERDEVICE; i++)
- {
- pthread_mutex_destroy(&lpDevice->clients[i].mutex);
- }
- pthread_mutex_destroy(&lpDevice->mutex);
- free(lpDevice);
- }
+ int i = 0;
+ if (lpDevice) {
+ for (i = 0; i < MAXCLIENTSPERDEVICE; i++) {
+ pthread_mutex_destroy(&lpDevice->clients[i].mutex);
+ }
+ pthread_mutex_destroy(&lpDevice->mutex);
+ free(lpDevice);
+ }
}
// handle sigterm to terminate properly
void sigint_handler(int sig)
{
- // User wants to force quit
- if(bSigINTReceived==1)
- {
- printf("handling SIGINT again: exit forced\n");
- exit(0);
- }
- else
- {
- // Now we must quit properly
- bSigINTReceived = 1;
- printf("handling SIGINT\n");
-
- // Dummy connection to unlock server (currently accepting)
- close_socket(make_client_socket());
- }
+ // User wants to force quit
+ if (bSigINTReceived == 1) {
+ printf("handling SIGINT again: exit forced\n");
+ exit(0);
+ } else {
+ // Now we must quit properly
+ bSigINTReceived = 1;
+ printf("handling SIGINT\n");
+
+ // Dummy connection to unlock server (currently accepting)
+ close_socket(make_client_socket());
+ }
}
// This function handles a client
-void* client_handler(void* param)
+void *client_handler(void *param)
{
- 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 ++;
-
- pthread_detach(lpClient->thread);
-
- 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)
- {
- printf("CTL WRITE thread %d.%d started\n", client_index, lpClient->sockfd);
-
- if(recv_socket(lpClient->sockfd, &AudioMixerData, sizeof(AudioMixerData))==sizeof(AudioMixerData))
- {
- 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);
- }
- }
-
- // This client wants to read our control status
- if(client_type==A2DPD_PLUGIN_CTL_READ)
- {
- printf("CTL READ 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);
-
- send_socket(lpClient->sockfd, &AudioMixerData, sizeof(AudioMixerData));
- }
-
- // This client wants to send us pcm stream
- if(client_type==A2DPD_PLUGIN_PCM_WRITE)
- {
- // 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)
- {
- 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(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)
- {
- 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;
- }
-
- 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);
- 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) errno=%d:%s\n", client_index, lpClient->sockfd, result, sizeof(pcm_buffer_size), errno, strerror(errno));
- }
- bError = 1;
- }
- }
-
- 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);
- 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);
+ 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++;
+
+ pthread_detach(lpClient->thread);
+
+ 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) {
+ printf("CTL WRITE thread %d.%d started\n", client_index, lpClient->sockfd);
+
+ if (recv_socket(lpClient->sockfd, &AudioMixerData, sizeof(AudioMixerData)) == sizeof(AudioMixerData)) {
+ 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);
+ }
+ }
+ // This client wants to read our control status
+ if (client_type == A2DPD_PLUGIN_CTL_READ) {
+ printf("CTL READ 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);
+
+ send_socket(lpClient->sockfd, &AudioMixerData, sizeof(AudioMixerData));
+ }
+ // This client wants to send us pcm stream
+ if (client_type == A2DPD_PLUGIN_PCM_WRITE) {
+ // 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) {
+ 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 (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) {
+ 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;
+ }
+
+ 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);
+ 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) errno=%d:%s\n", client_index, lpClient->sockfd, result, sizeof(pcm_buffer_size), errno,
+ strerror(errno));
+ }
+ bError = 1;
+ }
+ }
+
+ 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);
+ 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);
+
+ // Decrease thread count
+ iThreadsRunning--;
- // Free client data
- free(lpClient);
+ return 0;
+}
- // Decrease thread count
- iThreadsRunning --;
+/////////////////////////////////
+int audio_mixer(void *pcm_buffer, char **pcm_buffers, int *pcm_buffers_size, int vol_left, int vol_right)
+/////////////////////////////////
+{
+ int i, j;
+ int satured = 0;
+
+ // Mix audio streams 16 bits stereo channels
+ // We require little endianness here
+ int pcm_buffer_filed_size = 0;
+ for (j = 0; j < POOLENTRYSIZE / 4; j++) {
+ int32_t *pBuffer = (int32_t *) pcm_buffer;
+ int32_t channel_1 = 0;
+ int32_t channel_2 = 0;
+ for (i = 0; i < MAXCLIENTSPERDEVICE; i++) {
+ int32_t *pBuffers = (int32_t *) (pcm_buffers[i]);
+ if (pBuffers != NULL && (j < pcm_buffers_size[i] / 4)) {
+ int16_t i1 = *(((int16_t *) (pBuffers + j)) + 0);
+ int16_t i2 = *(((int16_t *) (pBuffers + j)) + 1);
+ channel_1 += i1;
+ channel_2 += i2;
+ pcm_buffer_filed_size = max(pcm_buffer_filed_size, pcm_buffers_size[i]);
+ }
+ }
+ //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;
+ 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++;
+ }
- return 0;
+ channel_1 *= vol_left;
+ channel_2 *= vol_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;
+ if(g_breversestereo) {
+ pBuffer[j] = (((channel_1 & 0x0000FFFF) << 16) | (channel_2 & 0x0000FFFF));
+ } else {
+ //FIXME We have a reverse stereo I don't know why
+ // The following line corrects the problem but I miss the cause so
+ pBuffer[j] = (((channel_2&0x0000FFFF)<<16)|(channel_1&0x0000FFFF));
+ pBuffer[j] = ( (channel_1 & 0xFFFF0000) | (channel_2 & 0x0000FFFF) );
+ }
+ }
+ return pcm_buffer_filed_size;
}
// This function handle the bluetooth connection
-void* bt_handler(void* param)
+void *bt_handler(void *param)
{
- int i,j;
- // We should not terminate the process if clients are still running
- iThreadsRunning ++;
-
- LPBTA2DPPERDEVICEDATA lpDevice = (LPBTA2DPPERDEVICEDATA)param;
- pthread_detach(lpDevice->thread);
-
- // As long as daemon is running
- while(!bSigINTReceived)
- {
- 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;
- int rate = read_config_int(g_srcfilename, "a2dpd", "rate", A2DPD_FRAME_RATE);
- memset(&TimerInfos, 0, sizeof(TimerInfos));
- TimerInfos.fps = (float)((((float)rate)*((float)A2DPD_FRAME_BYTES)/((float)A2DPD_BLOCK_SIZE))/1.0);
- printf("New connection to bluetooth [%d hz]\n", rate);
-
- // As long as we can send sound
- while(!bSigINTReceived && !bError)
- {
- int pcm_buffer_filed_size = 0;
- char* pcm_buffers[MAXCLIENTSPERDEVICE];
- int pcm_buffers_size[MAXCLIENTSPERDEVICE];
- 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 Since we read nb_clients, we should lock mutex, but it may create timer issues
- // pthread_mutex_lock(&lpDevice->mutex);
-
- if(lpDevice->nb_clients>0)
- {
- // Retrieve data for client where it is available
- for(i=0; i<MAXCLIENTSPERDEVICE; i++)
- {
- if(lpDevice->clients[i].lives)
- {
- pthread_mutex_lock(&lpDevice->clients[i].mutex);
-
- if(lpDevice->clients[i].ring_in != lpDevice->clients[i].ring_out)
- {
- // Get ring buffer
- pcm_buffers[i] = lpDevice->clients[i].ring[lpDevice->clients[i].ring_out];
- pcm_buffers_size[i] = lpDevice->clients[i].ring_len[lpDevice->clients[i].ring_out];
- // 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);
-
- //printf("Reading pool %d[ %d] = %p\n", i, lpDevice->clients[i].ring_out, pcm_buffers[i]);
-
- lpDevice->clients[i].ring_out = next_ring;
-
- // Remember we got some sound
- state_current = SOUND;
- }
-
- pthread_mutex_unlock(&lpDevice->clients[i].mutex);
- }
- }
- }
- //FIXME
- // pthread_mutex_unlock(&lpDevice->mutex);
-
- // Send mixed audio stream to clients
- switch(state_current)
- {
- case SOUND:
- {
- /////////////////////////////////
- // Mix what we got
- /////////////////////////////////
-
- static int frames = 0;
- frames ++;
-
- // Mix audio streams 16 bits stereo channels
- // We require little endianness here
- pcm_buffer_filed_size = 0;
- for(j=0; j<POOLENTRYSIZE/4; j++)
- {
- int32_t* pBuffer = (int32_t*)pcm_buffer;
- int32_t channel_1 = 0;
- int32_t channel_2 = 0;
- for(i=0; i<MAXCLIENTSPERDEVICE; i++)
- {
- int32_t* pBuffers = (int32_t*)(pcm_buffers[i]);
- if(pBuffers != NULL && (j<pcm_buffers_size[i]/4))
- {
- int16_t i1 = *(((int16_t*)(pBuffers+j))+0);
- int16_t i2 = *(((int16_t*)(pBuffers+j))+1);
- channel_1 += i1;
- channel_2 += i2;
- pcm_buffer_filed_size = max(pcm_buffer_filed_size, pcm_buffers_size[i]);
- }
- }
- //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; 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++)
- {
- if(pcm_buffers[i])
- {
- // Reintegrate data where they come from
- pool_push(pcm_buffers[i]);
- }
- }
-
- /////////////////////////////////
- // Transfer data to bluetooth
- /////////////////////////////////
-
- if(pcm_buffer && pcm_buffer_filed_size>0)
- {
- // Transfer takes place by A2DPD_BLOCK_SIZE bytes blocks
- int blockstart = 0;
- int blocksize = A2DPD_BLOCK_SIZE;
-
- // Allocate A2DP if we are not connected
- if(!lpA2dp)
- {
- lpA2dp = a2dp_new(lpDevice->addr, rate);
- g_nbdeviceconnected++;
- destroy_count = 0;
- }
-
- if(lpA2dp)
- {
- // Send data to BT headset
- while(!bError && blockstart<pcm_buffer_filed_size)
- {
- int transfer;
-
- 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
- {
- printf("Error in a2dp_transfer_raw\n");
- bError = 1;
- }
- }
- }
- }
- break;
- }
- case NOSOUND:
- {
- if(state_previous == SOUND)
- {
- //printf("Sound stream ran dry!!!\n");
- }
- break;
- }
- }
-
- // Free the A2DP device if needed
- // When destroy_count reaches 2000 we will destroy the A2DP link
- // However, destroy_count is reset whenever data are sent
- destroy_count++;
- if(lpA2dp && destroy_count>2000)
- {
- printf("Destroying lpA2dp, destroy_count is %d\n", destroy_count);
- g_nbdeviceconnected--;
- a2dp_destroy(lpA2dp);
- lpA2dp = NULL;
- }
-
- // 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;
- }
- pool_push(pcm_buffer);
-
- // Sleep a little bit before retrying
- if(!bSigINTReceived)
- sleep(1);
-
- // Free A2DP
- if(lpA2dp)
- {
- printf("Destroying lpA2dp, end of loop\n");
- g_nbdeviceconnected--;
- a2dp_destroy(lpA2dp);
- lpA2dp = NULL;
- }
- }
+ int i;
+ // We should not terminate the process if clients are still running
+ iThreadsRunning++;
+
+ LPBTA2DPPERDEVICEDATA lpDevice = (LPBTA2DPPERDEVICEDATA) param;
+ pthread_detach(lpDevice->thread);
+
+ // As long as daemon is running
+ while (!bSigINTReceived) {
+ int bError = 0;
+ int destroy_count = 0;
+ int ibytespersecond = 0;
+
+ // Connect to the A2DP device
+ void *lpA2dp = NULL;
+ char *pcm_buffer = pool_pop();
+ enum { NOSOUND, SOUND };
+ int state_previous = NOSOUND;
+ TIMERINFO TimerInfos;
+ int rate = read_config_int(g_srcfilename, "a2dpd", "rate",
+ A2DPD_FRAME_RATE);
+ memset(&TimerInfos, 0, sizeof(TimerInfos));
+ TimerInfos.fps = (float) ((((float) rate) * ((float) A2DPD_FRAME_BYTES) / ((float) A2DPD_BLOCK_SIZE)) / 1.0);
+ printf("New connection to bluetooth [%d hz]\n", rate);
+
+ // As long as we can send sound
+ while (!bSigINTReceived && !bError) {
+ int pcm_buffer_filed_size = 0;
+ char *pcm_buffers[MAXCLIENTSPERDEVICE];
+ int pcm_buffers_size[MAXCLIENTSPERDEVICE];
+ 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 Since we read nb_clients, we should lock mutex, but it may create timer issues
+ // degrading sound
+ // pthread_mutex_lock(&lpDevice->mutex);
+
+ if (lpDevice->nb_clients > 0) {
+ // Retrieve data for client where it is available
+ for (i = 0; i < MAXCLIENTSPERDEVICE; i++) {
+ if (lpDevice->clients[i].lives) {
+ pthread_mutex_lock(&lpDevice->clients[i].mutex);
+
+ if (lpDevice->clients[i].ring_in != lpDevice->clients[i].ring_out) {
+ // Get ring buffer
+ pcm_buffers[i] = lpDevice->clients[i].ring[lpDevice->clients[i].ring_out];
+ pcm_buffers_size[i] = lpDevice->clients[i].ring_len[lpDevice->clients[i].ring_out];
+ // 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);
+
+ //printf("Reading pool %d[ %d] = %p\n", i, lpDevice->clients[i].ring_out, pcm_buffers[i]);
+
+ lpDevice->clients[i].ring_out = next_ring;
+
+ // Remember we got some sound
+ state_current = SOUND;
+ }
+
+ pthread_mutex_unlock(&lpDevice->clients[i].mutex);
+ }
+ }
+ }
+ //FIXME
+ // pthread_mutex_unlock(&lpDevice->mutex);
+
+ // Send mixed audio stream to clients
+ switch (state_current) {
+ case SOUND:
+ pcm_buffer_filed_size = audio_mixer(pcm_buffer, pcm_buffers, pcm_buffers_size, lpDevice->mixer.volume_speaker_left, lpDevice->mixer.volume_speaker_right);
+
+ // Free no longer used audio blocks
+ for (i = 0; i < MAXCLIENTSPERDEVICE; i++) {
+ if (pcm_buffers[i]) {
+ // Reintegrate data where they come from
+ pool_push(pcm_buffers[i]);
+ }
+ }
+
+ /////////////////////////////////
+ // Transfer data to bluetooth
+ /////////////////////////////////
+
+ if (pcm_buffer && pcm_buffer_filed_size > 0) {
+ // Transfer takes place by A2DPD_BLOCK_SIZE bytes blocks
+ int blockstart = 0;
+ int blocksize = A2DPD_BLOCK_SIZE;
+
+ // Allocate A2DP if we are not connected
+ if (!lpA2dp) {
+ // Select the good device
+ lpDevice->bredirectalsa = read_config_int(g_srcfilename, "a2dpd", "enableredirectalsa", 0);
+ read_config_string(g_srcfilename, "a2dpd", "address", lpDevice->addr, sizeof(lpDevice->addr), "");
+ read_config_string(g_srcfilename, "a2dpd", "alsaoutput", lpDevice->plug, sizeof(lpDevice->plug), "");
+ // Allocate it
+ if (lpDevice->bredirectalsa)
+ lpA2dp = alsa_new(lpDevice->plug, rate);
+ else
+ lpA2dp = a2dp_new(lpDevice->addr, rate);
+ g_nbdeviceconnected++;
+ destroy_count = 0;
+ }
+
+ if (lpA2dp) {
+ // Send data to BT headset
+ while (!bError && blockstart < pcm_buffer_filed_size) {
+ int transfer;
+
+ blocksize = (pcm_buffer_filed_size < A2DPD_BLOCK_SIZE) ? pcm_buffer_filed_size : A2DPD_BLOCK_SIZE;
+
+ if (lpDevice->bredirectalsa)
+ transfer = alsa_transfer_raw(lpA2dp, pcm_buffer + blockstart, blocksize);
+ else
+ transfer = a2dp_transfer_raw(lpA2dp, pcm_buffer + blockstart, blocksize);
+
+ if (transfer >= 0) {
+ destroy_count = 0;
+ blockstart += blocksize;
+ ibytespersecond += transfer;
+ a2dp_timer_notifyframe(&TimerInfos);
+ } else {
+ printf("Error in a2dp_transfer_raw\n");
+ bError = 1;
+ }
+ }
+ }
+ }
+ break;
+ case NOSOUND:
+ if (state_previous == SOUND) {
+ //printf("Sound stream ran dry!!!\n");
+ }
+ break;
+ }
+
+ // 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);
+
+ // Read config file changes each second
+ if (TimerInfos.display > 0) {
+ if(g_brereadconfig) {
+ char addr[20];
+ char plug[20];
+ int bredirectalsa = read_config_int(g_srcfilename, "a2dpd", "enableredirectalsa", 0);
+ read_config_string(g_srcfilename, "a2dpd", "address", addr, sizeof(addr), "");
+ read_config_string(g_srcfilename, "a2dpd", "alsaoutput", plug, sizeof(plug), "");
+ if((strcmp(addr, lpDevice->addr) != 0) || (strcmp(plug, lpDevice->plug) != 0) || (bredirectalsa != lpDevice->bredirectalsa)) {
+ // Force destroy, device will be recreated upon audio incoming
+ destroy_count=10000;
+ }
+ }
+ /*
+ 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;
+ */
+ }
+
+ // Free the A2DP device if needed
+ // When destroy_count reaches 2000 we will destroy the A2DP link
+ // However, destroy_count is reset whenever data are sent
+ destroy_count++;
+ if (lpA2dp && destroy_count > 2000) {
+ printf("Destroying lpA2dp, destroy_count is %d\n", destroy_count);
+ g_nbdeviceconnected--;
+ if (lpDevice->bredirectalsa)
+ alsa_destroy(lpA2dp);
+ else
+ a2dp_destroy(lpA2dp);
+ lpA2dp = NULL;
+ }
+
+ state_previous = state_current;
+ }
+ pool_push(pcm_buffer);
+
+ // Sleep a little bit before retrying
+ if (!bSigINTReceived)
+ sleep(1);
+
+ // Free A2DP
+ if (lpA2dp) {
+ printf("Destroying lpA2dp, end of loop\n");
+ g_nbdeviceconnected--;
+ if (lpDevice->bredirectalsa)
+ alsa_destroy(lpA2dp);
+ else
+ a2dp_destroy(lpA2dp);
+ lpA2dp = NULL;
+ }
+ }
- iThreadsRunning --;
+ iThreadsRunning--;
- return 0;
+ return 0;
}
// This function handle the bluetooth connection
-void* avdtp_listener(void* param)
+void *avdtp_listener(void *param)
{
- // We should not terminate the process if clients are still running
- iThreadsRunning ++;
+ // We should not terminate the process if clients are still running
+ iThreadsRunning++;
- LPBTA2DPPERDEVICEDATA lpDevice = (LPBTA2DPPERDEVICEDATA)param;
- pthread_detach(lpDevice->thread);
+ LPBTA2DPPERDEVICEDATA lpDevice = (LPBTA2DPPERDEVICEDATA) param;
+ pthread_detach(lpDevice->thread);
- // As long as daemon is running
- printf("avdtp: Accepting incoming connection\n");
- while(!bSigINTReceived)
- {
- int sockfd = a2dp_make_listen_socket( 25);
- if(sockfd>=0)
- {
- while(!bSigINTReceived)
- {
- // Wait for incoming connections
- char szRemote[64];
- uint16_t iMTU = 0;
-
- int new_fd = a2dp_wait_connection(sockfd, szRemote, sizeof(szRemote), &iMTU);
-
- if(new_fd>0)
- {
- printf("avdtp: socket %d: Connection from %s, mtu=%d\n", new_fd, szRemote, iMTU);
-
- // Loop and manage what the client sends
- setup_socket(new_fd);
- int iReceived = 0;
- int play = 0;
- int count = 0;
- do
- {
- iReceived = a2dp_handle_avdtp_message(NULL, new_fd, NULL, NULL, 0);
- if(iReceived==0)
- {
- printf("avdtp: socket %d: Received frame, start %s\n", new_fd, g_sCmdNew);
- play=1;
- count=0;
- break;
- }
- else if(iReceived<0)
- {
- if(errno!=EAGAIN)
- printf("avdtp: socket %d: Received failed result=%d (errno=%d:%s)\n", new_fd, iReceived, errno, strerror(errno));
- }
- count++;
- }
- // AVDTP do not need to have a device connected, since it can establish device connection
- while(!bSigINTReceived && (iReceived>=0 || errno==EAGAIN) && count<10);
- printf("avdtp: socket %d: timed out\n", new_fd);
- close_socket(new_fd);
-
- if(play&&g_sCmdNew[0])
- {
- async_run_process(g_sCmdNew);
- }
- }
- else
- {
- if(errno!=EAGAIN)
- {
- printf("a2dp_wait_connection failed (AVDTP socket) : %d (errno=%d:%s)\n", new_fd, errno, strerror(errno));
- break;
- }
- }
- }
-
- close_socket(sockfd);
- }
-
- // Sleep a little bit if we must retry
- sleep(bSigINTReceived?1:0);
- }
+ // As long as daemon is running
+ printf("avdtp: Accepting incoming connection\n");
+ while (!bSigINTReceived) {
+ int sockfd = a2dp_make_listen_socket(25);
+ if (sockfd >= 0) {
+ while (!bSigINTReceived) {
+ // Wait for incoming connections
+ char szRemote[64];
+ uint16_t iMTU = 0;
+
+ int new_fd = a2dp_wait_connection(sockfd, szRemote, sizeof(szRemote), &iMTU);
+
+ if (new_fd > 0) {
+ printf("avdtp: socket %d: Connection from %s, mtu=%d\n", new_fd, szRemote, iMTU);
+
+ // Loop and manage what the client sends
+ setup_socket(new_fd);
+ int iReceived = 0;
+ int play = 0;
+ int count = 0;
+ do {
+ iReceived = a2dp_handle_avdtp_message(NULL, new_fd, NULL, NULL, 0);
+ if (iReceived == 0) {
+ printf("avdtp: socket %d: Received frame, start %s\n", new_fd, g_sCmdNew);
+ play = 1;
+ count = 0;
+ break;
+ } else if (iReceived < 0) {
+ if (errno != EAGAIN)
+ printf("avdtp: socket %d: Received failed result=%d (errno=%d:%s)\n", new_fd, iReceived, errno, strerror(errno));
+ }
+ count++;
+ }
+ // AVDTP do not need to have a device connected, since it can establish device connection
+ while (!bSigINTReceived && (iReceived >= 0 || errno == EAGAIN)
+ && count < 10);
+ printf("avdtp: socket %d: timed out\n", new_fd);
+ close_socket(new_fd);
+
+ if (play && g_sCmdNew[0]) {
+ async_run_process(g_sCmdNew);
+ }
+ } else {
+ if (errno != EAGAIN) {
+ printf("a2dp_wait_connection failed (AVDTP socket) : %d (errno=%d:%s)\n", new_fd, errno, strerror(errno));
+ break;
+ }
+ }
+ }
- iThreadsRunning --;
+ close_socket(sockfd);
+ }
+ // Sleep a little bit if we must retry
+ sleep(bSigINTReceived ? 1 : 0);
+ }
- return 0;
+ iThreadsRunning--;
+
+ return 0;
}
// This function handle the bluetooth connection
-void* avrcp_listener(void* param)
+void *avrcp_listener(void *param)
{
- // We should not terminate the process if clients are still running
- iThreadsRunning ++;
+ // We should not terminate the process if clients are still running
+ iThreadsRunning++;
+
+ LPBTA2DPPERDEVICEDATA lpDevice = (LPBTA2DPPERDEVICEDATA) param;
+ pthread_detach(lpDevice->thread);
- LPBTA2DPPERDEVICEDATA lpDevice = (LPBTA2DPPERDEVICEDATA)param;
- pthread_detach(lpDevice->thread);
+ // As long as daemon is running
+ printf("avrcp: Accepting incoming connection\n");
+ while (!bSigINTReceived) {
+ int sockfd = a2dp_make_listen_socket(23);
+ if (sockfd >= 0) {
+ while (!bSigINTReceived) {
+ // Wait for incoming connections
+ char szRemote[64];
+ uint16_t iMTU = 0;
+
+ int new_fd = a2dp_wait_connection(sockfd, szRemote,
+ sizeof(szRemote),
+ &iMTU);
+
+ if (new_fd > 0) {
+ printf("avrcp: socket %d: Connection from %s, mtu=%d\n", new_fd, szRemote, iMTU);
+ // Loop and manage what the client sends
+ setup_socket(new_fd);
+ int iReceived = 0;
+ do {
+ printf("avrcp: socket %d: Reading from %s, mtu=%d\n", new_fd, szRemote, iMTU);
+ errno = 0;
+ iReceived = a2dp_handle_avrcp_message(new_fd);
+ }
+ // AVRCP need device connected
+ while (g_nbdeviceconnected && !bSigINTReceived && (iReceived > 0 || errno == EAGAIN));
+ printf("avrcp: socket %d: timed out\n", new_fd);
+ close_socket(new_fd);
+ } else if (errno != EAGAIN) {
+ printf("a2dp_wait_connection failed (AVRCP socket) : %d (errno=%d:%s)\n", new_fd, errno, strerror(errno));
+ break;
+ }
+ }
- // As long as daemon is running
- printf("avrcp: Accepting incoming connection\n");
- while(!bSigINTReceived)
- {
- int sockfd = a2dp_make_listen_socket( 23);
- if(sockfd>=0)
- {
- while(!bSigINTReceived)
- {
- // Wait for incoming connections
- char szRemote[64];
- uint16_t iMTU = 0;
-
- int new_fd = a2dp_wait_connection(sockfd, szRemote, sizeof(szRemote), &iMTU);
-
- if(new_fd>0)
- {
- printf("avrcp: socket %d: Connection from %s, mtu=%d\n", new_fd, szRemote, iMTU);
- // Loop and manage what the client sends
- setup_socket(new_fd);
- int iReceived = 0;
- do
- {
- iReceived = a2dp_handle_avrcp_message(new_fd);
- }
- // AVRCP need device connected
- while(g_nbdeviceconnected && !bSigINTReceived && (iReceived>0 || errno==EAGAIN));
- printf("avrcp: socket %d: timed out\n", new_fd);
- close_socket(new_fd);
- }
- else
- {
- if(errno!=EAGAIN)
- {
- printf("a2dp_wait_connection failed (AVRCP socket) : %d (errno=%d:%s)\n", new_fd, errno, strerror(errno));
- break;
- }
- }
- }
-
- close_socket(sockfd);
- }
-
- // Sleep a little bit if we must retry
- sleep(bSigINTReceived?1:0);
- }
+ close_socket(sockfd);
+ }
+ // Sleep a little bit if we must retry
+ sleep(bSigINTReceived ? 1 : 0);
+ }
- iThreadsRunning --;
+ iThreadsRunning--;
- return 0;
+ return 0;
}
// server processing loop
-void main_loop(char* addr)
+void main_loop(char *addr)
{
- while(!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, avrcp_listener, lpDevice);
- pthread_create(&lpDevice->thread, &tattr, avdtp_listener, lpDevice);
-
- while(!bSigINTReceived)
- {
- int new_fd = -1;
- printf("Accepting incoming tcp 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);
- }
-
- 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);
- }
- else
- {
- printf("Error %d: cannot get the socket errno=%d (%s)\n", sockfd, errno, strerror(errno));
- }
+ while (!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;
+ pthread_t havrcp, havdtp;
+ 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);
+ if (g_bavrcp)
+ pthread_create(&havrcp, &tattr, avrcp_listener, lpDevice);
+ if (g_bavrcp)
+ pthread_create(&havdtp, &tattr, avdtp_listener, lpDevice);
+
+ while (!bSigINTReceived) {
+ int new_fd = -1;
+ printf("main_thread:Accepting incoming tcp stream connection\n");
+ new_fd = accept_socket(sockfd);
+ printf("main_thread: Accepted %d\n", new_fd);
+
+ // Handle connection if it is not the final dummy client
+ if (!bSigINTReceived && new_fd > 0) {
+ 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 if (new_fd > 0) {
+ close_socket(new_fd);
+ }
+ 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);
+ } else {
+ printf("Error %d: cannot get the socket errno=%d (%s)\n", sockfd, errno, strerror(errno));
+ }
- sleep(1);
- }
+ sleep(1);
+ }
}
@@ -1045,90 +1004,73 @@
// main function
int main(int argc, char *argv[])
{
- int i = 0;
- int fd;
- struct timespec timer_resolution = { 0, 0 };
- char address[256] = "";
- char* addr = &address[0];
- char* sonorix="00:0A:56:00:C0:C2";
- //char* iphono420= "C2:00:08:F4:30:07:64";
- //char* hpheadphone= "00:0D:44:2A:17:C7";
- struct sched_param schedparam = { sched_get_priority_max(SCHED_FIFO) };
- int res=0, bFork=0, bVerbose=1, bKill=0;
+ int i = 0;
+ struct timespec timer_resolution = { 0, 0 };
+ char address[256] = "";
+ char *addr = &address[0];
+ char *sonorix = "00:0A:56:00:C0:C2";
+ //char* iphono420= "C2:00:08:F4:30:07:64";
+ //char* hpheadphone= "00:0D:44:2A:17:C7";
+ struct sched_param schedparam = { sched_get_priority_max(SCHED_FIFO) };
+ int res = 0, bFork = 0, bVerbose = 1, bKill = 0, fd = 0;
FILE *fp;
pid_t pid;
- // Read config values from config file
- get_config_filename(g_srcfilename, sizeof(g_srcfilename));
- read_config_string(g_srcfilename, "a2dpd", "address", address, sizeof(address), sonorix);
- read_config_string(g_srcfilename, "a2dpd", "cmdplay", g_sCmdPlay, sizeof(g_sCmdPlay), "");
- read_config_string(g_srcfilename, "a2dpd", "cmdpause", g_sCmdPause, sizeof(g_sCmdPause), "");
- read_config_string(g_srcfilename, "a2dpd", "cmdprev", g_sCmdPrev, sizeof(g_sCmdPrev), "");
- read_config_string(g_srcfilename, "a2dpd", "cmdnext", g_sCmdNext, sizeof(g_sCmdNext), "");
- read_config_string(g_srcfilename, "a2dpd", "cmdnew", g_sCmdNew, sizeof(g_sCmdNew), "");
- read_config_string(g_srcfilename, "a2dpd", "logfile", g_sOutputFilename, sizeof(g_sOutputFilename), "/dev/null");
-
- // Parse command line parameters
- for(i=1; i<argc && argv[i]!=NULL; i++)
- {
- char c;
- // Search a bluetooth addr
- 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 if(!strcmp(argv[i], "-n"))
- {
- bFork=0;
- }
- else if(!strcmp(argv[i], "-d"))
- {
- bFork=1;
- }
- else if(!strcmp(argv[i], "-v"))
- {
- bVerbose=1;
- }
- else if(!strcmp(argv[i], "-k"))
- {
- bKill=1;
- }
- else if(!strcmp(argv[i], "+n"))
- {
- bFork=1;
- }
- else if(!strcmp(argv[i], "+d"))
- {
- bFork=0;
- }
- else if(!strcmp(argv[i], "+v"))
- {
- bVerbose=0;
- }
- else
- {
- printf("Parameter not handled: %s\r\n", argv[i]);
- }
- }
- clock_getres(CLOCK_REALTIME, &timer_resolution);
-
- init_uinput ();
-
- ignore_child_processes_return_values();
-
- // Redirect outputs
- make_daemon_process(bFork, bVerbose, g_sOutputFilename);
+ // Read config values from config file
+ get_config_filename(g_srcfilename, sizeof(g_srcfilename));
+ read_config_string(g_srcfilename, "a2dpd", "address", address, sizeof(address), sonorix);
+ read_config_string(g_srcfilename, "a2dpd", "cmdplay", g_sCmdPlay, sizeof(g_sCmdPlay), "");
+ read_config_string(g_srcfilename, "a2dpd", "cmdpause", g_sCmdPause, sizeof(g_sCmdPause), "");
+ read_config_string(g_srcfilename, "a2dpd", "cmdprev", g_sCmdPrev, sizeof(g_sCmdPrev), "");
+ read_config_string(g_srcfilename, "a2dpd", "cmdnext", g_sCmdNext, sizeof(g_sCmdNext), "");
+ read_config_string(g_srcfilename, "a2dpd", "cmdnew", g_sCmdNew, sizeof(g_sCmdNew), "");
+ read_config_string(g_srcfilename, "a2dpd", "logfile", g_sOutputFilename, sizeof(g_sOutputFilename), "/dev/null");
+ g_brereadconfig = read_config_int(g_srcfilename, "a2dpd", "enablerereadconfig", 1);
+ g_breversestereo = read_config_int(g_srcfilename, "a2dpd", "enablereversestereo", 0);
+ g_bavrcp = read_config_int(g_srcfilename, "a2dpd", "enableavrcp", 1);
+
+ // Parse command line parameters
+ for (i = 1; i < argc && argv[i] != NULL; i++) {
+ char c;
+ // Search a bluetooth addr
+ 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 if (!strcmp(argv[i], "-n")) {
+ bFork = 0;
+ } else if (!strcmp(argv[i], "-d")) {
+ bFork = 1;
+ } else if (!strcmp(argv[i], "-v")) {
+ bVerbose = 1;
+ } else if (!strcmp(argv[i], "-k")) {
+ bKill = 1;
+ } else if (!strcmp(argv[i], "+n")) {
+ bFork = 1;
+ } else if (!strcmp(argv[i], "+d")) {
+ bFork = 0;
+ } else if (!strcmp(argv[i], "+v")) {
+ bVerbose = 0;
+ } else {
+ printf("Parameter not handled: %s\r\n", argv[i]);
+ }
+ }
+ clock_getres(CLOCK_REALTIME, &timer_resolution);
+
+ init_uinput();
+ ignore_child_processes_return_values();
+
+ // Redirect outputs
+ make_daemon_process(bFork, bVerbose, g_sOutputFilename);
// Generate the lockfile
fd = open(PIDFILE, O_RDWR | O_CREAT | O_EXCL, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
if (fd == -1) {
- if (errno != EEXIST) // If we can't write the lock, then ignore
+ if (errno != EEXIST) // If we can't write the lock, then ignore
goto post_lock;
-
+
if ((fd = open(PIDFILE, O_RDWR)) < 0)
goto post_lock;
-
+
fp = fdopen(fd, "rw");
if (fp == NULL)
goto post_lock;
@@ -1136,25 +1078,24 @@
pid = -1;
if ((fscanf(fp, "%d", &pid) != 1) || (pid == getpid())
|| (lock_fd(fileno(fp)) == 0)) {
- unlink (PIDFILE);
+ unlink(PIDFILE);
} else {
if (bKill) {
- kill (pid, 15);
- sleep (5); // let the other daemon die
+ kill(pid, 15);
+ sleep(5); // let the other daemon die
} else
goto shutdown;
}
fclose(fp);
unlink(PIDFILE);
- fd = open(PIDFILE, O_RDWR | O_CREAT | O_EXCL,
- S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
+ fd = open(PIDFILE, O_RDWR | O_CREAT | O_EXCL, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
if (fd == -1)
goto post_lock;
-
+
}
-
+
lock_fd(fd);
fp = fdopen(fd, "w");
@@ -1162,31 +1103,30 @@
fflush(fp);
fcntl(fd, F_SETFD, (long) 1);
- post_lock:
- printf("%s addr=%s timer=%d us [%s %s]\n", argv[0], addr, (int)(timer_resolution.tv_nsec/1000), __DATE__, __TIME__);
+ post_lock:
+ printf("%s addr=%s timer=%d us [%s %s]\n", argv[0], addr, (int) (timer_resolution.tv_nsec / 1000), __DATE__, __TIME__);
- // If we can be realtime it will be better
- res = sched_setscheduler(0, SCHED_FIFO, &schedparam);
- printf("setscheduler returns %d (errno=%d:%s)\n", res, errno, strerror(errno));
+ // If we can be realtime it will be better
+ res = sched_setscheduler(0, SCHED_FIFO, &schedparam);
+ printf("setscheduler returns %d (errno=%d:%s)\n", res, errno, strerror(errno));
- // set up the handler
- signal(SIGINT, sigint_handler);
- signal(SIGTERM, sigint_handler);
+ // set up the handler
+ signal(SIGINT, sigint_handler);
+ signal(SIGTERM, sigint_handler);
- // global initialisations
- a2dp_init();
+ // global initialisations
+ a2dp_init();
- // Run main loop
- main_loop(addr);
+ // Run main loop
+ main_loop(addr);
- // global free
- a2dp_exit();
+ // global free
+ a2dp_exit();
kill_uinput();
-shutdown:
- printf("A2DPD terminated succesfully\n");
+ shutdown:
+ printf("A2DPD terminated succesfully\n");
- return 0;
+ return 0;
}
-
Index: alsa-plugins/a2dpd_protocol.h
===================================================================
RCS file: /cvsroot/bluetooth-alsa/btsco/alsa-plugins/a2dpd_protocol.h,v
retrieving revision 1.3
diff -u -r1.3 a2dpd_protocol.h
--- alsa-plugins/a2dpd_protocol.h 17 Aug 2006 14:06:27 -0000 1.3
+++ alsa-plugins/a2dpd_protocol.h 31 Aug 2006 15:58:57 -0000
@@ -26,12 +26,11 @@
// 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;
+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 }
@@ -44,8 +43,8 @@
#define A2DPD_VOLUME_MIN 0
#define A2DPD_VOLUME_MAX 15
-#define A2DPD_FRAME_BYTES 4 // 16bits * 2 channels
-#define A2DPD_FRAME_RATE 44100 // Can be 32000, tested with HP, iPhono and needed Sonorix, but quality decreases, 48000 nearly never works
+#define A2DPD_FRAME_BYTES 4 // 16bits * 2 channels
+#define A2DPD_FRAME_RATE 44100 // Can be 32000, tested with HP, iPhono and needed Sonorix, but quality decreases, 48000 nearly never works
// a2dp->sbc.channels*44100*2/(size*a2dp->frame_bytes);
// 344.53125=channels*freq*16 bits/sizeof(buf)
#define A2DPD_BLOCK_SIZE (512*1)
Index: alsa-plugins/a2dplib.c
===================================================================
RCS file: /cvsroot/bluetooth-alsa/btsco/alsa-plugins/a2dplib.c,v
retrieving revision 1.5
diff -u -r1.5 a2dplib.c
--- alsa-plugins/a2dplib.c 30 Aug 2006 14:43:21 -0000 1.5
+++ alsa-plugins/a2dplib.c 31 Aug 2006 15:58:57 -0000
@@ -79,7 +79,7 @@
#define A2DP_SERVICE_NAME "A2DP Audio Source"
#define A2DP_VERSION 0x0100
-static struct sigaction actions;
+static struct sigaction actions;
/*
sdp_record_t* a2dp_advertise_sdp(sdp_session_t* sdpSessionP)
{
@@ -158,1128 +158,1026 @@
void a2dp_init(void) __attribute__ ((constructor));
void a2dp_exit(void) __attribute__ ((destructor));
*/
-void memcpy_changeendian( void* dst, const void *src, int size)
+void memcpy_changeendian(void *dst, const void *src, int size)
{
- int i;
- const uint16_t* ptrsrc=src;
- uint16_t* ptrdst=dst;
- for(i = 0; i < size/2; i ++)
- {
- *ptrdst++ = htons(*ptrsrc++);
- }
+ int i;
+ const 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)
+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 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;
-
- memset(&put_req, 0, sizeof(put_req));
- init_request(&put_req.header, AVDTP_GET_CAPABILITIES);
- put_req.acp_seid = seid;
+ 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;
+
+ 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);
+ }
- if (write(s, &put_req, sizeof(put_req)) != sizeof(put_req))
- {
- DBG("Couldn't request capabilities for SEID = %d", seid);
- return (-1);
- }
+ 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);
+ }
- 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:\nservcap_cap=%d, servcap_len=%d,\ncap_type=%d, length=%d, media_type=%d, codec=%d",
+ cap_resp.serv_cap, cap_resp.serv_cap_len, cap_resp.cap_type, cap_resp.length, cap_resp.media_type, cap_resp.media_codec_type);
- DBG("Got capabilities response:\nservcap_cap=%d, servcap_len=%d,\ncap_type=%d, length=%d, media_type=%d, codec=%d",
- cap_resp.serv_cap,
- cap_resp.serv_cap_len,
- cap_resp.cap_type,
- cap_resp.length,
- cap_resp.media_type,
- cap_resp.media_codec_type
- );
-
- 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; //FIXME 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;
+ 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; //FIXME 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->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->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;
+ 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.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.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.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 (!(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);
- }
+ if (write(s, &s_config, sizeof(s_config)) != sizeof(s_config)) {
+ DBG("couldn't set config seid = %d", seid);
+ return (-1);
+ }
- size = read(s, &s_resp, sizeof(s_resp));
- DBG("Got Set Configurations Response (%d bytes:msgtype=%d,pkttype=%d,lbl=%d,sig=%d,rfa=%d)",
- size,
- s_resp.header.message_type,
- s_resp.header.packet_type,
- s_resp.header.transaction_label,
- s_resp.header.signal_id,
- s_resp.header.rfa0);
-
- 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);
- }
+ size = read(s, &s_resp, sizeof(s_resp));
+ DBG("Got Set Configurations Response (%d bytes:msgtype=%d,pkttype=%d,lbl=%d,sig=%d,rfa=%d)",
+ size, s_resp.header.message_type, s_resp.header.packet_type, s_resp.header.transaction_label, s_resp.header.signal_id, s_resp.header.rfa0);
+
+ 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);
+ }
- 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);
- }
+ 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);
+ }
- *psm = 25;
- return 0;
+ *psm = 25;
+ return 0;
}
int test_sdp(dst)
{
int result = 0;
-
+
return result;
}
// Connecting on PSM 25
-int do_connect(bdaddr_t *src, bdaddr_t *dst, unsigned short psm, uint16_t *mtu)
+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;
-
- sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
- if (sk < 0) {
- DBG( "Can't create socket. %s(%d)",
- strerror(errno), errno);
- return -1;
- }
-
- // Set connection timeout
- struct timeval t = { 3, 0 };
- setsockopt( sk, SOL_SOCKET, SO_SNDTIMEO, &t, sizeof(t));
- setsockopt( sk, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(t));
-
- 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;
- }
+ struct sockaddr_l2 addr;
+ struct l2cap_options opts;
+ int sk;
+ unsigned int opt;
+ int tries;
+
+ sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
+ if (sk < 0) {
+ DBG("Can't create socket. %s(%d)", strerror(errno), errno);
+ return -1;
+ }
+ // Set connection timeout
+ struct timeval t = { 3, 0 };
+ setsockopt(sk, SOL_SOCKET, SO_SNDTIMEO, &t, sizeof(t));
+ setsockopt(sk, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(t));
+
+ 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;
+ }
- /* 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;
- }
+ /* 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;
+ }
- 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);
- if(++tries > NBSDPRETRIESMAX) {
- close(sk);
- return -1;
- }
- sleep(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;
- }
+ /* 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;
+ }
- //DBG( "Connected psm=%d sk=%d [imtu %d, omtu %d, flush_to %d]", psm, sk, opts.imtu, opts.omtu, opts.flush_to);
+ 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);
+ if (++tries > NBSDPRETRIESMAX) {
+ close(sk);
+ return -1;
+ }
+ sleep(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;
+ }
+ //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 (mtu)
+ *mtu = opts.omtu;
- return sk;
+ return sk;
}
// 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)
+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;
+ 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;
// Try to connect an L2CAP socket to the sdp psm with short timeout for user interaction
int tmpsk = do_connect(src, dst, 1, NULL);
- if(tmpsk>0)
- {
+ if (tmpsk > 0) {
close(tmpsk);
- }
- else
- {
- DBG( "Warning: failed to connect to SDP server");
+ } else {
+ DBG("Warning: failed to connect to SDP server");
return -1;
}
- tries = 0;
- while(!(sess = sdp_connect(src, dst, SDP_RETRY_IF_BUSY))) {
- DBG("retrying sdp connect: %s", strerror(errno));
- if(++tries > NBSDPRETRIESMAX) {
- break;
- }
- sleep(1);
- }
- if (!sess) {
- DBG( "Warning: failed to connect to SDP server");
- 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;
+ tries = 0;
+ while (!(sess = sdp_connect(src, dst, SDP_RETRY_IF_BUSY))) {
+ DBG("retrying sdp connect: %s", strerror(errno));
+ if (++tries > NBSDPRETRIESMAX) {
+ break;
+ }
+ sleep(1);
+ }
+ if (!sess) {
+ DBG("Warning: failed to connect to SDP server");
+ if (psm)
+ *psm = 25;
+ if (flags)
+ *flags = 0;
+ return 0;
+ }
- DBG( "Found A2DP Sink");
- if (psm)
- *psm = 25;
-
- next = seq->next;
- free(seq);
- sdp_record_free(rec);
- }
+ /* 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;
+ }
- 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;
- }
+ for (; seq; seq = next) {
+ sdp_record_t *rec = (sdp_record_t *) seq->data;
- next = seq->next;
- free(seq);
- sdp_record_free(rec);
- }
+ DBG("Found A2DP Sink");
+ if (psm)
+ *psm = 25;
+
+ next = seq->next;
+ free(seq);
+ sdp_record_free(rec);
+ }
-done:
- sdp_close(sess);
- return 0;
-}
-
-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;
-
- 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);
- }
+ 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);
+ }
- psm_cmd=25;
- cmdfd = do_connect(src, dst, psm_cmd, &mtu);
- if (cmdfd < 0) {
- DBG( "cannot open psm_cmd = %d", psm_cmd);
- return -1;
- }
+ done:
+ sdp_close(sess);
+ return 0;
+}
+
+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;
- // 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));
+ 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);
+ }
- // SONORIX sends us a discover signal we should answer but we will discard
- while(tries<10)
- {
- size=a2dp_handle_avdtp_message(NULL, cmdfd, &discover_req.header, &discover_resp.header, sizeof(discover_resp));
- if(size>0)
- {
- // Answer to what we send
- break;
- }
- else
- {
- // Not answer
- usleep(100);
- tries++;
- }
- }
+ psm_cmd = 25;
+ cmdfd = do_connect(src, dst, psm_cmd, &mtu);
+ if (cmdfd < 0) {
+ DBG("cannot open psm_cmd = %d", psm_cmd);
+ return -1;
+ }
+ // 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));
- 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;
- }
+ // SONORIX sends us a discover signal we should answer but we will discard
+ while (tries < 10) {
+ size = a2dp_handle_avdtp_message(NULL, cmdfd, &discover_req.header, &discover_resp.header, sizeof(discover_resp));
+ if (size > 0) {
+ // Answer to what we send
+ break;
+ } else {
+ // Not answer
+ usleep(100);
+ tries++;
+ }
+ }
- seid = -1;
- nb_seid = (size-sizeof(discover_resp.header))/sizeof(struct acp_seid_info);
+ 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;
+ }
- DBG("received %d capabilities", nb_seid);
+ seid = -1;
+ nb_seid = (size - sizeof(discover_resp.header)) / sizeof(struct acp_seid_info);
- 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;
- }
- }
+ DBG("received %d capabilities", nb_seid);
- if(seid == -1) {
- //We have not found the seid that we want
- DBG("couldn't locate the correct seid");
- return -1;
- }
+ 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;
+ }
+ }
- // open the stream
- streamfd = do_connect(src, dst, psm_stream, &mtu);
- if (streamfd < 0) {
- DBG("cannot open psm_stream = %d", psm_stream);
- return -1;
- }
+ 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
- // 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;
+ }
- 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);
- 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);
+ }
- 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");
- DBG("Got start stream confirm");
+ *omtu = A2DPMAXIMUMTRANSFERUNITSIZE; //mtu;
+ *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;
- *omtu = A2DPMAXIMUMTRANSFERUNITSIZE; //mtu;
- *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;
// We have pcm data to send through bluetooth
-int a2dp_transfer_raw(LPA2DP a2dp, const char* pcm_buffer, int pcm_buffer_size)
+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;
- int written;
-
- // Check parameter
- if(a2dp==0 || pcm_buffer==0 || pcm_buffer_size==0) return EINVAL;
-
- // How much data can be encoded by sbc at a time?
- // 16 bits * 2 channels * 16 blocks * 8 subbands = 4096bits = 512 o
- codesize=a2dp->sbc.subbands*a2dp->sbc.blocks*a2dp->sbc.channels*2;
- // 44 bitpool?
- //codesize=a2dp->sbc.bitpool*a2dp->sbc.subbands*a2dp->sbc.blocks/8;
- datatoread=min(codesize,pcm_buffer_size);
-
- // Enqueue data in bufe
- if(a2dp->lenbufe+datatoread < BUFS)
- {
- // Append data to bufe, for sbc encoding
- memcpy_changeendian(a2dp->bufe+a2dp->lenbufe, pcm_buffer, datatoread);
- a2dp->lenbufe+=datatoread;
- }
- else
- {
- datatoread=0;
- }
-
-
- // If bufe is full, encode
- if(a2dp->lenbufe>=codesize)
- {
- // Enough data to encode (sbc wants 1k blocks)
- int encoded;
- encoded = sbc_encode(&(a2dp->sbc), a2dp->bufe, codesize); //encode
-
- if (encoded <= 0)
- return encoded;
-
- memmove(a2dp->bufe, a2dp->bufe + encoded, a2dp->lenbufe - encoded); // Shift the bufe
- a2dp->lenbufe -= encoded;
-
- // Send data through bluetooth
- if(a2dp->len + a2dp->sbc.len >= a2dp->mtu)
- {
- // time to prepare and send the packet
- 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.cc = 0;
- 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));
- if(a2dp->sk>0)
- {
- // Check if data are to be read
- // Not seen a device showing this yet
- fd_set readfds;
- struct timeval zero_timeout = {0,0};
- FD_ZERO(&readfds);
- FD_SET(a2dp->sk, &readfds);
- int iselect=select(1, &readfds, NULL, NULL, &zero_timeout);
- if(iselect>0)
- {
- if(FD_ISSET(a2dp->sk, &readfds))
- {
- a2dp_handle_avdtp_message(a2dp, a2dp->sk, NULL, NULL, 0);
- }
- }
- // Pause?
- // The value 0 have never been tested
- // However, we may safely simulate a failed write
- if(!a2dp->pause_writing)
- {
- // Send our data
- if((written = write(a2dp->sk,a2dp->buf,a2dp->len)) != a2dp->len)
- {
- // Error while sending data
- DBG("Wrote %d not %d bytes; (errno=%d:%s)", written, a2dp->len, errno,
- strerror(errno));
- result = written;
- }
- result = written;
- }
- else
- {
- // Make the upper layer believe we sent data
- result = a2dp->len;
- }
- }
+ // No error
+ 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;
+
+ // How much data can be encoded by sbc at a time?
+ // 16 bits * 2 channels * 16 blocks * 8 subbands = 4096bits = 512 o
+ codesize = a2dp->sbc.subbands * a2dp->sbc.blocks * a2dp->sbc.channels * 2;
+ // 44 bitpool?
+ //codesize=a2dp->sbc.bitpool*a2dp->sbc.subbands*a2dp->sbc.blocks/8;
+ datatoread = min(codesize, pcm_buffer_size);
+
+ // Enqueue data in bufe
+ if (a2dp->lenbufe + datatoread < BUFS) {
+ // Append data to bufe, for sbc encoding
+ memcpy_changeendian(a2dp->bufe + a2dp->lenbufe, pcm_buffer, datatoread);
+ a2dp->lenbufe += datatoread;
+ } else {
+ datatoread = 0;
+ }
- // Reset buffer of data to send
- a2dp->len = sizeof(struct media_packet_header)+sizeof(struct media_payload_header);
- a2dp->frame_count=0;
- a2dp->seq_num++;
- }
- // 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;
- }
+ // If bufe is full, encode
+ if (a2dp->lenbufe >= codesize) {
+ // Enough data to encode (sbc wants 1k blocks)
+ int encoded;
+ encoded = sbc_encode(&(a2dp->sbc), a2dp->bufe, codesize); //encode
+
+ if (encoded <= 0)
+ return encoded;
+
+ memmove(a2dp->bufe, a2dp->bufe + encoded, a2dp->lenbufe - encoded); // Shift the bufe
+ a2dp->lenbufe -= encoded;
+
+ // Send data through bluetooth
+ if (a2dp->len + a2dp->sbc.len >= a2dp->mtu) {
+ // time to prepare and send the packet
+ 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.cc = 0;
+ 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));
+ if (a2dp->sk > 0) {
+ // Check if data are to be read
+ // Not seen a device showing this yet
+ fd_set readfds;
+ struct timeval zero_timeout = { 0, 0 };
+ FD_ZERO(&readfds);
+ FD_SET(a2dp->sk, &readfds);
+ int iselect = select(1, &readfds, NULL, NULL, &zero_timeout);
+ if (iselect > 0) {
+ if (FD_ISSET(a2dp->sk, &readfds)) {
+ a2dp_handle_avdtp_message(a2dp, a2dp->sk, NULL, NULL, 0);
+ }
+ }
+ // Pause?
+ // The value 0 have never been tested
+ // However, we may safely simulate a failed write
+ if (!a2dp->pause_writing) {
+ // Send our data
+ if ((written = write(a2dp->sk, a2dp->buf, a2dp->len)) != a2dp->len) {
+ // Error while sending data
+ DBG("Wrote %d not %d bytes; (errno=%d:%s)", written, a2dp->len, errno, strerror(errno));
+ result = written;
+ }
+ result = written;
+ } else {
+ // Make the upper layer believe we sent data
+ result = a2dp->len;
+ }
+ }
+ // Reset buffer of data to send
+ a2dp->len = sizeof(struct media_packet_header) + sizeof(struct media_payload_header);
+ a2dp->frame_count = 0;
+ a2dp->seq_num++;
+ }
+ // 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;
+ }
- return result;
+ return result;
}
-static void init_response(struct avdtp_header * header, int response_type)
+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;
- if(a2dp->control_sk<0)
- {
- DBG("Listen thread not started [control_sk=%d]", a2dp->control_sk);
+ if (a2dp->control_sk < 0) {
+ DBG("Listen thread not started [control_sk=%d]", a2dp->control_sk);
return NULL;
- }
-
- DBG("Listen thread running [control_sk=%d]", a2dp->control_sk);
+ }
- // Set a timeout to close thread
- struct timeval t = { 1, 0 };
- setsockopt( a2dp->control_sk, SOL_SOCKET, SO_SNDTIMEO, &t, sizeof(t));
- setsockopt( a2dp->control_sk, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(t));
+ DBG("Listen thread running [control_sk=%d]", a2dp->control_sk);
- // Loop until end of writing
- while(!a2dp->stop_writing)
- {
- char szBuffer[A2DPMAXIMUMTRANSFERUNITSIZE];
- struct stream_cmd* cmd = (struct stream_cmd*)szBuffer;
- if(a2dp_handle_avdtp_message(a2dp, a2dp->control_sk, NULL, NULL, 0)<0)
- {
- // Error
- usleep(100*1000);
- }
-
- int size = read(a2dp->control_sk, szBuffer, sizeof(szBuffer));
- if(size>0)
- {
- if(cmd->header.signal_id == AVDTP_SUSPEND)
- {
- DBG("Received signal AVDTP_SUSPEND(%d) from set", cmd->header.signal_id);
- a2dp->pause_writing = 1;
- }
- else if(cmd->header.signal_id == AVDTP_START)
- {
- DBG("Received signal AVDTP_START(%d) from set", cmd->header.signal_id);
- a2dp->pause_writing = 0;
- }
- else
- {
- DBG("Unexpected headset directive %d", cmd->header.signal_id);
- }
- // ack the command regardless
- //FIXME 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", cmd->header.signal_id);
- }
- }
- else
- {
- if(errno!=EAGAIN)
- DBG("Error while receiving %d (errno=%d:%s)", size, errno, strerror(errno));
- if(errno!=EINTR)
- break;
- }
- }
+ // Set a timeout to close thread
+ struct timeval t = { 1, 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) {
+ char szBuffer[A2DPMAXIMUMTRANSFERUNITSIZE];
+ struct stream_cmd *cmd = (struct stream_cmd *) szBuffer;
+ if (a2dp_handle_avdtp_message(a2dp, a2dp->control_sk, NULL, NULL, 0) < 0) {
+ // Error
+ usleep(100 * 1000);
+ }
+
+ int size = read(a2dp->control_sk, szBuffer, sizeof(szBuffer));
+ if (size > 0) {
+ if (cmd->header.signal_id == AVDTP_SUSPEND) {
+ DBG("Received signal AVDTP_SUSPEND(%d) from set", cmd->header.signal_id);
+ a2dp->pause_writing = 1;
+ } else if (cmd->header.signal_id == AVDTP_START) {
+ DBG("Received signal AVDTP_START(%d) from set", cmd->header.signal_id);
+ a2dp->pause_writing = 0;
+ } else {
+ DBG("Unexpected headset directive %d", cmd->header.signal_id);
+ }
+ // ack the command regardless
+ //FIXME 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", cmd->header.signal_id);
+ }
+ } else {
+ if (errno != EAGAIN)
+ DBG("Error while receiving %d (errno=%d:%s)", size, errno, strerror(errno));
+ if (errno != EINTR)
+ break;
+ }
+ }
- return NULL;
+ return NULL;
}
-int a2dp_connect(snd_pcm_a2dp_t *a2dp)
+int a2dp_connect(snd_pcm_a2dp_t * a2dp)
{
- //struct sockaddr_rc addr;
- //socklen_t len;
- int sk = -1;
- int control_sk = -1;
- errno=0;
- /*
- 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);
+ //struct sockaddr_rc addr;
+ //socklen_t len;
+ int sk = -1;
+ int control_sk = -1;
+ errno = 0;
+ /*
+ 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;
- //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;
-
- if(sk>0)
- {
+ if (sk > 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 sk;
+ return sk;
}
snd_pcm_a2dp_t *a2dp_alloc(void)
{
- snd_pcm_a2dp_t *a2dp;
- 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);
- a2dp->sbc.rate = A2DPD_FRAME_RATE;
- a2dp->sbc.subbands = 8; // safe default
- a2dp->sbc.blocks = 16; // safe default
- a2dp->sbc.bitpool = 32; // recommended value 53, safe default is 32
- return a2dp;
-}
-
-void a2dp_free(snd_pcm_a2dp_t *a2dp)
-{
- DBG("");
- if (a2dp->sk > 0)
- close(a2dp->sk);
- if (a2dp->control_sk > 0)
- close(a2dp->control_sk);
+ snd_pcm_a2dp_t *a2dp;
+ a2dp = malloc(sizeof(*a2dp));
+ if (!a2dp)
+ return NULL;
- sbc_finish(&a2dp->sbc);
+ 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);
+ a2dp->sbc.rate = A2DPD_FRAME_RATE;
+ a2dp->sbc.subbands = 8; // safe default
+ a2dp->sbc.blocks = 16; // safe default
+ a2dp->sbc.bitpool = 32; // recommended value 53, safe default is 32
+ return a2dp;
+}
+
+void a2dp_free(snd_pcm_a2dp_t * a2dp)
+{
+ DBG("");
+ if (a2dp->sk > 0)
+ close(a2dp->sk);
+ if (a2dp->control_sk > 0)
+ close(a2dp->control_sk);
- free(a2dp);
+ sbc_finish(&a2dp->sbc);
+
+ free(a2dp);
}
static void sighand(int signo)
{
- return;
+ return;
}
void a2dp_init(void)
{
- // 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);
- */
+ // 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)
{
}
-LPA2DP a2dp_new(char* addr, int framerate)
+LPA2DP a2dp_new(char *addr, int framerate)
{
- snd_pcm_a2dp_t *a2dp = NULL;
- bdaddr_t src, dst;
- int err; //, pos = -1, use_rfcomm = 0;
-
- DBG("%s, %d", addr, framerate);
-
- bacpy(&src, BDADDR_ANY);
- bacpy(&dst, BDADDR_ANY);
- str2ba(addr, &dst);
-
- a2dp = a2dp_alloc();
- if (!a2dp) {
- DBG("Can't allocate");
- return NULL;
- }
- if(a2dp) a2dp->sbc.rate=framerate;
+ snd_pcm_a2dp_t *a2dp = NULL;
+ bdaddr_t src, dst;
+ int err; //, pos = -1, use_rfcomm = 0;
- 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;
- }
+ DBG("%s, %d", addr, framerate);
- return a2dp;
+ bacpy(&src, BDADDR_ANY);
+ bacpy(&dst, BDADDR_ANY);
+ str2ba(addr, &dst);
-error:
- a2dp_free(a2dp);
- return NULL;
-}
+ a2dp = a2dp_alloc();
+ if (!a2dp) {
+ DBG("Can't allocate");
+ return NULL;
+ }
+ if (a2dp)
+ a2dp->sbc.rate = framerate;
-void a2dp_destroy(LPA2DP a2dp)
-{
- struct stream_cmd close_stream;
- struct close_stream_rsp close_resp;
+ 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;
+ }
- 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));
-
- // 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;
- // Use control_sk if it is needed
- if((a2dp->control_sk>0 && (write(a2dp->control_sk, &close_stream, sizeof(close_stream)) != sizeof(close_stream)))
- // Else use sk
- || (write(a2dp->sk, &close_stream, sizeof(close_stream)) != sizeof(close_stream))
- )
- {
- DBG("Couldn't send close_stream (errno=%d:%s)", errno, strerror(errno));
- }
+ return a2dp;
- a2dp_free(a2dp);
- DBG("a2dp_destroy(%p) OK", a2dp);
+ error:
+ a2dp_free(a2dp);
+ return NULL;
}
-int a2dp_make_listen_socket(unsigned short psm)
+void a2dp_destroy(LPA2DP a2dp)
{
- 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.";
- }
+ struct stream_cmd close_stream;
+ struct close_stream_rsp close_resp;
- if(lpszError)
- {
- DBG("%s %s(%d)", lpszError, strerror(errno), errno);
- close(sockfd);
- sockfd=-1;
- }
-
- return sockfd;
+ 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));
+
+ // 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;
+ // Use control_sk if it is needed
+ if ((a2dp->control_sk > 0 && (write(a2dp->control_sk, &close_stream, sizeof(close_stream)) != sizeof(close_stream)))
+ // Else use sk
+ || (write(a2dp->sk, &close_stream, sizeof(close_stream)) != sizeof(close_stream))
+ ) {
+ DBG("Couldn't send close_stream (errno=%d:%s)", errno, strerror(errno));
+ }
+
+ a2dp_free(a2dp);
+ DBG("a2dp_destroy(%p) OK", a2dp);
}
-int a2dp_wait_connection( int sockfd, char* szRemote, int iRemoteSize, uint16_t *mtu)
+int a2dp_make_listen_socket(unsigned short psm)
{
- // Wait client connection
- struct sockaddr_l2 addr;
- socklen_t addrlen = sizeof(addr);
-
- // Timeouts each second to read variables
- struct timeval t = { 1, 0 };
- setsockopt( sockfd, SOL_SOCKET, SO_SNDTIMEO, &t, sizeof(t));
- setsockopt( sockfd, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(t));
+ char *lpszError = NULL;
+ int sockfd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
- int new_fd = accept(sockfd, (struct sockaddr *) &addr, &addrlen);
+ 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 (szRemote) *szRemote='\0';
+ if (lpszError) {
+ DBG("%s %s(%d)", lpszError, strerror(errno), errno);
+ close(sockfd);
+ sockfd = -1;
+ }
- 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]", opts.imtu, opts.omtu, opts.flush_to);
+ return sockfd;
+}
- if (szRemote)
- {
- strncpy(szRemote, batostr(&addr.l2_bdaddr), iRemoteSize);
- szRemote[iRemoteSize-1] = '\0';
- }
- }
- return new_fd;
+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);
+
+ // Timeouts each second to read variables
+ struct timeval t = { 1, 0 };
+ setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &t, sizeof(t));
+ setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(t));
+
+ int new_fd = accept(sockfd, (struct sockaddr *) &addr, &addrlen);
+
+ 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]", opts.imtu, opts.omtu, opts.flush_to);
+
+ if (szRemote) {
+ strncpy(szRemote, batostr(&addr.l2_bdaddr), iRemoteSize);
+ szRemote[iRemoteSize - 1] = '\0';
+ }
+ }
+ return new_fd;
}
// This function handle the bluetooth connection
-int a2dp_handle_avdtp_message(LPA2DP a2dp, int sockfd, struct avdtp_header* sent_packet, struct avdtp_header* answer, int answer_size)
+int a2dp_handle_avdtp_message(LPA2DP a2dp, int sockfd, struct avdtp_header *sent_packet, struct avdtp_header *answer, int answer_size)
{
- int result = 0;
- int wrresult = 0;
-
- char lpFrame [A2DPMAXIMUMTRANSFERUNITSIZE];
- int iReceived = recv(sockfd, lpFrame, sizeof(lpFrame), 0);
- struct avdtp_header* pkt_hdr = (struct avdtp_header*)lpFrame;
- if(iReceived>0)
- {
- // Manage the packet
- if(sent_packet==NULL)
- {
- int i;
- printf("socket %d: Received %d bytes\n", sockfd, iReceived);
- for(i = 0; i<iReceived; i++)
- {
- char c=lpFrame[i];
- if(i%16==0) printf("%05d: ", i);
- printf("%02x ", c);
- if(i%16==15) printf("\n");
- }
- printf("\n");
- result=0;
- }
- else if((pkt_hdr->message_type == MESSAGE_TYPE_ACCEPT) &&(pkt_hdr->signal_id == sent_packet->signal_id)
- )
- {
- // Got expected answer
- memcpy(answer, lpFrame, answer_size>iReceived?answer_size:iReceived);
- result=iReceived;
- }
- else
- {
- // Got bad answer
- result=0;
- }
-
- // Reply to the packet by rejecting it
- if(pkt_hdr->message_type == MESSAGE_TYPE_COMMAND)
- {
- int accepted = 0;
- if(a2dp && pkt_hdr->signal_id == AVDTP_SUSPEND)
- {
- DBG("Received signal AVDTP_SUSPEND(%d) from set", pkt_hdr->signal_id);
- a2dp->pause_writing = 1;
- accepted=1;
- }
- else if(a2dp && pkt_hdr->signal_id == AVDTP_START)
- {
- DBG("Received signal AVDTP_START(%d) from set", pkt_hdr->signal_id);
- a2dp->pause_writing = 0;
- accepted=1;
- }
- else
- {
- DBG("Unexpected headset directive %d", pkt_hdr->signal_id);
- }
-
- DBG("Answering command packet (msgtype=%s,signal=%d)", accepted?"MESSAGE_TYPE_ACCEPT":"MESSAGE_TYPE_REJECT", pkt_hdr->signal_id);
- // Reject a command received
- pkt_hdr->message_type = accepted?MESSAGE_TYPE_ACCEPT:MESSAGE_TYPE_REJECT;
+ int result = 0;
+ int wrresult = 0;
- wrresult = write(sockfd, pkt_hdr, sizeof(*pkt_hdr));
+ char lpFrame[A2DPMAXIMUMTRANSFERUNITSIZE];
+ int iReceived = recv(sockfd, lpFrame, sizeof(lpFrame), 0);
+ struct avdtp_header *pkt_hdr = (struct avdtp_header *) lpFrame;
+ if (iReceived > 0) {
+ // Manage the packet
+ if (sent_packet == NULL) {
+ int i;
+ printf("socket %d: Received %d bytes\n", sockfd, iReceived);
+ for (i = 0; i < iReceived; i++) {
+ char c = lpFrame[i];
+ if (i % 16 == 0)
+ printf("%05d: ", i);
+ printf("%02x ", c);
+ if (i % 16 == 15)
+ printf("\n");
+ }
+ printf("\n");
+ result = 0;
+ } else if ((pkt_hdr->message_type == MESSAGE_TYPE_ACCEPT) && (pkt_hdr->signal_id == sent_packet->signal_id)
+ ) {
+ // Got expected answer
+ memcpy(answer, lpFrame, answer_size > iReceived ? answer_size : iReceived);
+ result = iReceived;
+ } else {
+ // Got bad answer
+ result = 0;
+ }
+
+ // Reply to the packet by rejecting it
+ if (pkt_hdr->message_type == MESSAGE_TYPE_COMMAND) {
+ int accepted = 0;
+ if (a2dp && pkt_hdr->signal_id == AVDTP_SUSPEND) {
+ DBG("Received signal AVDTP_SUSPEND(%d) from set", pkt_hdr->signal_id);
+ a2dp->pause_writing = 1;
+ accepted = 1;
+ } else if (a2dp && pkt_hdr->signal_id == AVDTP_START) {
+ DBG("Received signal AVDTP_START(%d) from set", pkt_hdr->signal_id);
+ a2dp->pause_writing = 0;
+ accepted = 1;
+ } else {
+ DBG("Unexpected headset directive %d", pkt_hdr->signal_id);
+ }
- if(wrresult != sizeof(*pkt_hdr))
- {
- DBG("FAILED Answering command packet (msgtype=%s,signal=%d) wrresult=%d/%d (errno=%d:%s)", accepted?"MESSAGE_TYPE_ACCEPT":"MESSAGE_TYPE_REJECT", pkt_hdr->signal_id, wrresult, sizeof(*pkt_hdr), errno, strerror(errno));
- }
- }
- else
- {
- DBG("Read non command packet (msgtype=%d,signal=%d)", pkt_hdr->message_type, pkt_hdr->signal_id);
- }
- }
- else
- {
- result=iReceived;
- if(errno!=EAGAIN)
- printf("socket %d: Receive failed %d (errno=%d:%s)\n", sockfd, iReceived, errno, strerror(errno));
- }
+ DBG("Answering command packet (msgtype=%s,signal=%d)", accepted ? "MESSAGE_TYPE_ACCEPT" : "MESSAGE_TYPE_REJECT", pkt_hdr->signal_id);
+ // Reject a command received
+ pkt_hdr->message_type = accepted ? MESSAGE_TYPE_ACCEPT : MESSAGE_TYPE_REJECT;
+
+ wrresult = write(sockfd, pkt_hdr, sizeof(*pkt_hdr));
+
+ if (wrresult != sizeof(*pkt_hdr)) {
+ DBG("FAILED Answering command packet (msgtype=%s,signal=%d) wrresult=%d/%d (errno=%d:%s)", accepted ? "MESSAGE_TYPE_ACCEPT" : "MESSAGE_TYPE_REJECT", pkt_hdr->signal_id,
+ wrresult, sizeof(*pkt_hdr), errno, strerror(errno));
+ }
+ } else {
+ DBG("Read non command packet (msgtype=%d,signal=%d)", pkt_hdr->message_type, pkt_hdr->signal_id);
+ }
+ } else {
+ result = iReceived;
+ if (errno != EAGAIN)
+ printf("socket %d: Receive failed %d (errno=%d:%s)\n", sockfd, iReceived, errno, strerror(errno));
+ }
- return result;
+ return result;
}
-
Index: alsa-plugins/alsalib.c
===================================================================
RCS file: alsa-plugins/alsalib.c
diff -N alsa-plugins/alsalib.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ alsa-plugins/alsalib.c 31 Aug 2006 15:58:57 -0000
@@ -0,0 +1,203 @@
+/*
+*
+* 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>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <malloc.h>
+#include <signal.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/select.h>
+
+#include <netinet/in.h>
+
+#include <pthread.h>
+#include <alsa/asoundlib.h>
+#include "alsalib.h"
+#include "a2dpd_protocol.h"
+
+#define NBSDPRETRIESMAX 0
+#define NONSPECAUDIO 1
+#define BUFS 2048
+
+#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...)
+
+static struct sigaction actions;
+
+typedef struct snd_pcm_alsa {
+ snd_pcm_t *playback_handle;
+} snd_pcm_alsa_t;
+
+/*
+* Underrun and suspend recovery
+*/
+
+static int xrun_recovery(snd_pcm_t * handle, int err)
+{
+ if (err == -EPIPE) { /* under-run */
+ err = snd_pcm_prepare(handle);
+ if (err < 0)
+ printf("Can't recovery from underrun, prepare failed: %s\n", snd_strerror(err));
+ return 0;
+ } else if (err == -ESTRPIPE) {
+ while ((err = snd_pcm_resume(handle)) == -EAGAIN)
+ sleep(1); /* wait until the suspend flag is released */
+ if (err < 0) {
+ err = snd_pcm_prepare(handle);
+ if (err < 0)
+ printf("Can't recovery from suspend, prepare failed: %s\n", snd_strerror(err));
+ }
+ return 0;
+ }
+ return err;
+}
+
+int alsa_transfer_raw(LPALSA alsa, const char *pcm_buffer, int pcm_buffer_size)
+{
+ int result = 0;
+
+ result = snd_pcm_writei(alsa->playback_handle, pcm_buffer, pcm_buffer_size / A2DPD_FRAME_BYTES);
+ switch (result) {
+ case -EBADFD:
+ DBG("EBADFD(%d)", result);
+ break;
+ case -EPIPE:
+ // To manage underrun, we will try to ignore
+ xrun_recovery(alsa->playback_handle, result);
+ //result = 0;
+ DBG("EPIPE(%d)", result);
+ break;
+ case -ESTRPIPE:
+ xrun_recovery(alsa->playback_handle, result);
+ //result=0;
+ DBG("ESTRPIPE(%d)", result);
+ break;
+ }
+
+ return result;
+}
+
+snd_pcm_alsa_t *alsa_alloc(void)
+{
+ snd_pcm_alsa_t *alsa;
+ alsa = malloc(sizeof(*alsa));
+ if (!alsa)
+ return NULL;
+
+ memset(alsa, 0, sizeof(*alsa));
+ return alsa;
+}
+
+void alsa_free(snd_pcm_alsa_t * alsa)
+{
+ free(alsa);
+}
+
+static void sighand(int signo)
+{
+ return;
+}
+
+void alsa_init(void)
+{
+ // 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);
+}
+
+void alsa_exit(void)
+{
+}
+
+LPALSA alsa_new(char *device, int framerate)
+{
+ DBG("");
+ snd_pcm_alsa_t *alsa = NULL;
+ snd_pcm_hw_params_t *hw_params = NULL;
+ int bcontinue = 1;
+ char *devname = (device && device[0]) ? device : "plughw:0,0";
+
+ alsa = alsa_alloc();
+ if (!alsa) {
+ DBG("Can't allocate");
+ return NULL;
+ }
+ // Setup alsa
+ bcontinue = bcontinue && (snd_pcm_open(&alsa->playback_handle, devname, SND_PCM_STREAM_PLAYBACK, 0) >= 0);
+ DBG("snd_pcm_open()==%d", bcontinue);
+ bcontinue = bcontinue && (snd_pcm_hw_params_malloc(&hw_params) >= 0);
+ DBG("snd_pcm_hw_params_malloc()==%d", bcontinue);
+ bcontinue = bcontinue && (snd_pcm_hw_params_any(alsa->playback_handle, hw_params) >= 0);
+ DBG("snd_pcm_hw_params_any()==%d", bcontinue);
+ bcontinue = bcontinue && (snd_pcm_hw_params_set_access(alsa->playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED) >= 0);
+ DBG("snd_pcm_hw_params_set_access()==%d", bcontinue);
+ bcontinue = bcontinue && (snd_pcm_hw_params_set_format(alsa->playback_handle, hw_params, SND_PCM_FORMAT_S16_LE) >= 0);
+ DBG("snd_pcm_hw_params_set_format()==%d", bcontinue);
+ bcontinue = bcontinue && (snd_pcm_hw_params_set_rate(alsa->playback_handle, hw_params, framerate, 0) >= 0);
+ DBG("snd_pcm_hw_params_set_rate()==%d", bcontinue);
+ bcontinue = bcontinue && (snd_pcm_hw_params_set_channels(alsa->playback_handle, hw_params, 2) >= 0);
+ DBG("snd_pcm_hw_params_set_channels()==%d", bcontinue);
+ bcontinue = bcontinue && (snd_pcm_hw_params(alsa->playback_handle, hw_params) >= 0);
+ DBG("snd_pcm_hw_params()==%d", bcontinue);
+ bcontinue = bcontinue && (snd_pcm_prepare(alsa->playback_handle) >= 0);
+ DBG("snd_pcm_prepare()==%d", bcontinue);
+
+ // Free if allocated
+ if (hw_params)
+ snd_pcm_hw_params_free(hw_params);
+
+ if (alsa->playback_handle != NULL) {
+ }
+
+ if (!bcontinue) {
+ alsa_destroy(alsa);
+ alsa = NULL;
+ }
+
+ return alsa;
+}
+
+void alsa_destroy(LPALSA alsa)
+{
+ DBG("");
+ if (alsa->playback_handle != NULL) {
+ snd_pcm_close(alsa->playback_handle);
+ }
+ alsa_free(alsa);
+ DBG("OK");
+}
Index: alsa-plugins/alsalib.h
===================================================================
RCS file: alsa-plugins/alsalib.h
diff -N alsa-plugins/alsalib.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ alsa-plugins/alsalib.h 31 Aug 2006 15:58:57 -0000
@@ -0,0 +1,48 @@
+/*
+ *
+ * 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
+ *
+ */
+
+#ifndef __ALSA_LIB_H__
+#define __ALSA_LIB_H__
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+
+#define A2DPMAXIMUMTRANSFERUNITSIZE 610
+
+typedef struct snd_pcm_alsa* LPALSA;
+
+// Global library initialisation
+extern void alsa_init( void);
+extern void alsa_exit( void);
+
+// Connect to alsa
+extern LPALSA alsa_new( char* device, int framerate);
+extern void alsa_destroy( LPALSA a2dp);
+
+// transfers data
+extern int alsa_transfer_raw( LPALSA a2dp, const char* pcm_buffer, int pcm_buffer_size);
+
+#endif
Index: alsa-plugins/pcm_a2dpd.c
===================================================================
RCS file: /cvsroot/bluetooth-alsa/btsco/alsa-plugins/pcm_a2dpd.c,v
retrieving revision 1.4
diff -u -r1.4 pcm_a2dpd.c
--- alsa-plugins/pcm_a2dpd.c 17 Aug 2006 14:06:27 -0000 1.4
+++ alsa-plugins/pcm_a2dpd.c 31 Aug 2006 15:58:57 -0000
@@ -51,381 +51,358 @@
#define DBG(fmt, arg...) printf("DEBUG: %s: (errno=%d:%s)" fmt "\n" , __FUNCTION__ , errno, strerror(errno), ## arg)
//#define DBG(D...)
-static char g_srcfilename [512];
+static char g_srcfilename[512];
// 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;
+ printf("A2DPD CTL in signal handler %d\n", signo);
+ return;
}
-typedef struct snd_pcm_a2dp
-{
- snd_pcm_ioplug_t io;
- int sk;
- int rate;
- int channels;
- snd_pcm_sframes_t num;
- unsigned int frame_bytes;
- TIMERINFO TimerInfos;
+typedef struct snd_pcm_a2dp {
+ snd_pcm_ioplug_t io;
+ int sk;
+ int rate;
+ int channels;
+ snd_pcm_sframes_t num;
+ unsigned int frame_bytes;
+ TIMERINFO TimerInfos;
} snd_pcm_a2dp_t;
-static int a2dp_disconnect(snd_pcm_a2dp_t *a2dp)
+static int a2dp_disconnect(snd_pcm_a2dp_t * a2dp)
{
- close_socket(a2dp->sk);
- a2dp->sk = -1;
- return 0;
-}
-
-static int a2dp_connect(snd_pcm_a2dp_t *a2dp)
-{
- 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;
+ close_socket(a2dp->sk);
+ a2dp->sk = -1;
+ return 0;
+}
+
+static int a2dp_connect(snd_pcm_a2dp_t * a2dp)
+{
+ 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 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;
+ snd_pcm_a2dp_t *a2dp;
+ DBG("Init");
+ a2dp = malloc(sizeof(*a2dp));
+ if (!a2dp)
+ return NULL;
+ memset(a2dp, 0, sizeof(*a2dp));
+ a2dp->sk = -1;
- {
- get_config_filename(g_srcfilename, sizeof(g_srcfilename));
- int rate = read_config_int(g_srcfilename, "a2dpd", "rate", A2DPD_FRAME_RATE);
- a2dp->TimerInfos.fps = (float)((((float)rate)*((float)A2DPD_FRAME_BYTES)/((float)A2DPD_BLOCK_SIZE))/1.0);
- }
- DBG("OK");
- return a2dp;
+ {
+ get_config_filename(g_srcfilename, sizeof(g_srcfilename));
+ int rate = read_config_int(g_srcfilename, "a2dpd", "rate", A2DPD_FRAME_RATE);
+ a2dp->TimerInfos.fps = (float) ((((float) rate) * ((float) A2DPD_FRAME_BYTES) / ((float) A2DPD_BLOCK_SIZE)) / 1.0);
+ }
+ DBG("OK");
+ return a2dp;
}
-static inline void a2dp_free(snd_pcm_a2dp_t *a2dp)
+static inline void a2dp_free(snd_pcm_a2dp_t * a2dp)
{
- DBG("Finishing");
- a2dp_disconnect(a2dp);
- free(a2dp);
- DBG("OK");
+ DBG("Finishing");
+ a2dp_disconnect(a2dp);
+ free(a2dp);
+ DBG("OK");
}
-static int a2dp_start(snd_pcm_ioplug_t *io)
+static int a2dp_start(snd_pcm_ioplug_t * io)
{
- //snd_pcm_a2dp_t *a2dp = io->private_data;
- //FIXME
- return 0;
+ //snd_pcm_a2dp_t *a2dp = io->private_data;
+ //FIXME
+ return 0;
}
-static int a2dp_stop(snd_pcm_ioplug_t *io)
+static int a2dp_stop(snd_pcm_ioplug_t * io)
{
- //snd_pcm_a2dp_t *a2dp = io->private_data;
- return 0;
+ //snd_pcm_a2dp_t *a2dp = io->private_data;
+ return 0;
}
-static snd_pcm_sframes_t a2dp_pointer(snd_pcm_ioplug_t *io)
+static snd_pcm_sframes_t a2dp_pointer(snd_pcm_ioplug_t * io)
{
- snd_pcm_a2dp_t *a2dp = io->private_data;
- return a2dp->num;
+ snd_pcm_a2dp_t *a2dp = io->private_data;
+ return a2dp->num;
}
// 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)
-{
- snd_pcm_a2dp_t* a2dp = io->private_data;
- int transfer = 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);
-
- // Disconnect if error detected
- if(transfer<0) a2dp_disconnect(a2dp);
-
- // 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);
-
- // Stats
- if(a2dp->TimerInfos.display>0)
- {
- if(errno != 0 || transfer <= 0)
- {
- syslog( LOG_INFO, "send_socket(%d bytes)=%d (errno=%d:%s)", datatoread, transfer, errno, strerror(errno));
- }
- }
+static snd_pcm_sframes_t a2dp_transfer2(snd_pcm_ioplug_t * io, char *buf, int32_t datatoread)
+{
+ snd_pcm_a2dp_t *a2dp = io->private_data;
+ int transfer = 0;
- // update pointer, tell alsa we're done
- a2dp->num += datatoread / a2dp->frame_bytes;
+ // 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);
+
+ // Disconnect if error detected
+ if (transfer < 0)
+ a2dp_disconnect(a2dp);
+
+ // 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);
+
+ // Stats
+ if (a2dp->TimerInfos.display > 0) {
+ if (errno != 0 || transfer <= 0) {
+ syslog(LOG_INFO, "send_socket(%d bytes)=%d (errno=%d:%s)", datatoread, transfer, errno, strerror(errno));
+ }
+ }
+ // update pointer, tell alsa we're done
+ a2dp->num += datatoread / a2dp->frame_bytes;
- return 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_transfer_all(snd_pcm_ioplug_t *io,
- const snd_pcm_channel_area_t *areas,
- snd_pcm_uframes_t offset, snd_pcm_uframes_t size)
+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 i = 0;
- snd_pcm_sframes_t totaltransfered = 0;
- while(i++<1 && totaltransfered < size)
- {
- 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)
- {
- offset += transfered;
- totaltransfered += transfered;
- }
- else
- {
- break;
- }
- }
- return totaltransfered;
+ snd_pcm_a2dp_t *a2dp = io->private_data;
+ int i = 0;
+ snd_pcm_sframes_t totaltransfered = 0;
+ while (i++ < 1 && totaltransfered < size) {
+ 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) {
+ offset += transfered;
+ totaltransfered += transfered;
+ } else {
+ break;
+ }
+ }
+ return totaltransfered;
}
-static int a2dp_close(snd_pcm_ioplug_t *io)
+static int a2dp_close(snd_pcm_ioplug_t * io)
{
- snd_pcm_a2dp_t *a2dp = io->private_data;
- a2dp_disconnect(a2dp);
- a2dp_free(a2dp);
- return 0;
+ snd_pcm_a2dp_t *a2dp = io->private_data;
+ a2dp_disconnect(a2dp);
+ a2dp_free(a2dp);
+ return 0;
}
-static int a2dp_params(snd_pcm_ioplug_t *io, snd_pcm_hw_params_t *params)
+static 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;
+ snd_pcm_a2dp_t *a2dp = io->private_data;
+ unsigned int period_bytes;
- DBG("a2dp %p", a2dp);
+ DBG("a2dp %p", a2dp);
- a2dp->frame_bytes = (snd_pcm_format_physical_width(io->format) * io->channels) / 8;
+ a2dp->frame_bytes = (snd_pcm_format_physical_width(io->format) * io->channels) / 8;
- period_bytes = io->period_size * a2dp->frame_bytes;
+ 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("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);
+ 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 0;
}
-static int a2dp_prepare(snd_pcm_ioplug_t *io)
+static int a2dp_prepare(snd_pcm_ioplug_t * io)
{
- snd_pcm_a2dp_t *a2dp = io->private_data;
- DBG("a2dp %p", a2dp);
- a2dp->num = 0;
- a2dp->rate = io->rate;
- a2dp->channels = io->channels;
- return 0;
+ snd_pcm_a2dp_t *a2dp = io->private_data;
+ DBG("a2dp %p", a2dp);
+ a2dp->num = 0;
+ a2dp->rate = io->rate;
+ a2dp->channels = io->channels;
+ return 0;
}
-static int a2dp_drain(snd_pcm_ioplug_t *io)
+static int a2dp_drain(snd_pcm_ioplug_t * io)
{
- snd_pcm_a2dp_t *a2dp = io->private_data;
- DBG("a2dp %p", a2dp);
- return 0;
+ snd_pcm_a2dp_t *a2dp = io->private_data;
+ DBG("a2dp %p", a2dp);
+ return 0;
}
-static int a2dp_descriptors_count(snd_pcm_ioplug_t *io)
+static int a2dp_descriptors_count(snd_pcm_ioplug_t * io)
{
- return 1;
+ return 1;
}
-static int a2dp_descriptors(snd_pcm_ioplug_t *io, struct pollfd *pfds, unsigned int space)
+static int a2dp_descriptors(snd_pcm_ioplug_t * io, struct pollfd *pfds, unsigned int space)
{
- if (space < 1)
- {
- DBG("Can't fill in descriptors");
- SNDERR("Can't fill in descriptors");
- return 0;
- }
-
- // Alsa does make sure writing now will not block
- // So give him an always writable socket!
- pfds[0].fd = fileno(stdout);
- pfds[0].events = POLLOUT;
- return 1;
+ if (space < 1) {
+ DBG("Can't fill in descriptors");
+ SNDERR("Can't fill in descriptors");
+ return 0;
+ }
+ // Alsa does make sure writing now will not block
+ // So give him an always writable socket!
+ pfds[0].fd = fileno(stdout);
+ pfds[0].events = POLLOUT;
+ return 1;
}
-static int a2dp_poll(snd_pcm_ioplug_t *io, struct pollfd *pfds,
- unsigned int nfds, unsigned short *revents)
+static 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;
+ snd_pcm_a2dp_t *a2dp = io->private_data;
+ *revents = pfds[0].revents;
- if (a2dp->sk<=0)
- return 0;
+ if (a2dp->sk <= 0)
+ return 0;
- if (pfds[0].revents & POLLHUP) {
- a2dp_disconnect(a2dp);
- snd_pcm_ioplug_reinit_status(&a2dp->io);
- }
+ if (pfds[0].revents & POLLHUP) {
+ a2dp_disconnect(a2dp);
+ snd_pcm_ioplug_reinit_status(&a2dp->io);
+ }
- return 0;
+ return 0;
}
static snd_pcm_ioplug_callback_t a2dp_callback = {
- .close = a2dp_close,
- .start = a2dp_start,
- .stop = a2dp_stop,
- .prepare = a2dp_prepare,
- .transfer = a2dp_transfer_all,
- .pointer = a2dp_pointer,
- .hw_params = a2dp_params,
- .drain = a2dp_drain,
- .poll_descriptors_count = a2dp_descriptors_count,
- .poll_descriptors = a2dp_descriptors,
- .poll_revents = a2dp_poll,
+ .close = a2dp_close,
+ .start = a2dp_start,
+ .stop = a2dp_stop,
+ .prepare = a2dp_prepare,
+ .transfer = a2dp_transfer_all,
+ .pointer = a2dp_pointer,
+ .hw_params = a2dp_params,
+ .drain = a2dp_drain,
+ .poll_descriptors_count = a2dp_descriptors_count,
+ .poll_descriptors = a2dp_descriptors,
+ .poll_revents = a2dp_poll,
};
// 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)
+static int a2dp_constraint(snd_pcm_a2dp_t * a2dp)
{
- snd_pcm_ioplug_t *io = &a2dp->io;
- snd_pcm_access_t access_list[] = {
- SND_PCM_ACCESS_RW_INTERLEAVED,
- SND_PCM_ACCESS_MMAP_INTERLEAVED,
- };
- unsigned int format[2], channel[2], rate[2];
- int err;
+ snd_pcm_ioplug_t *io = &a2dp->io;
+ snd_pcm_access_t access_list[] = {
+ SND_PCM_ACCESS_RW_INTERLEAVED,
+ SND_PCM_ACCESS_MMAP_INTERLEAVED,
+ };
+ unsigned int format[2], channel[2], rate[2];
+ int err;
- syslog(LOG_INFO, "[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)
- return err;
+ err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_ACCESS, 2, access_list);
+ if (err < 0)
+ return err;
- format[0] = SND_PCM_FORMAT_S16_LE;
+ format[0] = SND_PCM_FORMAT_S16_LE;
- err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_FORMAT, 1, format);
- if (err < 0)
- return err;
+ err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_FORMAT, 1, format);
+ if (err < 0)
+ return err;
- channel[0] = 1;
- channel[1] = 2;
+ channel[0] = 1;
+ channel[1] = 2;
- err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_CHANNELS, 2, channel);
- if (err < 0)
- return err;
+ err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_CHANNELS, 2, channel);
+ if (err < 0)
+ return err;
- get_config_filename(g_srcfilename, sizeof(g_srcfilename));
- rate[0] = read_config_int(g_srcfilename, "a2dpd", "rate", A2DPD_FRAME_RATE);
- //rate[1] = 48000;
+ get_config_filename(g_srcfilename, sizeof(g_srcfilename));
+ rate[0] = read_config_int(g_srcfilename, "a2dpd", "rate", A2DPD_FRAME_RATE);
+ //rate[1] = 48000;
- err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_RATE, 1, rate);
- if (err < 0)
- return err;
+ err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_RATE, 1, rate);
+ if (err < 0)
+ return err;
- err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIOD_BYTES, 8192, 8192);
- if (err < 0)
- return err;
+ err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIOD_BYTES, 8192, 8192);
+ if (err < 0)
+ return err;
- err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIODS, 2, 2);
- if (err < 0)
- return err;
+ err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIODS, 2, 2);
+ if (err < 0)
+ return err;
- return 0;
+ return 0;
}
SND_PCM_PLUGIN_DEFINE_FUNC(a2dpd)
{
- snd_pcm_a2dp_t *a2dp = NULL;
- snd_config_iterator_t i, next;
- int err = 0;
-
- DBG("name %s mode %d", name, mode);
-
- // 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;
-
- if (snd_config_get_id(n, &id) < 0)
- continue;
-
- if (!strcmp(id, "comment") || !strcmp(id, "type"))
- continue;
-
- // Ignore old options
- if (strstr("ipaddr bdaddr port src dst use_rfcomm", id))
- continue;
-
- SNDERR("Unknown field %s", id);
- return -EINVAL;
- }
-
- a2dp = a2dp_alloc();
- if (!a2dp)
- {
- SNDERR("Can't allocate plugin data");
- return -ENOMEM;
- }
-
- // Connect
- a2dp_connect(a2dp);
-
- // Notify plugin
- a2dp->io.version = SND_PCM_IOPLUG_VERSION;
- a2dp->io.name = "Bluetooth Advanced Audio Distribution";
- a2dp->io.mmap_rw = 0;
- a2dp->io.callback = &a2dp_callback;
- a2dp->io.private_data = a2dp;
-
- err = snd_pcm_ioplug_create(&a2dp->io, name, stream, mode);
- if (err < 0)
- goto error;
-
- err = a2dp_constraint(a2dp);
- if (err < 0) {
- snd_pcm_ioplug_delete(&a2dp->io);
- goto error;
- }
-
- *pcmp = a2dp->io.pcm;
- return 0;
-
-error:
- a2dp_disconnect(a2dp);
- a2dp_free(a2dp);
+ snd_pcm_a2dp_t *a2dp = NULL;
+ snd_config_iterator_t i, next;
+ int err = 0;
+
+ DBG("name %s mode %d", name, mode);
+
+ // 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;
+
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
+
+ if (!strcmp(id, "comment") || !strcmp(id, "type"))
+ continue;
+
+ // Ignore old options
+ if (strstr("ipaddr bdaddr port src dst use_rfcomm", id))
+ continue;
+
+ SNDERR("Unknown field %s", id);
+ return -EINVAL;
+ }
+
+ a2dp = a2dp_alloc();
+ if (!a2dp) {
+ SNDERR("Can't allocate plugin data");
+ return -ENOMEM;
+ }
+ // Connect
+ a2dp_connect(a2dp);
+
+ // Notify plugin
+ a2dp->io.version = SND_PCM_IOPLUG_VERSION;
+ a2dp->io.name = "Bluetooth Advanced Audio Distribution";
+ a2dp->io.mmap_rw = 0;
+ a2dp->io.callback = &a2dp_callback;
+ a2dp->io.private_data = a2dp;
+
+ err = snd_pcm_ioplug_create(&a2dp->io, name, stream, mode);
+ if (err < 0)
+ goto error;
+
+ err = a2dp_constraint(a2dp);
+ if (err < 0) {
+ snd_pcm_ioplug_delete(&a2dp->io);
+ goto error;
+ }
+
+ *pcmp = a2dp->io.pcm;
+ return 0;
+
+ error:
+ a2dp_disconnect(a2dp);
+ a2dp_free(a2dp);
- return err;
+ return err;
}
SND_PCM_PLUGIN_SYMBOL(a2dpd);
Index: alsa-plugins/sample.a2dprc
===================================================================
RCS file: /cvsroot/bluetooth-alsa/btsco/alsa-plugins/sample.a2dprc,v
retrieving revision 1.2
diff -u -r1.2 sample.a2dprc
--- alsa-plugins/sample.a2dprc 17 Aug 2006 14:06:27 -0000 1.2
+++ alsa-plugins/sample.a2dprc 31 Aug 2006 15:58:57 -0000
@@ -1,10 +1,38 @@
[a2dpd]
+#
+# Rate
+# use 32000 if your headset seems to not support 44100 (HP works well at 44100, Sonorix at 32000)
+# Alsa output may not work depending on your graphics card
+# Very few players supports it (xmms does, but not amarok/gxine engine)
+#
rate=44100
#rate=32000
-address=00:0D:44:2A:17:C7
+enablereversestereo=0
+
+#
+# AVRCP Commands to run
+#
cmdplay=xmms --play
cmdpause=xmms --pause
cmdprev=xmms --rew
cmdnext=xmms --fwd
cmdnew=xmms --play
+# Put to 0 to ignore AVRCP (if your computer freezes when commands are received)
+enableavrcp=1
+
+#
+# Audio routing
+#
+# If set to 1 (at a2dp startup only) a2dp will reread configuration file
+#Â for audio routing changes each second
+enablerereadconfig=1
+
+# 0 => Bluetooth A2DP Sink
+# 1 => Alsa
+enableredirectalsa=0
+
+# Your bluetooth headset address
+address=00:08:F4:30:07:64
+# Address of your alsa output (default : plughw:0,0) you have to know what to do
+alsaoutput=
[-- Attachment #3: Type: text/plain, Size: 373 bytes --]
-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
[-- 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] 27+ messages in thread