yes, a2dp timing is whacked
Hey
I have the hp headset now. woohoo. a2play will use it but only after tuning the usleep parameter for my specific setup. I think the hp does buffer a little bit (a2play seems to finish streaming just a bit before the audio track finishes)
I will start by looking at the rtc interface and trying to find hooks in alsa for timing.
Maybe for convenience, libsbc should compute the timeslice for the frame.
Brad
-------------------------------------------------------
This SF.Net email is sponsored by: NEC IT Guy Games.
Get your fingers limbered up and give it your best shot. 4 great events, 4 opportunities to win big! Highest score wins.NEC IT Guy Games. Play to win an NEC 61 plasma display. Visit http://www.necitguy.com/?r=20
_______________________________________________
Bluez-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/bluez-devel
Moin,
Am Wed, 04 May 2005 13:58:49 -0600 schrieb Brad Midgley:
Quoted 2 lines
Maybe for convenience, libsbc should compute the timeslice for the frame.
It does now. I added a function sbc_time(sbc_t *sbc) which computes the microseconds for one frame. I then replaced the fixed value in a2play's usleep() call with the time the whole packet should take to play (time for one frame times number of frames in the packet) multiplied by (arbitrarily chosen) 0.8 to make up for the time lost with computing and sending.
Quoted 2 lines
I will start by looking at the rtc interface and trying to find hooks in alsa for timing.
That would be really cool.
Signature · 4 lines
Henryk Plötz Grüße aus Berlin ~~~~~~~ Un-CDs, nein danke! http://www.heise.de/ct/cd-register/ ~~~~~~~ ~ Help Microsoft fight software piracy: Give Linux to a friend today! ~
Marcel Holtmann
maintainerHi Henryk,
Quoted 9 lines
Quoted 2 lines
Maybe for convenience, libsbc should compute the timeslice for the frame.
It does now. I added a function
sbc_time(sbc_t *sbc)which computes the microseconds for one frame. I then replaced the fixed value in a2play'susleep()call with the time the whole packet should take to play (time for one frame times number of frames in the packet) multiplied by (arbitrarily chosen) 0.8 to make up for the time lost with computing and sending.
the time that is eaten up by encoding or decoding could be measured with gettimeofday() and then you can subtract this from the whole time.
Since it is a linear operation we can make the SBC library do it all for us. Let sbc_encode() and sbc_decode() calculate the processing time and then store a sleep value for us inside sbc_t.
And the value should be really unsigned long and not int.
Regards
Marcel
-------------------------------------------------------
This SF.Net email is sponsored by: NEC IT Guy Games.
Get your fingers limbered up and give it your best shot. 4 great events, 4 opportunities to win big! Highest score wins.NEC IT Guy Games. Play to win an NEC 61 plasma display. Visit http://www.necitguy.com/?r=20
_______________________________________________
Bluez-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/bluez-devel
Marcel Holtmann
maintainerHi Henryk,
Quoted 10 lines
Quoted 9 lines
Quoted 2 lines
Maybe for convenience, libsbc should compute the timeslice for the frame.
It does now. I added a function
sbc_time(sbc_t *sbc)which computes the microseconds for one frame. I then replaced the fixed value in a2play'susleep()call with the time the whole packet should take to play (time for one frame times number of frames in the packet) multiplied by (arbitrarily chosen) 0.8 to make up for the time lost with computing and sending.
Quoted 6 lines
the time that is eaten up by encoding or decoding could be measured with
gettimeofday()and then you can subtract this from the whole time.Since it is a linear operation we can make the SBC library do it all for us. Let
sbc_encode()andsbc_decode()calculate the processing time and then store a sleep value for us insidesbc_t.
forget about this stupid idea. I tried it and it is not working out. So I only moved the time calculation into sbc->duration and added the gettimeofday() magic into a2play. This is somekind of working, but the quality is not that good with the HP headphone.
I also figured out that the HP headphone has somekind of buffer and you can send more than one AVDTP frame (equals 8 SBC frames). But it seems that this is somekind of ringbuffer. Too many frames will overwrite previous frames and make the sound a mess.
So the best thing is too encode two or three full AVDTP frames in advance and have them ready to send. The sending can't be controlled be usleep(). We need a time that kicks in every whatever msec and makes us to transmit the next frame.
Regards
Marcel
-------------------------------------------------------
This SF.Net email is sponsored by: NEC IT Guy Games.
Get your fingers limbered up and give it your best shot. 4 great events, 4 opportunities to win big! Highest score wins.NEC IT Guy Games. Play to win an NEC 61 plasma display. Visit http://www.necitguy.com/?r=20
_______________________________________________
Bluez-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/bluez-devel
Moin,
Am Sat, 07 May 2005 21:27:33 +0200 schrieb Marcel Holtmann:
Quoted 1 line
forget about this stupid idea. I tried it and it is not working out.
I didn't like it either.
Quoted 4 lines
So the best thing is too encode two or three full AVDTP frames in advance and have them ready to send. The sending can't be controlled be
usleep(). We need a time that kicks in every whatever msec and makes us to transmit the next frame.
That's what I would favour. According to the libc manual setitimer() would be the function of choice, if nobody else has a better idea (RTC, anyone?).
Signature · 4 lines
Henryk Plötz Grüße aus Berlin ~~~~~~~ Un-CDs, nein danke! http://www.heise.de/ct/cd-register/ ~~~~~~~ ~ Help Microsoft fight software piracy: Give Linux to a friend today! ~
Marcel Holtmann
maintainerHi Henryk,
Quoted 8 lines
Quoted 4 lines
So the best thing is too encode two or three full AVDTP frames in advance and have them ready to send. The sending can't be controlled be
usleep(). We need a time that kicks in every whatever msec and makes us to transmit the next frame.That's what I would favour. According to the libc manual
setitimer()would be the function of choice, if nobody else has a better idea (RTC, anyone?).
so in general the time that a SBC frame is calculated for, is always the same if we don't change the parameters, right?
Using the ITIMER_REAL domain may works and since you can setup your timer in microseconds, then this would be the way to go.
Regards
Marcel
-------------------------------------------------------
This SF.Net email is sponsored by: NEC IT Guy Games.
Get your fingers limbered up and give it your best shot. 4 great events, 4 opportunities to win big! Highest score wins.NEC IT Guy Games. Play to win an NEC 61 plasma display. Visit http://www.necitguy.com/?r=20
_______________________________________________
Bluez-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/bluez-devel
Guys,
I put a rough proof-of-concept implementation together using setitimer. (Yes, it's gross and the signal handler doesn't actually do any work, just indicates that the interval is over)
The music seems to be timed right but it's a very "noisy" signal on the hp headset. Any ideas?
I didn't commit it because it's so ugly.
Brad
Quoted 13 lines · Marcel Holtmann
Hi Henryk,
Quoted 8 lines
Quoted 4 lines
So the best thing is too encode two or three full AVDTP frames in advance and have them ready to send. The sending can't be controlled be
usleep(). We need a time that kicks in every whatever msec and makes us to transmit the next frame.That's what I would favour. According to the libc manual
setitimer()would be the function of choice, if nobody else has a better idea (RTC, anyone?).
Quoted 5 lines
so in general the time that a SBC frame is calculated for, is always the same if we don't change the parameters, right?
Using the
ITIMER_REALdomain may works and since you can setup your timer in microseconds, then this would be the way to go.
Index: a2play.c
===================================================================
RCS file: /cvsroot/bluetooth-alsa/btsco/a2play.c,v retrieving revision 1.64
a2play.c +27 -2
@@ -56,6 +56,7 @@#define BUFS 1024static volatile int terminate =0 ; +static volatile int xmitpause =0 ;static int cmdfd;struct sbc_frame_header sbc_info;
@@ -102,6 +103,16 @@ static void sig_term(int sig) terminate =1 ; } +static void sig_alrm (int sig) +{ +struct sigaction sa; +memset (&sa,0 ,sizeof (sa)); + sa.sa_flags =SA_NOCLDSTOP ; + sa.sa_handler = sig_alrm; +sigaction (SIGALRM , &sa,NULL ); + xmitpause =0 ; +} +// Usage static void usage () {
@@ -404,6 +415,8 @@ s_config was set from sbc_info before:int main (int argc,char *argv[]) { +int timerset =0 ; +struct itimerval itimer;struct sigaction sa;struct timeval start, end;int streamfd;
@@ -619,6 +632,8 @@ int main(int argc, char *argv[]) timestamp =0 ; +sig_alrm (0 ); +while (!terminate) {// a2dp headers: avdtp p.45
@@ -698,8 +713,18 @@ int main(int argc, char *argv[])memcpy (buf +sizeof (packet_header), &payload_header,sizeof (payload_header));write (streamfd, buf, psize); -//printf("\nSending packet:%d, size %d no. of sbc frames:%d", seq_num, psize, payload_header.frame_count); +if (!timerset) { + timerset =1 ; + itimer.it_interval.tv_sec = itimer.it_value.tv_sec =0 ; + itimer.it_interval.tv_usec = itimer.it_value.tv_usec = (sleeptime*95 )/100 ; +if (setitimer (ITIMER_REAL , &itimer,NULL ))printf ("couldn't setitimer\n" ); + } + +while (xmitpause)usleep (10 ); + xmitpause =1 ; +#if 0 +//printf("\nSending packet:%d, size %d no. of sbc frames:%d", seq_num, psize, payload_header.frame_count); pending++;if (pending >4 ) {
@@ -717,7 +742,7 @@ int main(int argc, char *argv[]) sleeptime =0 ; pending = 0; } - +#endif /* END: NONSPECAUDIO == FALSE */ }
I think my hack introduced timing issues of its own... tomorrow I'll fix it up with code that uses a ring buffer and bleeds from the ring in the sighandler.
Quoted 107 lines · Brad Midgley
Guys,
I put a rough proof-of-concept implementation together using setitimer. (Yes, it's gross and the signal handler doesn't actually do any work, just indicates that the interval is over)
The music seems to be timed right but it's a very "noisy" signal on the hp headset. Any ideas?
I didn't commit it because it's so ugly.
Brad
Quoted 15 lines · Marcel Holtmann
Hi Henryk,
Quoted 9 lines
Quoted 4 lines
So the best thing is too encode two or three full AVDTP frames in advance and have them ready to send. The sending can't be controlled be
usleep(). We need a time that kicks in every whatever msec and makes us to transmit the next frame.That's what I would favour. According to the libc manual
setitimer()would be the function of choice, if nobody else has a better idea (RTC, anyone?).Quoted 5 lines
so in general the time that a SBC frame is calculated for, is always the same if we don't change the parameters, right?
Using the
ITIMER_REALdomain may works and since you can setup your timer in microseconds, then this would be the way to go.------------------------------------------------------------------------
Index:
a2play.c
===================================================================
RCS file: /cvsroot/bluetooth-alsa/btsco/a2play.c,v retrieving revision 1.64
diff -u -b -B -w -p -r1.64a2play.ca2play.c +26
-1@@ -56,6 +56,7 @@#define BUFS 1024static volatile int terminate =0 ; +static volatile int xmitpause =0 ;static int cmdfd;struct sbc_frame_header sbc_info;@@ -102,6 +103,16 @@ static void sig_term(int sig) terminate =1 ; } +static void sig_alrm (int sig) +{ +struct sigaction sa; +memset (&sa,0 ,sizeof (sa)); + sa.sa_flags =SA_NOCLDSTOP ; + sa.sa_handler = sig_alrm; +sigaction (SIGALRM , &sa,NULL ); + xmitpause =0 ; +} +// Usage static void usage () {@@ -404,6 +415,8 @@ s_config was set from sbc_info before:int main (int argc,char *argv[]) { +int timerset =0 ; +struct itimerval itimer;struct sigaction sa;struct timeval start, end;int streamfd;@@ -619,6 +632,8 @@ int main(int argc, char *argv[]) timestamp =0 ; +sig_alrm (0 ); +while (!terminate) {// a2dp headers: avdtp p.45 @@ -698,8 +713,18 @@ int main(int argc, char *argv[])memcpy (buf +sizeof (packet_header), &payload_header,sizeof (payload_header));write (streamfd, buf, psize); -//printf("\nSending packet:%d, size %d no. of sbc frames:%d", seq_num, psize, payload_header.frame_count); +if (!timerset) { + timerset =1 ; + itimer.it_interval.tv_sec = itimer.it_value.tv_sec =0 ; + itimer.it_interval.tv_usec = itimer.it_value.tv_usec = (sleeptime*95 )/100 ; +if (setitimer (ITIMER_REAL , &itimer,NULL ))printf ("couldn't setitimer\n" ); + } + +while (xmitpause)usleep (10 ); + xmitpause =1 ; +#if 0 +//printf("\nSending packet:%d, size %d no. of sbc frames:%d", seq_num, psize, payload_header.frame_count); pending++;if (pending >4 ) {
a2play.c int main(int argc, char *argv[]) · line 748
Quoted 8 lines
a2play.c +1
-1@@ -717,7 +742,7 @@ int main(int argc, char *argv[]) sleeptime =0 ; pending = 0; } - +#endif /* END: NONSPECAUDIO == FALSE */ }
-------------------------------------------------------
This SF.Net email is sponsored by: NEC IT Guy Games.
Get your fingers limbered up and give it your best shot. 4 great events, 4 opportunities to win big! Highest score wins.NEC IT Guy Games. Play to win an NEC 61 plasma display. Visit http://www.necitguy.com/?r=20
_______________________________________________
Bluez-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/bluez-devel
guys,
I wrote up basic itimer/ring buffer support in a2play. It still needed some tuning (eg it uses the frame timespan * .87 to set the itimer)
I really just think the HP headset is poorly engineered. Either you are going to send frames too slowly and get a noisy glitch when it hits a dry patch or you are going to send them too quickly and have the occasional pop when it drops a frame. There's no way around it.
I did experiment with ring buffer size and SA_NODEFER option on the signal handler. I was trying to see if one write to the headset could be interrupted by the alarm so that the next frame could get on its way, like if you had a poor connection and wanted to keep the timing more accurate. I finally decided this wasn't the way... a long ring buffer and nodefer enabled meant really fast-playing catch-up periods after the connection was good again.
Brad
Quoted 1 line · Brad Midgley
I think my hack introduced timing issues of its own... tomorrow I'll fix it up with code that uses a ring buffer and bleeds from the ring in the sighandler.
-------------------------------------------------------
This SF.Net email is sponsored by: NEC IT Guy Games.
Get your fingers limbered up and give it your best shot. 4 great events, 4 opportunities to win big! Highest score wins.NEC IT Guy Games. Play to win an NEC 61 plasma display. Visit http://www.necitguy.com/?r=20
_______________________________________________
Bluez-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/bluez-devel