2005-05-04 19:58:49

by Brad Midgley

[permalink] [raw]
Subject: [Bluez-devel] 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


2005-05-09 21:27:25

by Brad Midgley

[permalink] [raw]
Subject: Re: [Bluez-devel] yes, a2dp timing is whacked

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

Brad Midgley wrote:
> 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

2005-05-09 07:21:56

by Brad Midgley

[permalink] [raw]
Subject: Re: [Bluez-devel] yes, a2dp timing is whacked

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.

Brad Midgley wrote:
> 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
>
> Marcel Holtmann wrote:
>
>> Hi Henryk,
>>
>>
>>>> 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.
>
>
> ------------------------------------------------------------------------
>
> Index: a2play.c
> ===================================================================
> RCS file: /cvsroot/bluetooth-alsa/btsco/a2play.c,v
> retrieving revision 1.64
> diff -u -b -B -w -p -r1.64 a2play.c
> --- a2play.c 7 May 2005 02:43:00 -0000 1.64
> +++ a2play.c 9 May 2005 06:30:36 -0000
> @@ -56,6 +56,7 @@
> #define BUFS 1024
>
> static 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 */
> }
>


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

2005-05-09 06:34:58

by Brad Midgley

[permalink] [raw]
Subject: Re: [Bluez-devel] yes, a2dp timing is whacked

Index: a2play.c
===================================================================
RCS file: /cvsroot/bluetooth-alsa/btsco/a2play.c,v
retrieving revision 1.64
diff -u -b -B -w -p -r1.64 a2play.c
--- a2play.c 7 May 2005 02:43:00 -0000 1.64
+++ a2play.c 9 May 2005 06:30:36 -0000
@@ -56,6 +56,7 @@
#define BUFS 1024

static 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 */
}


Attachments:
a2play.patch (1.98 kB)

2005-05-07 20:45:15

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [Bluez-devel] yes, a2dp timing is whacked

Hi Henryk,

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

2005-05-07 20:20:47

by Henryk Plötz

[permalink] [raw]
Subject: Re: [Bluez-devel] yes, a2dp timing is whacked

Moin,

Am Sat, 07 May 2005 21:27:33 +0200 schrieb Marcel Holtmann:

> forget about this stupid idea. I tried it and it is not working out.

I didn't like it either.

> 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?).

--
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! ~


Attachments:
(No filename) (743.00 B)
(No filename) (189.00 B)
Download all attachments

2005-05-07 19:27:33

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [Bluez-devel] yes, a2dp timing is whacked

Hi Henryk,

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

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

2005-05-07 01:26:41

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [Bluez-devel] yes, a2dp timing is whacked

Hi Henryk,

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

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

2005-05-07 01:13:14

by Henryk Plötz

[permalink] [raw]
Subject: Re: [Bluez-devel] yes, a2dp timing is whacked

Moin,

Am Wed, 04 May 2005 13:58:49 -0600 schrieb Brad Midgley:

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

> I will start by looking at the rtc interface and trying to find hooks
> in alsa for timing.

That would be really cool.

--
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! ~


Attachments:
(No filename) (809.00 B)
(No filename) (189.00 B)
Download all attachments