>
> This would work *if* you were willing to tolerate the fact that  
> your write of 1024 might take a while.  (Or the read.)  But this  
> can cause underruns on either the write or the read side (whichever  
> side you *aren't* writing or reading to), especially if your read  
> or write request is larger than a fragment or two.   (Actually, as  
> I think about it, using a *small* buffer -- smaller than the  
> fragment size -- should be free of this problem, but you'll have  
> higher processing overhead in your application, and it makes a bad  
> assumption about the input and output fragment sizes being the  
> same, which may not always be true.)
>
> In other words, while you're waiting for your write() to complete,  
> the capture data may become available and the capture queue can  
> overfill, causing an overrun and lost capture data.
>
> Conversely, while you're waiting for read() to complete, the  
> playback buffer could drain completely, causing an underrun and the  
> resulting popping noises.
>
> Using multiple threads (one for reading, and one for writing)  
> solves this problem cleanly -- each thread will do the processing  
> as soon as the underlying kernel code indicates availability, and  
> then you *can* skip most of the compexity associated with poll and  
> ioctl, and just use normal blocking IO.   (But then you should open  
> two file descriptors, one with O_RDONLY, and one with O_WRONLY).
>
> It should be obvious that you get a big simplification from using  
> separate threads -- if you're OS can support it and you don't have  
> other reasons to require synchronization between capture and  
> playback processing.
>
>    -- Garrett
>

I understand the need for 2 threads in "general" case, but here the  
requeriments are somewhat restricted. JACK server runs usually in  
*duplex* mode, using a card and using input and output devices of the  
*same* card. That is we assume both devices runs completely  
synchronized (otherwise we are not going to try having a system meant  
for completely synchronous execution to work reliably....)

That said, the system is supposed to consume and produce frames at  
the right time! Said in another way, if the execution of the client  
graph takes toom much time, then we have an "Xrun (overrun/underrun)"  
which is perfectly normal... What else could we do? We can possible  
smooth  "occasionnal" CPU spike a bit by prefilling the output  
buffer, but in the general case, the audio cycle : Read / Process/  
Write is not supposed to take more time than represented but the  
"buffer size" used in the graph processing.

So to summarize, we prefill output a bit to avoid underruns, then the  
Read / Process/ Write is supposed to work at the right speed. And  
this one thread model simplify others parts: we don't need to use  
additonal "ring-buffers" or "queues" to move data between the thread  
that calls the graph "Process" and the one that would call Read/Write.

Stephane Letz




Reply via email to