All of lore.kernel.org
 help / color / mirror / Atom feed
* Event Based time synchronization with ALSA
@ 2005-01-17 10:50 Paolo Losi
  2005-01-17 16:45 ` Benno Senoner
  0 siblings, 1 reply; 6+ messages in thread
From: Paolo Losi @ 2005-01-17 10:50 UTC (permalink / raw)
  To: alsa-devel

Hi all,
	I'd like to develop a sip phone using alsa...

All the app is going to be event based (no_blocking io, poll).

One of the issues is how to read 20ms sample periods
to build an rtp packet

What I'd like to understand is if I can rely on interrupts (poll
read data available event) by HW in order to get accurate 50HZ
poll frequency or I must rely on poll timeout instead...

My goal is (as always :-) ) to reduce as much as I can latency...

In the case poll events would be enough what would be the
relevant sw_params api's?

	Thank you very much

	PL


-------------------------------------------------------
The SF.Net email is sponsored by: Beat the post-holiday blues
Get a FREE limited edition SourceForge.net t-shirt from ThinkGeek.
It's fun and FREE -- well, almost....http://www.thinkgeek.com/sfshirt

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

* Re: Event Based time synchronization with ALSA
  2005-01-17 10:50 Event Based time synchronization with ALSA Paolo Losi
@ 2005-01-17 16:45 ` Benno Senoner
  2005-01-17 19:46   ` Jaroslav Kysela
  2005-01-18 11:47   ` Paolo Losi
  0 siblings, 2 replies; 6+ messages in thread
From: Benno Senoner @ 2005-01-17 16:45 UTC (permalink / raw)
  To: Paolo Losi; +Cc: alsa-devel

I suggest you to do the following:

have a thread that does audio I/O and write/read the
audio data to 2 ringbuffers using eg frame size of about 10msec.
10msec = 441 samples, thus I'd choose 512 samples (alsa period sizes 
must be power of 2).

for example for the RTP sending (capturing audio from the alsa device 
and send a RTP packet).

you could for example do:

short audiobu[512];

while(1) {

 capture_audio_from_alsa(audiobuf) // (blocking read,  512 samples)

 write_to_ringbuffer(audiobuf, 512); // write the 512 samples to the 
ringbuffer

 space = get_ringbuffer_read_space(); // now we get how many samples are 
accumulated in the ringbuffer

 if(space >= 882)  {   // ( 882 = 20msec of samples at 44100Hz).
    ringbufferdata = read_from_ringbuffer(882);
    send_rtp_packet(ringbufferdata);
  }


}

The above routine has the advantage that you can use any kind of 
periodsize (fragment size) in ALSA
and the send_rtp packet() always gets 20msec worth of data.
But you must ensure that the ALSA period size must be <20msec , 
otherwise too much jitter is introduced.
eg if I have a periodsize of 100msec , the ALSA blocking read() will 
block until 100msec worth of audio are available

and then the send_rtp_packet() would only fetch 20msec of audio from the 
ringbuffer and the thread would sleep
for 100msec again and the ringbuffer would eventually fill up leading to 
garbled RTP audio (you hear only
every 5th packet).
You could wrap  space = ...  ; if(space >= 882) in a while(space >= 882) 
loop but that would cause to send
out fast bursts of 20msec packets each 100msec probably overrunning or 
putting strain on the jitter buffer
on the receiving side of the other SIP phone.

So far for the sending side of your SIP phone.

The receiving side is more complex since RTP packets (which are based on 
UDP) could come out of order
so you need a jitter buffer (sliding window) which reorders the packets, 
discards late packets etc.
Or if you assume that out of order packets are very rare you could 
ignore the case and discard the packet.
and simply insert the RTP audio data to the end of a receiving 
ringbuffer (in an analogous way like the the code
above) and have the audio thread writing an audio frames to the ALSA 
device as soon as enough packets are here.
The problem of the internet is that it is not easy to estimate the 
latency in advance (eg when you do a oversea
SIP call) so you have to use an adaptive algorithm which measures jitter 
between packets
(eg instead of each 20msec, some packets could arrive after 100msec but 
then 5 packets in a burst etc), and thus
adapting the size of the ringbufffer dynamically based on the latency 
measurements.
This will give you the lowest possible latency with the best call quality.
Perhaps if you look at the code of some of the opensource soft phones 
you can get an idea what's the best method
to implement this.

ciao,
Benno









Paolo Losi wrote:

> Hi all,
>     I'd like to develop a sip phone using alsa...
>
> All the app is going to be event based (no_blocking io, poll).
>
> One of the issues is how to read 20ms sample periods
> to build an rtp packet
>
> What I'd like to understand is if I can rely on interrupts (poll
> read data available event) by HW in order to get accurate 50HZ
> poll frequency or I must rely on poll timeout instead...
>
> My goal is (as always :-) ) to reduce as much as I can latency...
>
> In the case poll events would be enough what would be the
> relevant sw_params api's?
>
>     Thank you very much
>
>     PL
>
>
> -------------------------------------------------------
> The SF.Net email is sponsored by: Beat the post-holiday blues
> Get a FREE limited edition SourceForge.net t-shirt from ThinkGeek.
> It's fun and FREE -- well, almost....http://www.thinkgeek.com/sfshirt
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/alsa-devel
>



-------------------------------------------------------
The SF.Net email is sponsored by: Beat the post-holiday blues
Get a FREE limited edition SourceForge.net t-shirt from ThinkGeek.
It's fun and FREE -- well, almost....http://www.thinkgeek.com/sfshirt

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

* Re: Event Based time synchronization with ALSA
  2005-01-17 16:45 ` Benno Senoner
@ 2005-01-17 19:46   ` Jaroslav Kysela
  2005-01-18  9:40     ` Takashi Iwai
  2005-01-18 11:47   ` Paolo Losi
  1 sibling, 1 reply; 6+ messages in thread
From: Jaroslav Kysela @ 2005-01-17 19:46 UTC (permalink / raw)
  To: Benno Senoner; +Cc: Paolo Losi, alsa-devel

On Mon, 17 Jan 2005, Benno Senoner wrote:

> 10msec = 441 samples, thus I'd choose 512 samples (alsa period sizes 
> must be power of 2).

It's not true. You may use any size which hardware / end plugin supports, 
but it's true that many drivers don't allow other period sizes that 
power of 2.

						Jaroslav

-----
Jaroslav Kysela <perex@suse.cz>
Linux Kernel Sound Maintainer
ALSA Project, SUSE Labs


-------------------------------------------------------
The SF.Net email is sponsored by: Beat the post-holiday blues
Get a FREE limited edition SourceForge.net t-shirt from ThinkGeek.
It's fun and FREE -- well, almost....http://www.thinkgeek.com/sfshirt

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

* Re: Event Based time synchronization with ALSA
  2005-01-17 19:46   ` Jaroslav Kysela
@ 2005-01-18  9:40     ` Takashi Iwai
  0 siblings, 0 replies; 6+ messages in thread
From: Takashi Iwai @ 2005-01-18  9:40 UTC (permalink / raw)
  To: Jaroslav Kysela; +Cc: Benno Senoner, Paolo Losi, alsa-devel

At Mon, 17 Jan 2005 20:46:17 +0100 (CET),
Jaroslav wrote:
> 
> On Mon, 17 Jan 2005, Benno Senoner wrote:
> 
> > 10msec = 441 samples, thus I'd choose 512 samples (alsa period sizes 
> > must be power of 2).
> 
> It's not true. You may use any size which hardware / end plugin supports, 
> but it's true that many drivers don't allow other period sizes that 
> power of 2.

AFAIK, power-of-2 restriction is rare in the ALSA driver level.
But, the restriction is required for OSS emulation, so it's safer if
you consider the portability.


Takashi


-------------------------------------------------------
The SF.Net email is sponsored by: Beat the post-holiday blues
Get a FREE limited edition SourceForge.net t-shirt from ThinkGeek.
It's fun and FREE -- well, almost....http://www.thinkgeek.com/sfshirt

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

* Re: Event Based time synchronization with ALSA
  2005-01-17 16:45 ` Benno Senoner
  2005-01-17 19:46   ` Jaroslav Kysela
@ 2005-01-18 11:47   ` Paolo Losi
  2005-01-18 13:46     ` Benno Senoner
  1 sibling, 1 reply; 6+ messages in thread
From: Paolo Losi @ 2005-01-18 11:47 UTC (permalink / raw)
  To: Benno Senoner; +Cc: alsa-devel

Hi Benno,

	thank you very much for you response.
	
Benno Senoner wrote:
  > The above routine has the advantage that you can use any kind of
> periodsize (fragment size) in ALSA
> and the send_rtp packet() always gets 20msec worth of data.
> But you must ensure that the ALSA period size must be <20msec , 
> otherwise too much jitter is introduced.

I see your point.... but I would have two objections:
- I don't want/can't use threads
- I get too much jitter

If I make poll timeout every 20ms in the main loop,
I'm sure I get 20ms worth of data
so I can busy loop to reading (in blocking mode) all samples
(If I would want to enforced that period is power of two, I could
choose the max power of two number of samples that is divider of the 
required number of samples)
That would be 8000HZ sampling for 20ms => 160 sample per packet
=> 5 32samples reads

But I'd rather tell ALSA: "please wake up poll as soon as you have
160 samples available". Is that feaseble? Can I expect to be always
woken up?

How

snd_pcm_sw_params_set_avail_min
snd_pcm_sw_params_set_sleep_min
snd_pcm_sw_params_set_start_threshold  	

relates to my problem?

I tried to read the API doc but, since I've no experience with audio
programming, I didn't get all the points...

Can anyone point to a good poll based read example?

	thanks again benno!

	Paolo


-------------------------------------------------------
The SF.Net email is sponsored by: Beat the post-holiday blues
Get a FREE limited edition SourceForge.net t-shirt from ThinkGeek.
It's fun and FREE -- well, almost....http://www.thinkgeek.com/sfshirt

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

* Re: Event Based time synchronization with ALSA
  2005-01-18 11:47   ` Paolo Losi
@ 2005-01-18 13:46     ` Benno Senoner
  0 siblings, 0 replies; 6+ messages in thread
From: Benno Senoner @ 2005-01-18 13:46 UTC (permalink / raw)
  To: alsa-devel

Paolo Losi wrote:

> Hi Benno,
>
>     thank you very much for you response.
>     
> Benno Senoner wrote:
>  > The above routine has the advantage that you can use any kind of
>
>> periodsize (fragment size) in ALSA
>> and the send_rtp packet() always gets 20msec worth of data.
>> But you must ensure that the ALSA period size must be <20msec , 
>> otherwise too much jitter is introduced.
>
>
> I see your point.... but I would have two objections:
> - I don't want/can't use threads


you can use a single thread as described in my previous mail.
you just write to a ringbuffer and afterwards read from the same 
ringbuffer to have an easy method
to queue up samples until you have at least 20msec worth of audio data 
(160 samples at 8kHz).
But as said you need to write(and read) to the ringbuffer with a 
granularity greater than 20msec otherwise
weird things do happen.
The same can be done on the receiving side. Assume you read/write audio 
samples with eg 8msec frequency
(period size 64 samples).
At each iteration you check if an RTP packet arrived (using nonblocking 
recv() ) and if it arrived you insert it into
the receiving buffer (check ordering etc).

> - I get too much jitter

this is not true. Jitter will always be here on a RTP data stream and 
that's why the receiver must use a receiving
buffer that is at least 2-3 times bigger than the payload of the RTP 
packet (eg 20msec).
For example if the receive buffer is 40msec you can have up to 40msec 
jitter (eg a packet can come up to 40msec late)
without any audio degradation. Keep in mind that an oversea SIP call can 
often have hundreds of msec of latency
and thus the jitter could be in the range of 100msec or more.
This means you have to use an adequately sized buffer, otherwise you get 
lots of late packets and therefore grabled audio.

Anyway why not use jack as the API for your application ? It's easier to 
program and you don't have to mess with
setting up the soundcard, deal with different characterstics of 
soundcards (like sample rate, sample size etc, ... ok
ALSA plughw can ease some pain too).

Jaroslav, while you are right about that periodsize can be != power of 
two on many cards, I agree with Takashi about
trying to use a power of two periodsize if possible.
Anyway the algorithm I proposed in my former mail does not impose 
restrictions on the period size except that
it must be < than RTP audio period size.
So if you use  RTP audio sizes of 20msec, you can use anything from  19 
down to 1msec.
But when choosing the capture size it is better to not go too low 
otherwise you could get XRUNs and you load up
the CPU more. Probably around 8-10msec is an ideal size because the 
introduced jitter is < 10msec (which
is not a problem for the receiver size which will have a receive buffer 
of N*20msec) plus  you can probably run
the app without SCHED_FIFO without getting significant xrun problems 
(except in high load situations).
 

>
> If I make poll timeout every 20ms in the main loop,
> I'm sure I get 20ms worth of data
> so I can busy loop to reading (in blocking mode) all samples
> (If I would want to enforced that period is power of two, I could
> choose the max power of two number of samples that is divider of the 
> required number of samples)
> That would be 8000HZ sampling for 20ms => 160 sample per packet
> => 5 32samples reads


5 x 32 sample reads means you must wake up the thread each 4msec, 
perhaps a bit of a waste.
Plus I would not trust the OS that you get woken up at the right time, 
but since I don't know ALSA's internals
well it could be that it does not matter since ALSA might queue up the 
samples in an internal ringbuffer for you
which could make my proposed external ringbuffer redundant.
The advantage of my proposal is that it works with any kind of audio 
interface and with any period size.
When coding apps I tend to make as little as possible assumptions about 
underlying APIs and subsystems
because if at a later time you want to switch to other APIs or hardware 
changing the app gets very messy.

>
> But I'd rather tell ALSA: "please wake up poll as soon as you have
> 160 samples available". Is that feaseble? Can I expect to be always
> woken up?
>
> How
>
> snd_pcm_sw_params_set_avail_min
> snd_pcm_sw_params_set_sleep_min
> snd_pcm_sw_params_set_start_threshold     
>
> relates to my problem?
>
> I tried to read the API doc but, since I've no experience with audio
> programming, I didn't get all the points...

> Can anyone point to a good poll based read example?

On the http://www.alsa-project.org site there should be some examples, 
otherwise try to check
out the source of aplay.
And if ALSA is too complex for you there's always jack  :) 
http://jackit.sf.net
What I prefer of jack is the ability to route audio from/to any app, use 
many apps at the same
time sharing the same soundcard etc.
For example a SIP phone with jack support could easily record the 
conversation into a HDR app
(like eca, ardour etc), or you could feed music into it by simply 
connecting the output from any app
into the SIP phone. (eg connect the softsynth to the SIP phone and then 
play a piece live for your
party on the other side :) )

>     thanks again benno!

no problem :)
I wish you luck with your audio programming. It's sometimes very 
frustrating until you get things
running smoothly but the gratification is big and you can learn lots of 
things when implementing
real time audio/networking apps. (synchronization, buffering, 
multithreading, jitter handling, scheduling etc).

cheers,
Benno
http://www.linuxsampler.org



-------------------------------------------------------
The SF.Net email is sponsored by: Beat the post-holiday blues
Get a FREE limited edition SourceForge.net t-shirt from ThinkGeek.
It's fun and FREE -- well, almost....http://www.thinkgeek.com/sfshirt

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

end of thread, other threads:[~2005-01-18 13:46 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-01-17 10:50 Event Based time synchronization with ALSA Paolo Losi
2005-01-17 16:45 ` Benno Senoner
2005-01-17 19:46   ` Jaroslav Kysela
2005-01-18  9:40     ` Takashi Iwai
2005-01-18 11:47   ` Paolo Losi
2005-01-18 13:46     ` Benno Senoner

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.