* [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; 19+ 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] 19+ messages in thread
* Re: [Bluez-devel] Big patch to a2dpd
2006-08-31 16:04 ` [Bluez-devel] Big " Frédéric DALLEAU
@ 2006-09-01 12:57 ` andy
2006-09-01 18:25 ` Michael Frey
2006-09-02 16:05 ` Brad Midgley
2006-09-02 16:08 ` Brad Midgley
2 siblings, 1 reply; 19+ messages in thread
From: andy @ 2006-09-01 12:57 UTC (permalink / raw)
To: BlueZ development
Hi Fr=E9d=E9ric,
Whoo some patch cant wait to give it a whirl..
On the subject of your DOC nice work very concise
You might like to add
------------------
If you create an ~.asoundrc as follows
pcm.a2dpd {
type a2dpd
}
Then you can directly add the headphone device (pcm.a2dpd) to any app that
supports alsa plugins correctly, Without affecting the default Gnome/X/KDE
sounds
Known working Apps
Xmms
alsaplayer
VLC (you have to manualy add it to the conf file as the gui wont allow
adding non visible plugins (bug)).
cheers Andy
--------------------------------------
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=3D 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=E9d=E9ric
>
>
-------------------------------------------------------------------------
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 easi=
er
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=3Dlnk&kid=3D120709&bid=3D263057&dat=3D1=
21642
_______________________________________________
Bluez-devel mailing list
Bluez-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bluez-devel
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Bluez-devel] Big patch to a2dpd
2006-09-01 12:57 ` andy
@ 2006-09-01 18:25 ` Michael Frey
0 siblings, 0 replies; 19+ messages in thread
From: Michael Frey @ 2006-09-01 18:25 UTC (permalink / raw)
To: BlueZ development
Is there a way to have a2dpd use the alsa dmixer? And does anyone =
know how to change the default alsa device on the fly. I know you =
can change .asoundrc but any running applications need to be =
restarted in order to pick up the change. Is there a better way?
Michael
On Sep 1, 2006, at 8:57 AM, andy@samuri.demon.co.uk wrote:
> Hi Fr=E9d=E9ric,
>
> Whoo some patch cant wait to give it a whirl..
>
> On the subject of your DOC nice work very concise
>
> You might like to add
> ------------------
> If you create an ~.asoundrc as follows
>
> pcm.a2dpd {
> type a2dpd
> }
>
> Then you can directly add the headphone device (pcm.a2dpd) to any =
> app that
> supports alsa plugins correctly, Without affecting the default =
> Gnome/X/KDE
> sounds
>
> Known working Apps
>
> Xmms
> alsaplayer
> VLC (you have to manualy add it to the conf file as the gui wont allow
> adding non visible plugins (bug)).
>
> cheers Andy
> --------------------------------------
> 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=3D 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=E9d=E9ric
>>
>>
>
>
>
> ---------------------------------------------------------------------- =
> ---
> 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=3Dlnk&kid=3D120709&bid=3D263057&dat=3D121642
> _______________________________________________
> Bluez-devel mailing list
> Bluez-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/bluez-devel
-------------------------------------------------------------------------
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 easi=
er
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=3Dlnk&kid=3D120709&bid=3D263057&dat=3D1=
21642
_______________________________________________
Bluez-devel mailing list
Bluez-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bluez-devel
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Bluez-devel] Big patch to a2dpd
@ 2006-09-02 6:04 Li, Lea
2006-09-02 13:02 ` Michael Frey
0 siblings, 1 reply; 19+ messages in thread
From: Li, Lea @ 2006-09-02 6:04 UTC (permalink / raw)
To: BlueZ development
[-- Attachment #1: Type: text/plain, Size: 3478 bytes --]
Hi Michael,
's "Big patch to a2dpd" is just the right thing you are looking for. To switch to default alsa device, one way is to change ".asoundrc", the other way is to enable "audio routing" (see enablerereadconfig & enableredirectalsa) in ".a2dprc" which can do that on the fly. :)
Thanks,
Lea
-----Original Message-----
From: bluez-devel-bounces@lists.sourceforge.net [mailto:bluez-devel-bounces@lists.sourceforge.net] On Behalf Of Michael Frey
Sent: 2006年9月2日 2:26
To: BlueZ development
Subject: Re: [Bluez-devel] Big patch to a2dpd
Is there a way to have a2dpd use the alsa dmixer? And does anyone
know how to change the default alsa device on the fly. I know you
can change .asoundrc but any running applications need to be
restarted in order to pick up the change. Is there a better way?
Michael
On Sep 1, 2006, at 8:57 AM, andy@samuri.demon.co.uk wrote:
> Hi Frédéric,
>
> Whoo some patch cant wait to give it a whirl..
>
> On the subject of your DOC nice work very concise
>
> You might like to add
> ------------------
> If you create an ~.asoundrc as follows
>
> pcm.a2dpd {
> type a2dpd
> }
>
> Then you can directly add the headphone device (pcm.a2dpd) to any
> app that
> supports alsa plugins correctly, Without affecting the default
> Gnome/X/KDE
> sounds
>
> Known working Apps
>
> Xmms
> alsaplayer
> VLC (you have to manualy add it to the conf file as the gui wont allow
> adding non visible plugins (bug)).
>
> cheers Andy
> --------------------------------------
> 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
>>
>>
>
>
>
> ----------------------------------------------------------------------
> ---
> 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
> _______________________________________________
> Bluez-devel mailing list
> Bluez-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/bluez-devel
-------------------------------------------------------------------------
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
_______________________________________________
Bluez-devel mailing list
Bluez-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bluez-devel
[-- Attachment #2: 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 #3: 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] 19+ messages in thread
* Re: [Bluez-devel] Big patch to a2dpd
@ 2006-09-02 6:21 Li, Lea
2006-09-06 3:06 ` Brad Midgley
0 siblings, 1 reply; 19+ messages in thread
From: Li, Lea @ 2006-09-02 6:21 UTC (permalink / raw)
To: BlueZ development
[-- Attachment #1: Type: text/plain, Size: 2040 bytes --]
It's really a great patch - which is the right patch I am looking for. :)
I've tried it on my XScale board. It is perfect but only one line to be modified to make default alsa device work smoothly. See below patch:
The better way is to modify the code in alsa_transfer_raw(), I think, as below:
case -EPIPE:
// To manage underrun, we will try to recover from error state
if(xrun_recovery(alsa->playback_handle, result) == 0)
result = 0;
DBG("EPIPE(%d)", result);
break;
case -ESTRPIPE:
if(xrun_recovery(alsa->playback_handle, result) == 0)
result=0;
DBG("ESTRPIPE(%d)", result);
break;
}
========patch begin========
--- a2dpd.c.old 2006-09-02 13:53:31.601040096 +0800
+++ a2dpd.c 2006-09-02 13:14:53.065511072 +0800
@@ -716,7 +716,7 @@
blockstart += blocksize;
ibytespersecond += transfer;
a2dp_timer_notifyframe(&TimerInfos);
- } else {
+ } else if (! (lpDevice->bredirectalsa)){
printf("Error in a2dp_transfer_raw\n");
bError = 1;
}
========patch end========
Thanks,
Lea
-----Original Message-----
From: bluez-devel-bounces@lists.sourceforge.net [mailto:bluez-devel-bounces@lists.sourceforge.net] On Behalf Of Frédéric DALLEAU
Sent: 2006年9月1日 0:05
To: BlueZ development
Subject: [Bluez-devel] Big patch to a2dpd
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: 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 #3: 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] 19+ messages in thread
* Re: [Bluez-devel] Big patch to a2dpd
2006-09-02 6:04 Li, Lea
@ 2006-09-02 13:02 ` Michael Frey
0 siblings, 0 replies; 19+ messages in thread
From: Michael Frey @ 2006-09-02 13:02 UTC (permalink / raw)
To: BlueZ development
TGVhLAoKSSBzZWUgdGhvc2Ugb3B0aW9ucywgYnV0IEkgYW0gc3RpbGwgYSBiaXQgY29uZnVzZWQg
aG93IHRoZXkgd29yay4gQ2FuICAKeW91IGdpdmUgbWUgYW4gZXhhbXBsZT8gIExldHMgc2F5IG1w
bGF5ZXIgaXMgcGxheWluZyB0byB0aGUgZGVmYXVsdCAgCkFMU0EgZGV2aWNlIGFuZCBJIHdhbnQg
dG8gdG9nZ2xlIGJldHdlZW4gc3BlYWtlcnMgYW5kIGhlYWRzZXQsIGhvdyAgCndvdWxkIHRoYXQg
YmUgZG9uZSB3aXRoIC5hMmRwcmM/CgpUaGFua3MgZm9yIHlvdXIgaGVscCwKTWljaGFlbAoKT24g
U2VwIDIsIDIwMDYsIGF0IDI6MDQgQU0sIExpLCBMZWEgd3JvdGU6Cgo+IEhpIE1pY2hhZWwsCj4K
PiAncyAiQmlnIHBhdGNoIHRvIGEyZHBkIiBpcyBqdXN0IHRoZSByaWdodCB0aGluZyB5b3UgYXJl
IGxvb2tpbmcgIAo+IGZvci4gVG8gc3dpdGNoIHRvIGRlZmF1bHQgYWxzYSBkZXZpY2UsIG9uZSB3
YXkgaXMgdG8gY2hhbmdlICAKPiAiLmFzb3VuZHJjIiwgdGhlIG90aGVyIHdheSBpcyB0byBlbmFi
bGUgImF1ZGlvIHJvdXRpbmciIChzZWUgIAo+IGVuYWJsZXJlcmVhZGNvbmZpZyAmIGVuYWJsZXJl
ZGlyZWN0YWxzYSkgaW4gIi5hMmRwcmMiIHdoaWNoIGNhbiBkbyAgCj4gdGhhdCBvbiB0aGUgZmx5
LiA6KQo+Cj4KPiBUaGFua3MsCj4gTGVhCj4KPgo+IC0tLS0tT3JpZ2luYWwgTWVzc2FnZS0tLS0t
Cj4gRnJvbTogYmx1ZXotZGV2ZWwtYm91bmNlc0BsaXN0cy5zb3VyY2Vmb3JnZS5uZXQgW21haWx0
bzpibHVlei1kZXZlbC0gCj4gYm91bmNlc0BsaXN0cy5zb3VyY2Vmb3JnZS5uZXRdIE9uIEJlaGFs
ZiBPZiBNaWNoYWVsIEZyZXkKPiBTZW50OiAyMDA25bm0OeaciDLml6UgMjoyNgo+IFRvOiBCbHVl
WiBkZXZlbG9wbWVudAo+IFN1YmplY3Q6IFJlOiBbQmx1ZXotZGV2ZWxdIEJpZyBwYXRjaCB0byBh
MmRwZAo+Cj4gSXMgdGhlcmUgYSB3YXkgdG8gaGF2ZSBhMmRwZCB1c2UgdGhlIGFsc2EgZG1peGVy
PyAgQW5kIGRvZXMgYW55b25lCj4ga25vdyBob3cgdG8gY2hhbmdlIHRoZSBkZWZhdWx0IGFsc2Eg
ZGV2aWNlIG9uIHRoZSBmbHkuICBJIGtub3cgeW91Cj4gY2FuIGNoYW5nZSAuYXNvdW5kcmMgYnV0
IGFueSBydW5uaW5nIGFwcGxpY2F0aW9ucyBuZWVkIHRvIGJlCj4gcmVzdGFydGVkIGluIG9yZGVy
IHRvIHBpY2sgdXAgdGhlIGNoYW5nZS4gIElzIHRoZXJlIGEgYmV0dGVyIHdheT8KPgo+IE1pY2hh
ZWwKPgo+IE9uIFNlcCAxLCAyMDA2LCBhdCA4OjU3IEFNLCBhbmR5QHNhbXVyaS5kZW1vbi5jby51
ayB3cm90ZToKPgo+PiBIaSBGcsOpZMOpcmljLAo+Pgo+PiBXaG9vIHNvbWUgcGF0Y2ggY2FudCB3
YWl0IHRvIGdpdmUgaXQgYSB3aGlybC4uCj4+Cj4+IE9uIHRoZSBzdWJqZWN0IG9mIHlvdXIgRE9D
IG5pY2Ugd29yayB2ZXJ5IGNvbmNpc2UKPj4KPj4gWW91IG1pZ2h0IGxpa2UgdG8gYWRkCj4+IC0t
LS0tLS0tLS0tLS0tLS0tLQo+PiBJZiB5b3UgY3JlYXRlIGFuIH4uYXNvdW5kcmMgYXMgZm9sbG93
cwo+Pgo+PiBwY20uYTJkcGQgewo+PiAgICAgICAgdHlwZSBhMmRwZAo+PiB9Cj4+Cj4+IFRoZW4g
eW91IGNhbiBkaXJlY3RseSBhZGQgdGhlIGhlYWRwaG9uZSBkZXZpY2UgKHBjbS5hMmRwZCkgdG8g
YW55Cj4+IGFwcCB0aGF0Cj4+IHN1cHBvcnRzIGFsc2EgcGx1Z2lucyBjb3JyZWN0bHksIFdpdGhv
dXQgYWZmZWN0aW5nIHRoZSBkZWZhdWx0Cj4+IEdub21lL1gvS0RFCj4+IHNvdW5kcwo+Pgo+PiBL
bm93biB3b3JraW5nIEFwcHMKPj4KPj4gWG1tcwo+PiBhbHNhcGxheWVyCj4+IFZMQyAoeW91IGhh
dmUgdG8gbWFudWFseSBhZGQgaXQgdG8gdGhlIGNvbmYgZmlsZSBhcyB0aGUgZ3VpIHdvbnQgIAo+
PiBhbGxvdwo+PiBhZGRpbmcgbm9uIHZpc2libGUgcGx1Z2lucyAoYnVnKSkuCj4+Cj4+IGNoZWVy
cyBBbmR5Cj4+IC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCj4+ICBIaSBC
cmFkLAo+Pj4+Cj4+Pj4gSSBsb29rZWQgb3ZlciBNYXR0aGV3J3MgcGF0Y2hlcyBhbmQgYXBwbGll
ZCB0aGVtLiBJIGFwcGxpZWQgeW91cgo+Pj4+ICJzbWFsbAo+Pj4+IHBhdGNoIiB3aGljaCB0dXJu
cyBvdXQgdG8gYmUgYmlnZ2VyIHRoYW4gaXQgc291bmRzIDopCj4+Pj4KPj4+IFRoaXMgb25lIGlz
IG1vcmUgdGhhbiBiaWdnZXIhCj4+PiBSZWluZGVudCwKPj4+IEFsc2Egb3V0cHV0IHJlZGlyZWN0
aW9uLAo+Pj4gTmV3IG9uLXRoZS1mbHkgaW4tcGxheSBzd2l0Y2ggZnJvbSBidCB0byBhbHNhIGFu
ZCByZXZlcnNlCj4+PiBDaGFuZ2luZyBiZGFkZHIgaW4gcGxheSB0b28uCj4+PiBNb3JlIG9wdGlv
bnMgZGVzY3JpYmVkIGluIHNhbXBsZS5hMmRwcmMKPj4+Cj4+PiBJIHJlbW92ZWQgdGhlIGxpbmUg
TElCUz0gZnJvbSBNYWtlZmlsZS5hbSBhcyBzdWdnZXN0ZWQuIFRoaXMgbGluZSAgCj4+PiB3YXMK
Pj4+IG1ha2luZyB0b25zIG9mIGNvbXBpbGF0aW9uIHByb2JsZW1zLiBBcyBhMmRwZCBmaW5hbGx5
IGxpbmtzIHRvCj4+PiBhbHNhLCBpdAo+Pj4gaXMgbm8gbG9uZ2VyIG5lZWRlZC4KPj4+IFBsZWFz
ZSBnaXZlIGl0IGEgdHJ5IGJlZm9yZSBzdWJtaXR0aW5nIChNYXR0aGV3IGFuZCBSVUkgaWYgeW91
Cj4+PiByZWFkIHRoYXQpLgo+Pj4KPj4+IFdyb3RlIGEgZG9jIDogaHR0cDovL2ZkYWxsZWF1LmZy
ZWUuZnIvYTJkcF9kb2MucGRmIGlkZWFzIHdlbGNvbWUhCj4+Pgo+Pj4gRnLDqWTDqXJpYwo+Pj4K
Pj4+Cj4+Cj4+Cj4+Cj4+IC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAKPj4gLQo+PiAtLS0KPj4gVXNpbmcgVG9tY2F0
IGJ1dCBuZWVkIHRvIGRvIG1vcmU/IE5lZWQgdG8gc3VwcG9ydCB3ZWIgc2VydmljZXMsCj4+IHNl
Y3VyaXR5Pwo+PiBHZXQgc3R1ZmYgZG9uZSBxdWlja2x5IHdpdGggcHJlLWludGVncmF0ZWQgdGVj
aG5vbG9neSB0byBtYWtlIHlvdXIKPj4gam9iIGVhc2llcgo+PiBEb3dubG9hZCBJQk0gV2ViU3Bo
ZXJlIEFwcGxpY2F0aW9uIFNlcnZlciB2LjEuMC4xIGJhc2VkIG9uIEFwYWNoZQo+PiBHZXJvbmlt
bwo+PiBodHRwOi8vc2VsLmFzLXVzLmZhbGthZy5uZXQvc2VsPwo+PiBjbWQ9bG5rJmtpZD0xMjA3
MDkmYmlkPTI2MzA1NyZkYXQ9MTIxNjQyCj4+IF9fX19fX19fX19fX19fX19fX19fX19fX19fX19f
X19fX19fX19fX19fX19fX19fCj4+IEJsdWV6LWRldmVsIG1haWxpbmcgbGlzdAo+PiBCbHVlei1k
ZXZlbEBsaXN0cy5zb3VyY2Vmb3JnZS5uZXQKPj4gaHR0cHM6Ly9saXN0cy5zb3VyY2Vmb3JnZS5u
ZXQvbGlzdHMvbGlzdGluZm8vYmx1ZXotZGV2ZWwKPgo+Cj4gLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAKPiAtLS0K
PiBVc2luZyBUb21jYXQgYnV0IG5lZWQgdG8gZG8gbW9yZT8gTmVlZCB0byBzdXBwb3J0IHdlYiBz
ZXJ2aWNlcywgIAo+IHNlY3VyaXR5Pwo+IEdldCBzdHVmZiBkb25lIHF1aWNrbHkgd2l0aCBwcmUt
aW50ZWdyYXRlZCB0ZWNobm9sb2d5IHRvIG1ha2UgeW91ciAgCj4gam9iIGVhc2llcgo+IERvd25s
b2FkIElCTSBXZWJTcGhlcmUgQXBwbGljYXRpb24gU2VydmVyIHYuMS4wLjEgYmFzZWQgb24gQXBh
Y2hlICAKPiBHZXJvbmltbwo+IGh0dHA6Ly9zZWwuYXMtdXMuZmFsa2FnLm5ldC9zZWw/IAo+IGNt
ZD1sbmsma2lkPTEyMDcwOSZiaWQ9MjYzMDU3JmRhdD0xMjE2NDIKPiBfX19fX19fX19fX19fX19f
X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXwo+IEJsdWV6LWRldmVsIG1haWxpbmcgbGlz
dAo+IEJsdWV6LWRldmVsQGxpc3RzLnNvdXJjZWZvcmdlLm5ldAo+IGh0dHBzOi8vbGlzdHMuc291
cmNlZm9yZ2UubmV0L2xpc3RzL2xpc3RpbmZvL2JsdWV6LWRldmVsCj4KPiAtLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
IAo+IC0tLQo+IFVzaW5nIFRvbWNhdCBidXQgbmVlZCB0byBkbyBtb3JlPyBOZWVkIHRvIHN1cHBv
cnQgd2ViIHNlcnZpY2VzLCAgCj4gc2VjdXJpdHk/Cj4gR2V0IHN0dWZmIGRvbmUgcXVpY2tseSB3
aXRoIHByZS1pbnRlZ3JhdGVkIHRlY2hub2xvZ3kgdG8gbWFrZSB5b3VyICAKPiBqb2IgZWFzaWVy
Cj4gRG93bmxvYWQgSUJNIFdlYlNwaGVyZSBBcHBsaWNhdGlvbiBTZXJ2ZXIgdi4xLjAuMSBiYXNl
ZCBvbiBBcGFjaGUgIAo+IEdlcm9uaW1vCj4gaHR0cDovL3NlbC5hcy11cy5mYWxrYWcubmV0L3Nl
bD8gCj4gY21kPWxuayZraWQ9MTIwNzA5JmJpZD0yNjMwNTcmZGF0PTEyMTY0Ml9fX19fX19fX19f
X19fX19fX19fX19fX19fX19fXyAKPiBfX19fX19fX19fX19fX19fXwo+IEJsdWV6LWRldmVsIG1h
aWxpbmcgbGlzdAo+IEJsdWV6LWRldmVsQGxpc3RzLnNvdXJjZWZvcmdlLm5ldAo+IGh0dHBzOi8v
bGlzdHMuc291cmNlZm9yZ2UubmV0L2xpc3RzL2xpc3RpbmZvL2JsdWV6LWRldmVsCgoKLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLQpVc2luZyBUb21jYXQgYnV0IG5lZWQgdG8gZG8gbW9yZT8gTmVlZCB0byBzdXBw
b3J0IHdlYiBzZXJ2aWNlcywgc2VjdXJpdHk/CkdldCBzdHVmZiBkb25lIHF1aWNrbHkgd2l0aCBw
cmUtaW50ZWdyYXRlZCB0ZWNobm9sb2d5IHRvIG1ha2UgeW91ciBqb2IgZWFzaWVyCkRvd25sb2Fk
IElCTSBXZWJTcGhlcmUgQXBwbGljYXRpb24gU2VydmVyIHYuMS4wLjEgYmFzZWQgb24gQXBhY2hl
IEdlcm9uaW1vCmh0dHA6Ly9zZWwuYXMtdXMuZmFsa2FnLm5ldC9zZWw/Y21kPWxuayZraWQ9MTIw
NzA5JmJpZD0yNjMwNTcmZGF0PTEyMTY0MgpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19f
X19fX19fX19fX19fX19fXwpCbHVlei1kZXZlbCBtYWlsaW5nIGxpc3QKQmx1ZXotZGV2ZWxAbGlz
dHMuc291cmNlZm9yZ2UubmV0Cmh0dHBzOi8vbGlzdHMuc291cmNlZm9yZ2UubmV0L2xpc3RzL2xp
c3RpbmZvL2JsdWV6LWRldmVsCg==
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Bluez-devel] Big patch to a2dpd
2006-08-31 16:04 ` [Bluez-devel] Big " Frédéric DALLEAU
2006-09-01 12:57 ` andy
@ 2006-09-02 16:05 ` Brad Midgley
2006-09-02 16:08 ` Brad Midgley
2 siblings, 0 replies; 19+ messages in thread
From: Brad Midgley @ 2006-09-02 16:05 UTC (permalink / raw)
To: BlueZ development
Fr=E9d=E9ric
thanks for the continued work.
> 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
a few problems:
It only works if the bdaddr is specified in .asoundrc (the old way) as
well as in .a2dprc. Specifying it on the a2dpd command line does not
seem to help.
Audio only came out the left speaker using my itech r35 black set. (My
other sets are up at work)
How do you switch on the fly to wired audio?
> Wrote a doc : http://fdalleau.free.fr/a2dp_doc.pdf ideas welcome!
Could we contribute this stuff to a wiki? I actually have the feeling
that no one of us understands the whole picture. I have an account on
the ubuntu wiki but a better one for our purposes would have no
association with a specific distro...
Brad
-------------------------------------------------------------------------
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 easi=
er
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=3Dlnk&kid=3D120709&bid=3D263057&dat=3D1=
21642
_______________________________________________
Bluez-devel mailing list
Bluez-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bluez-devel
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Bluez-devel] Big patch to a2dpd
2006-08-31 16:04 ` [Bluez-devel] Big " Frédéric DALLEAU
2006-09-01 12:57 ` andy
2006-09-02 16:05 ` Brad Midgley
@ 2006-09-02 16:08 ` Brad Midgley
2006-09-02 17:01 ` Brad Midgley
2 siblings, 1 reply; 19+ messages in thread
From: Brad Midgley @ 2006-09-02 16:08 UTC (permalink / raw)
To: BlueZ development
argh... another problem...
when I just sent that last message via wifi while streaming with xmms,
the audio turned choppy (works for 1s, silence for 1s, repeat) and it
never started working again even after no wifi activity :(
brad
-------------------------------------------------------------------------
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
_______________________________________________
Bluez-devel mailing list
Bluez-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bluez-devel
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Bluez-devel] Big patch to a2dpd
2006-09-02 16:08 ` Brad Midgley
@ 2006-09-02 17:01 ` Brad Midgley
0 siblings, 0 replies; 19+ messages in thread
From: Brad Midgley @ 2006-09-02 17:01 UTC (permalink / raw)
To: BlueZ development
hey
> argh... another problem...
>
> when I just sent that last message via wifi while streaming with xmms,
> the audio turned choppy (works for 1s, silence for 1s, repeat) and it
> never started working again even after no wifi activity :(
whoops... not sure if this is better or worse.
what actually happened is my wifi stopped working during the a2dp
streaming. so the computer demand-dialed using my cellphone over
bluetooth and that's when the trouble started. so maybe it would have
recovered once the dun connection was closed.
my r35 is a combo hfp/hsp so it does like to be master and doesn't like
scatternetting. funny if you think about it... the network was a
fully-connected triangle between the three devices when the audio was
breaking up.
brad
-------------------------------------------------------------------------
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
_______________________________________________
Bluez-devel mailing list
Bluez-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bluez-devel
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Bluez-devel] Big patch to a2dpd
2006-09-02 6:21 [Bluez-devel] Big patch to a2dpd Li, Lea
@ 2006-09-06 3:06 ` Brad Midgley
0 siblings, 0 replies; 19+ messages in thread
From: Brad Midgley @ 2006-09-06 3:06 UTC (permalink / raw)
To: BlueZ development
Lea
You seem to be proposing two different changes below. Do we need to
discuss which one is best?
thanks
Brad
> I've tried it on my XScale board. It is perfect but only one line to be modified to make default alsa device work smoothly. See below patch:
> The better way is to modify the code in alsa_transfer_raw(), I think, as below:
>
> case -EPIPE:
> // To manage underrun, we will try to recover from error state
> if(xrun_recovery(alsa->playback_handle, result) == 0)
> result = 0;
> DBG("EPIPE(%d)", result);
> break;
> case -ESTRPIPE:
> if(xrun_recovery(alsa->playback_handle, result) == 0)
> result=0;
> DBG("ESTRPIPE(%d)", result);
> break;
> }
>
> ========patch begin========
> --- a2dpd.c.old 2006-09-02 13:53:31.601040096 +0800
> +++ a2dpd.c 2006-09-02 13:14:53.065511072 +0800
> @@ -716,7 +716,7 @@
> blockstart += blocksize;
> ibytespersecond += transfer;
> a2dp_timer_notifyframe(&TimerInfos);
> - } else {
> + } else if (! (lpDevice->bredirectalsa)){
> printf("Error in a2dp_transfer_raw\n");
> bError = 1;
> }
> ========patch end========
>
> Thanks,
> Lea
-------------------------------------------------------------------------
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
_______________________________________________
Bluez-devel mailing list
Bluez-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bluez-devel
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Bluez-devel] Big patch to a2dpd
@ 2006-09-06 3:12 Li, Lea
2006-09-06 3:38 ` Brad Midgley
0 siblings, 1 reply; 19+ messages in thread
From: Li, Lea @ 2006-09-06 3:12 UTC (permalink / raw)
To: BlueZ development
[-- Attachment #1: Type: text/plain, Size: 2156 bytes --]
Yes. I prefer modifying alsa_transfer_raw(), which makes the framework logic consistent. How do you think about it?
Thanks,
Lea
-----Original Message-----
From: bluez-devel-bounces@lists.sourceforge.net [mailto:bluez-devel-bounces@lists.sourceforge.net] On Behalf Of Brad Midgley
Sent: 2006年9月6日 11:06
To: BlueZ development
Subject: Re: [Bluez-devel] Big patch to a2dpd
Lea
You seem to be proposing two different changes below. Do we need to
discuss which one is best?
thanks
Brad
> I've tried it on my XScale board. It is perfect but only one line to be modified to make default alsa device work smoothly. See below patch:
> The better way is to modify the code in alsa_transfer_raw(), I think, as below:
>
> case -EPIPE:
> // To manage underrun, we will try to recover from error state
> if(xrun_recovery(alsa->playback_handle, result) == 0)
> result = 0;
> DBG("EPIPE(%d)", result);
> break;
> case -ESTRPIPE:
> if(xrun_recovery(alsa->playback_handle, result) == 0)
> result=0;
> DBG("ESTRPIPE(%d)", result);
> break;
> }
>
> ========patch begin========
> --- a2dpd.c.old 2006-09-02 13:53:31.601040096 +0800
> +++ a2dpd.c 2006-09-02 13:14:53.065511072 +0800
> @@ -716,7 +716,7 @@
> blockstart += blocksize;
> ibytespersecond += transfer;
> a2dp_timer_notifyframe(&TimerInfos);
> - } else {
> + } else if (! (lpDevice->bredirectalsa)){
> printf("Error in a2dp_transfer_raw\n");
> bError = 1;
> }
> ========patch end========
>
> Thanks,
> Lea
-------------------------------------------------------------------------
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
_______________________________________________
Bluez-devel mailing list
Bluez-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bluez-devel
[-- Attachment #2: 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 #3: 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] 19+ messages in thread
* Re: [Bluez-devel] Big patch to a2dpd
2006-09-06 3:12 Li, Lea
@ 2006-09-06 3:38 ` Brad Midgley
2006-09-06 9:33 ` Frédéric DALLEAU
0 siblings, 1 reply; 19+ messages in thread
From: Brad Midgley @ 2006-09-06 3:38 UTC (permalink / raw)
To: BlueZ development
[-- Attachment #1: Type: text/plain, Size: 349 bytes --]
Lea
> Yes. I prefer modifying alsa_transfer_raw(), which makes the framework logic consistent. How do you think about it?
I'm not familiar with this new stuff, but it seems that the return
values were commented out for some reason and maybe forgotten. If
Frederic has no problems with the change to alsa_transfer_raw, I'll do
it that way.
Brad
[-- Attachment #2: 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 #3: 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] 19+ messages in thread
* Re: [Bluez-devel] Big patch to a2dpd
2006-09-06 3:38 ` Brad Midgley
@ 2006-09-06 9:33 ` Frédéric DALLEAU
2006-09-07 16:48 ` Andrew Waldram
0 siblings, 1 reply; 19+ messages in thread
From: Frédéric DALLEAU @ 2006-09-06 9:33 UTC (permalink / raw)
To: BlueZ development
[-- Attachment #1: Type: text/plain, Size: 1707 bytes --]
Hi,
> Lea
>
>
>> Yes. I prefer modifying alsa_transfer_raw(), which makes the framework logic consistent. How do you think about it?
>>
>
> I'm not familiar with this new stuff, but it seems that the return
> values were commented out for some reason and maybe forgotten. If
> Frederic has no problems with the change to alsa_transfer_raw, I'll do
> it that way.
>
Hi Brad and Lea,
No it's not forgotten : what I wanted is to restart audio on errors. I
had some failures when trying to recover : when pausing a stream in
xmms, an underrun occurs as the alsa device is not closed.
However, I didn't investigate the xrun_recovery return value.
Lea's patch is interesting but it miss something : the xrun_recovery
will ALWAYS return 0 if fed with EPIPE or ESIGPIPE, whether the recovery
succeed or not.
The cleanest is to keep Lea's patch but remove the two "return 0;" calls
in order to "return err;" at the end of the func.
The modification to a2dpd.c should not be done.
See the following :
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; // ------------------------ Remove this line to return err at
the end of the func
} 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;// ------------------------ Remove this line to return err at
the end of the func
}
return err;
}
[-- Attachment #2: 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 #3: 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] 19+ messages in thread
* Re: [Bluez-devel] Big patch to a2dpd
2006-09-06 9:33 ` Frédéric DALLEAU
@ 2006-09-07 16:48 ` Andrew Waldram
2006-09-07 19:47 ` Brad Midgley
0 siblings, 1 reply; 19+ messages in thread
From: Andrew Waldram @ 2006-09-07 16:48 UTC (permalink / raw)
To: BlueZ development
SGkgRnJlZGVyaWMsCgpTaW5jZSBCcmFkIGFwcGxpZWQgdGhlIEJpZyBwYXRjaCB0byBhMmRwZCBp
J20gZ2V0dGluZwoKYTJkcGQuYzo0MDoyMTogZXJyb3I6IGFsc2FsaWIuaDogTm8gc3VjaCBmaWxl
IG9yIGRpcmVjdG9yeQphMmRwZC5jOiBJbiBmdW5jdGlvbiDigJhidF9oYW5kbGVy4oCZOgphMmRw
ZC5jOjY5NTogd2FybmluZzogaW1wbGljaXQgZGVjbGFyYXRpb24gb2YgZnVuY3Rpb24g4oCYYWxz
YV9uZXfigJkKCkkgY2FuJ3QgZmlndXJlIG91dCB3aGVyZSBhbHNhbGliLmggc2hvdWxkIGJlIGNv
bW1pbmcgZnJvbSA/CgoKT24gV2VkLCAyMDA2LTA5LTA2IGF0IDExOjMzICswMjAwLCBGcsOpZMOp
cmljIERBTExFQVUgd3JvdGU6Cj4gSGksCj4gCj4gPiBMZWEKPiA+Cj4gPiAgIAo+ID4+IFllcy4g
SSBwcmVmZXIgbW9kaWZ5aW5nIGFsc2FfdHJhbnNmZXJfcmF3KCksIHdoaWNoIG1ha2VzIHRoZSBm
cmFtZXdvcmsgbG9naWMgY29uc2lzdGVudC4gSG93IGRvIHlvdSB0aGluayBhYm91dCBpdD8gCj4g
Pj4gICAgIAo+ID4KPiA+IEknbSBub3QgZmFtaWxpYXIgd2l0aCB0aGlzIG5ldyBzdHVmZiwgYnV0
IGl0IHNlZW1zIHRoYXQgdGhlIHJldHVybgo+ID4gdmFsdWVzIHdlcmUgY29tbWVudGVkIG91dCBm
b3Igc29tZSByZWFzb24gYW5kIG1heWJlIGZvcmdvdHRlbi4gSWYKPiA+IEZyZWRlcmljIGhhcyBu
byBwcm9ibGVtcyB3aXRoIHRoZSBjaGFuZ2UgdG8gYWxzYV90cmFuc2Zlcl9yYXcsIEknbGwgZG8K
PiA+IGl0IHRoYXQgd2F5Lgo+ID4gICAKPiAKPiBIaSBCcmFkIGFuZCBMZWEsCj4gTm8gaXQncyBu
b3QgZm9yZ290dGVuIDogd2hhdCBJIHdhbnRlZCBpcyB0byByZXN0YXJ0IGF1ZGlvIG9uIGVycm9y
cy4gSQo+IGhhZCBzb21lIGZhaWx1cmVzIHdoZW4gdHJ5aW5nIHRvIHJlY292ZXIgOiB3aGVuIHBh
dXNpbmcgYSBzdHJlYW0gaW4KPiB4bW1zLCBhbiB1bmRlcnJ1biBvY2N1cnMgYXMgdGhlIGFsc2Eg
ZGV2aWNlIGlzIG5vdCBjbG9zZWQuCj4gSG93ZXZlciwgSSBkaWRuJ3QgaW52ZXN0aWdhdGUgdGhl
IHhydW5fcmVjb3ZlcnkgcmV0dXJuIHZhbHVlLgo+IExlYSdzIHBhdGNoIGlzIGludGVyZXN0aW5n
IGJ1dCBpdCBtaXNzIHNvbWV0aGluZyA6IHRoZSB4cnVuX3JlY292ZXJ5Cj4gd2lsbCBBTFdBWVMg
cmV0dXJuIDAgaWYgZmVkIHdpdGggRVBJUEUgb3IgRVNJR1BJUEUsIHdoZXRoZXIgdGhlIHJlY292
ZXJ5Cj4gc3VjY2VlZCBvciBub3QuCj4gVGhlIGNsZWFuZXN0IGlzIHRvIGtlZXAgTGVhJ3MgcGF0
Y2ggYnV0IHJlbW92ZSB0aGUgdHdvICJyZXR1cm4gMDsiIGNhbGxzCj4gaW4gb3JkZXIgdG8gInJl
dHVybiBlcnI7IiBhdCB0aGUgZW5kIG9mIHRoZSBmdW5jLgo+IAo+IFRoZSBtb2RpZmljYXRpb24g
dG8gYTJkcGQuYyBzaG91bGQgbm90IGJlIGRvbmUuCj4gCj4gU2VlIHRoZSBmb2xsb3dpbmcgOgo+
IAo+IHN0YXRpYyBpbnQgeHJ1bl9yZWNvdmVyeShzbmRfcGNtX3QgKiBoYW5kbGUsIGludCBlcnIp
Cj4gewo+IGlmIChlcnIgPT0gLUVQSVBFKSB7IC8qIHVuZGVyLXJ1biAqLwo+IGVyciA9IHNuZF9w
Y21fcHJlcGFyZShoYW5kbGUpOwo+IGlmIChlcnIgPCAwKQo+IHByaW50ZigiQ2FuJ3QgcmVjb3Zl
cnkgZnJvbSB1bmRlcnJ1biwgcHJlcGFyZSBmYWlsZWQ6ICVzXG4iLAo+IHNuZF9zdHJlcnJvcihl
cnIpKTsKPiByZXR1cm4gMDsgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIFJlbW92ZSB0aGlz
IGxpbmUgdG8gcmV0dXJuIGVyciBhdAo+IHRoZSBlbmQgb2YgdGhlIGZ1bmMKPiB9IGVsc2UgaWYg
KGVyciA9PSAtRVNUUlBJUEUpIHsKPiB3aGlsZSAoKGVyciA9IHNuZF9wY21fcmVzdW1lKGhhbmRs
ZSkpID09IC1FQUdBSU4pCj4gc2xlZXAoMSk7IC8qIHdhaXQgdW50aWwgdGhlIHN1c3BlbmQgZmxh
ZyBpcyByZWxlYXNlZCAqLwo+IGlmIChlcnIgPCAwKSB7Cj4gZXJyID0gc25kX3BjbV9wcmVwYXJl
KGhhbmRsZSk7Cj4gaWYgKGVyciA8IDApCj4gcHJpbnRmKCJDYW4ndCByZWNvdmVyeSBmcm9tIHN1
c3BlbmQsIHByZXBhcmUgZmFpbGVkOiAlc1xuIiwKPiBzbmRfc3RyZXJyb3IoZXJyKSk7Cj4gfQo+
IHJldHVybiAwOy8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSBSZW1vdmUgdGhpcyBsaW5lIHRv
IHJldHVybiBlcnIgYXQKPiB0aGUgZW5kIG9mIHRoZSBmdW5jCj4gfQo+IHJldHVybiBlcnI7Cj4g
fQo+IAo+IAo+IAo+IAo+IC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KPiBVc2luZyBUb21jYXQgYnV0IG5lZWQg
dG8gZG8gbW9yZT8gTmVlZCB0byBzdXBwb3J0IHdlYiBzZXJ2aWNlcywgc2VjdXJpdHk/Cj4gR2V0
IHN0dWZmIGRvbmUgcXVpY2tseSB3aXRoIHByZS1pbnRlZ3JhdGVkIHRlY2hub2xvZ3kgdG8gbWFr
ZSB5b3VyIGpvYiBlYXNpZXIKPiBEb3dubG9hZCBJQk0gV2ViU3BoZXJlIEFwcGxpY2F0aW9uIFNl
cnZlciB2LjEuMC4xIGJhc2VkIG9uIEFwYWNoZSBHZXJvbmltbwo+IGh0dHA6Ly9zZWwuYXMtdXMu
ZmFsa2FnLm5ldC9zZWw/Y21kPWxuayZraWQ9MTIwNzA5JmJpZD0yNjMwNTcmZGF0PTEyMTY0Mgo+
IF9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fIEJsdWV6LWRl
dmVsIG1haWxpbmcgbGlzdCBCbHVlei1kZXZlbEBsaXN0cy5zb3VyY2Vmb3JnZS5uZXQgaHR0cHM6
Ly9saXN0cy5zb3VyY2Vmb3JnZS5uZXQvbGlzdHMvbGlzdGluZm8vYmx1ZXotZGV2ZWwKCi0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0KVXNpbmcgVG9tY2F0IGJ1dCBuZWVkIHRvIGRvIG1vcmU/IE5lZWQgdG8gc3Vw
cG9ydCB3ZWIgc2VydmljZXMsIHNlY3VyaXR5PwpHZXQgc3R1ZmYgZG9uZSBxdWlja2x5IHdpdGgg
cHJlLWludGVncmF0ZWQgdGVjaG5vbG9neSB0byBtYWtlIHlvdXIgam9iIGVhc2llcgpEb3dubG9h
ZCBJQk0gV2ViU3BoZXJlIEFwcGxpY2F0aW9uIFNlcnZlciB2LjEuMC4xIGJhc2VkIG9uIEFwYWNo
ZSBHZXJvbmltbwpodHRwOi8vc2VsLmFzLXVzLmZhbGthZy5uZXQvc2VsP2NtZD1sbmsma2lkPTEy
MDcwOSZiaWQ9MjYzMDU3JmRhdD0xMjE2NDIKX19fX19fX19fX19fX19fX19fX19fX19fX19fX19f
X19fX19fX19fX19fX19fX18KQmx1ZXotZGV2ZWwgbWFpbGluZyBsaXN0CkJsdWV6LWRldmVsQGxp
c3RzLnNvdXJjZWZvcmdlLm5ldApodHRwczovL2xpc3RzLnNvdXJjZWZvcmdlLm5ldC9saXN0cy9s
aXN0aW5mby9ibHVlei1kZXZlbAo=
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Bluez-devel] Big patch to a2dpd
2006-09-07 16:48 ` Andrew Waldram
@ 2006-09-07 19:47 ` Brad Midgley
2006-09-07 20:36 ` Michael Frey
2006-09-07 21:06 ` Andrew Waldram
0 siblings, 2 replies; 19+ messages in thread
From: Brad Midgley @ 2006-09-07 19:47 UTC (permalink / raw)
To: BlueZ development
QW5kcmV3Cgo+IFNpbmNlIEJyYWQgYXBwbGllZCB0aGUgQmlnIHBhdGNoIHRvIGEyZHBkIGknbSBn
ZXR0aW5nCj4gCj4gYTJkcGQuYzo0MDoyMTogZXJyb3I6IGFsc2FsaWIuaDogTm8gc3VjaCBmaWxl
IG9yIGRpcmVjdG9yeQo+IGEyZHBkLmM6IEluIGZ1bmN0aW9uIOKAmGJ0X2hhbmRsZXLigJk6Cj4g
YTJkcGQuYzo2OTU6IHdhcm5pbmc6IGltcGxpY2l0IGRlY2xhcmF0aW9uIG9mIGZ1bmN0aW9uIOKA
mGFsc2FfbmV34oCZCgpkb2guIGZvcmdvdCB0byBhZGQgbmV3bHktY3JlYXRlZCBmaWxlcyB0byBj
dnMuIGl0J3MgaW4gY3ZzIG5vdyBzbyBpdApzaG91bGQgcHJvcG9nYXRlIHRvIGFub24gY3ZzIHNo
b3J0bHkKCmJyYWQKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KVXNpbmcgVG9tY2F0IGJ1dCBuZWVkIHRvIGRv
IG1vcmU/IE5lZWQgdG8gc3VwcG9ydCB3ZWIgc2VydmljZXMsIHNlY3VyaXR5PwpHZXQgc3R1ZmYg
ZG9uZSBxdWlja2x5IHdpdGggcHJlLWludGVncmF0ZWQgdGVjaG5vbG9neSB0byBtYWtlIHlvdXIg
am9iIGVhc2llcgpEb3dubG9hZCBJQk0gV2ViU3BoZXJlIEFwcGxpY2F0aW9uIFNlcnZlciB2LjEu
MC4xIGJhc2VkIG9uIEFwYWNoZSBHZXJvbmltbwpodHRwOi8vc2VsLmFzLXVzLmZhbGthZy5uZXQv
c2VsP2NtZD1sbmsma2lkPTEyMDcwOSZiaWQ9MjYzMDU3JmRhdD0xMjE2NDIKX19fX19fX19fX19f
X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18KQmx1ZXotZGV2ZWwgbWFpbGluZyBs
aXN0CkJsdWV6LWRldmVsQGxpc3RzLnNvdXJjZWZvcmdlLm5ldApodHRwczovL2xpc3RzLnNvdXJj
ZWZvcmdlLm5ldC9saXN0cy9saXN0aW5mby9ibHVlei1kZXZlbAo=
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Bluez-devel] Big patch to a2dpd
2006-09-07 19:47 ` Brad Midgley
@ 2006-09-07 20:36 ` Michael Frey
2006-09-07 22:46 ` Brad Midgley
2006-09-07 21:06 ` Andrew Waldram
1 sibling, 1 reply; 19+ messages in thread
From: Michael Frey @ 2006-09-07 20:36 UTC (permalink / raw)
To: BlueZ development
This new version works great. Has anyone been able to watch a movie =
with mplayer? Playing audio is just fine. Playing a movie -- the =
video can not keep up. Any hints?
Michael
On Sep 7, 2006, at 3:47 PM, Brad Midgley wrote:
> Andrew
>
>> Since Brad applied the Big patch to a2dpd i'm getting
>>
>> a2dpd.c:40:21: error: alsalib.h: No such file or directory
>> a2dpd.c: In function =91bt_handler=92:
>> a2dpd.c:695: warning: implicit declaration of function =91alsa_new=92
>
> doh. forgot to add newly-created files to cvs. it's in cvs now so it
> should propogate to anon cvs shortly
>
> brad
>
> ---------------------------------------------------------------------- =
> ---
> 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=3Dlnk&kid=3D120709&bid=3D263057&dat=3D121642
> _______________________________________________
> Bluez-devel mailing list
> Bluez-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/bluez-devel
-------------------------------------------------------------------------
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 easi=
er
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=3Dlnk&kid=3D120709&bid=3D263057&dat=3D1=
21642
_______________________________________________
Bluez-devel mailing list
Bluez-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bluez-devel
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Bluez-devel] Big patch to a2dpd
2006-09-07 19:47 ` Brad Midgley
2006-09-07 20:36 ` Michael Frey
@ 2006-09-07 21:06 ` Andrew Waldram
2006-09-07 22:52 ` Brad Midgley
1 sibling, 1 reply; 19+ messages in thread
From: Andrew Waldram @ 2006-09-07 21:06 UTC (permalink / raw)
To: BlueZ development
QnJhZCwKClRoYXQgZml4ZWQgaXQgdGhhbmtzLAoKSSBub3RpY2UgdGhhdCB0aGUgbWF4aW11bSB2
b2x1bWUgaXMgYSBsb3QgbG93ZXIgZnJvbSBteSBQQyB0aGFuIG15CndvbmRvd3MgUERBIGlzIHRo
ZXJlIGFueXdheSB0byBpbmNyZWFzZSB0aGUgdm9sdW1lIGF0IHRoZSBQQyBzaWRlIGJlZm9yZQp0
cmFuc21pc3Npb24gdG8gdGhlIGhlYWRzZXQuPwoKIApPbiBUaHUsIDIwMDYtMDktMDcgYXQgMTM6
NDcgLTA2MDAsIEJyYWQgTWlkZ2xleSB3cm90ZToKPiBBbmRyZXcKPiAKPiA+IFNpbmNlIEJyYWQg
YXBwbGllZCB0aGUgQmlnIHBhdGNoIHRvIGEyZHBkIGknbSBnZXR0aW5nCj4gPiAKPiA+IGEyZHBk
LmM6NDA6MjE6IGVycm9yOiBhbHNhbGliLmg6IE5vIHN1Y2ggZmlsZSBvciBkaXJlY3RvcnkKPiA+
IGEyZHBkLmM6IEluIGZ1bmN0aW9uIOKAmGJ0X2hhbmRsZXLigJk6Cj4gPiBhMmRwZC5jOjY5NTog
d2FybmluZzogaW1wbGljaXQgZGVjbGFyYXRpb24gb2YgZnVuY3Rpb24g4oCYYWxzYV9uZXfigJkK
PiAKPiBkb2guIGZvcmdvdCB0byBhZGQgbmV3bHktY3JlYXRlZCBmaWxlcyB0byBjdnMuIGl0J3Mg
aW4gY3ZzIG5vdyBzbyBpdAo+IHNob3VsZCBwcm9wb2dhdGUgdG8gYW5vbiBjdnMgc2hvcnRseQo+
IAo+IGJyYWQKPiAKPiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCj4gVXNpbmcgVG9tY2F0IGJ1dCBuZWVkIHRv
IGRvIG1vcmU/IE5lZWQgdG8gc3VwcG9ydCB3ZWIgc2VydmljZXMsIHNlY3VyaXR5Pwo+IEdldCBz
dHVmZiBkb25lIHF1aWNrbHkgd2l0aCBwcmUtaW50ZWdyYXRlZCB0ZWNobm9sb2d5IHRvIG1ha2Ug
eW91ciBqb2IgZWFzaWVyCj4gRG93bmxvYWQgSUJNIFdlYlNwaGVyZSBBcHBsaWNhdGlvbiBTZXJ2
ZXIgdi4xLjAuMSBiYXNlZCBvbiBBcGFjaGUgR2Vyb25pbW8KPiBodHRwOi8vc2VsLmFzLXVzLmZh
bGthZy5uZXQvc2VsP2NtZD1sbmsma2lkPTEyMDcwOSZiaWQ9MjYzMDU3JmRhdD0xMjE2NDIKPiBf
X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXwo+IEJsdWV6LWRl
dmVsIG1haWxpbmcgbGlzdAo+IEJsdWV6LWRldmVsQGxpc3RzLnNvdXJjZWZvcmdlLm5ldAo+IGh0
dHBzOi8vbGlzdHMuc291cmNlZm9yZ2UubmV0L2xpc3RzL2xpc3RpbmZvL2JsdWV6LWRldmVsCgot
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tClVzaW5nIFRvbWNhdCBidXQgbmVlZCB0byBkbyBtb3JlPyBOZWVkIHRv
IHN1cHBvcnQgd2ViIHNlcnZpY2VzLCBzZWN1cml0eT8KR2V0IHN0dWZmIGRvbmUgcXVpY2tseSB3
aXRoIHByZS1pbnRlZ3JhdGVkIHRlY2hub2xvZ3kgdG8gbWFrZSB5b3VyIGpvYiBlYXNpZXIKRG93
bmxvYWQgSUJNIFdlYlNwaGVyZSBBcHBsaWNhdGlvbiBTZXJ2ZXIgdi4xLjAuMSBiYXNlZCBvbiBB
cGFjaGUgR2Vyb25pbW8KaHR0cDovL3NlbC5hcy11cy5mYWxrYWcubmV0L3NlbD9jbWQ9bG5rJmtp
ZD0xMjA3MDkmYmlkPTI2MzA1NyZkYXQ9MTIxNjQyCl9fX19fX19fX19fX19fX19fX19fX19fX19f
X19fX19fX19fX19fX19fX19fX19fCkJsdWV6LWRldmVsIG1haWxpbmcgbGlzdApCbHVlei1kZXZl
bEBsaXN0cy5zb3VyY2Vmb3JnZS5uZXQKaHR0cHM6Ly9saXN0cy5zb3VyY2Vmb3JnZS5uZXQvbGlz
dHMvbGlzdGluZm8vYmx1ZXotZGV2ZWwK
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Bluez-devel] Big patch to a2dpd
2006-09-07 20:36 ` Michael Frey
@ 2006-09-07 22:46 ` Brad Midgley
0 siblings, 0 replies; 19+ messages in thread
From: Brad Midgley @ 2006-09-07 22:46 UTC (permalink / raw)
To: BlueZ development
Michael
> This new version works great. Has anyone been able to watch a movie
> with mplayer? Playing audio is just fine. Playing a movie -- the
> video can not keep up. Any hints?
latency is pretty bad. if it's at least consistent, you could try the
mplayer prefs to delay the video for whatever fraction of a second it's
off by.
which set is this? i've noticed latency was worse on some of the first
sets out there. we have introduced a lot of latency too with using a
sound server.
brad
-------------------------------------------------------------------------
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
_______________________________________________
Bluez-devel mailing list
Bluez-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bluez-devel
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Bluez-devel] Big patch to a2dpd
2006-09-07 21:06 ` Andrew Waldram
@ 2006-09-07 22:52 ` Brad Midgley
0 siblings, 0 replies; 19+ messages in thread
From: Brad Midgley @ 2006-09-07 22:52 UTC (permalink / raw)
To: BlueZ development
Andrew
> I notice that the maximum volume is a lot lower from my PC than my
> wondows PDA is there anyway to increase the volume at the PC side before
> transmission to the headset.?
I'm afraid the problem is in the encoder. When we went to fixed point,
the stream would "snap" every few seconds when the math would overflow.
we had to fiddle a lot with levels so it wouldn't overflow and now we're
knocking out too much steam.
brad
-------------------------------------------------------------------------
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
_______________________________________________
Bluez-devel mailing list
Bluez-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bluez-devel
^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2006-09-07 22:52 UTC | newest]
Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-09-02 6:21 [Bluez-devel] Big patch to a2dpd Li, Lea
2006-09-06 3:06 ` Brad Midgley
-- strict thread matches above, loose matches on Subject: below --
2006-09-06 3:12 Li, Lea
2006-09-06 3:38 ` Brad Midgley
2006-09-06 9:33 ` Frédéric DALLEAU
2006-09-07 16:48 ` Andrew Waldram
2006-09-07 19:47 ` Brad Midgley
2006-09-07 20:36 ` Michael Frey
2006-09-07 22:46 ` Brad Midgley
2006-09-07 21:06 ` Andrew Waldram
2006-09-07 22:52 ` Brad Midgley
2006-09-02 6:04 Li, Lea
2006-09-02 13:02 ` Michael Frey
2006-08-23 16:55 [Bluez-devel] Small " Frédéric DALLEAU
2006-08-30 14:45 ` Brad Midgley
2006-08-31 16:04 ` [Bluez-devel] Big " Frédéric DALLEAU
2006-09-01 12:57 ` andy
2006-09-01 18:25 ` Michael Frey
2006-09-02 16:05 ` Brad Midgley
2006-09-02 16:08 ` Brad Midgley
2006-09-02 17:01 ` Brad Midgley
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox