St?phane Letz wrote:
>>>>
>>>
>>> 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....)
>>
>> Duplex works fine with multiple threads.  You can have two file 
>> descriptors, one used by the reading thread (opened O_RDONLY) and one 
>> used by the playback thread (opened O_WRONLY).  You don't have to use 
>> only a single file descriptor to make this work.
>>
>> You should *not* assume that the two sides (read vs. write) are 
>> synchronized.  On a single device, they might have different 
>> fragmentation boundaries, and might use completely independent 
>> clocks!  (This is not as uncommon as you might think.)
>
> Do you mean with an input and output rate that would not stay in 
> synch? What is the application supposed to do (for example in a input 
> ==> some processing  ==> output case) Resample?

In general, the sample rates *should* be the same, but there could be 
some clock drift.   The *fragment sizes* might also not be the same, 
even if the clock rates are.   Resampling shouldn't be necessary, but 
tying the input quantum to the output quantum *might* be a mistake.

>
>>
>> I think the root of your troubles here are "assumptions".  Well 
>> written code won't have any such assumptions and will work well 
>> regardless of the details of the device driver, or even the 
>> underlying implementation.
>>
>>>
>>> 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.
>>
>> *That* is a bad assumption.  You're trying to get a promise/guarantee 
>> from the kernel that simply doesn't exist.  And, you don't actually 
>> need the promise if your code is written properly.
>>
>> To prevent overruns or underruns, you need to either restrict your 
>> writes or reads to the size that can be performed without blocking 
>> (which you can learn with the SNDCTL_DSP_GETOSPACE/ISPACE ioctls), or 
>> use non-blocking IO.  If you want to do this for both read and write 
>> in a single thread, you'll need to also use poll().
>>
>> All the other approaches you're thinking of are hacks that *might* 
>> work for some of the devices some of the time, but which are 
>> technically "incorrect" and will almost certainly fail for *some* 
>> devices, at least some of the time.
>
> Do we at least agree on the fact that a duplex processing application 
> *cannot* use more than the time slice represented by the buffer-size 
> value the application processing part is using, *on average* ?
>
>  (I agree that for a *given* cycle this may be more, if the output 
> buffer has some frames in advance to compensate...)

Yes, I think I would agree with that.
>
>>
>>>
>>> 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.
>>
>> Okay, one thread will work for you, but you need to use the poll or 
>> ioctl or nonblocking approaches I've already pointed out then.  My 
>> sample code should help you out there.
>>
>> Actually, with your crazy processing considerations, probably what we 
>> should do is look into getting you mmap(2) support, where you can 
>> just run completely disconnected from the kernel code, and use 
>> whatever speed and rate is most comfortable for your server.  
>> Unfortunately, the mmap(2) syscall isn't supported by Boomer Phase I 
>> (it will be in Phase II), and in any case it isn't portable to all 
>> drivers.  (4Front's code only supports it on Linux, and only for some 
>> devices ... e.g. USB audio probably doesn't support it because USB 
>> devices don't use memory mapped IO.)
>
> Yes I know mmap would be much better (used in JACK ALSA backend  in 
> Linux)

Hopefully you'll be able to use it in a couple of months when we have 
Boomer Phase II ready for test.

    -- Garrett
>
> Stephane Letz


Reply via email to