Hi, thank you very much for your comments!
So, here is what I did on my Ubuntu laptop:
- Setup of device/soundcard "hw:0,0" for processing at a samplerate of 44.1 kHz, buffersize 128 samples.
Please note that not every hardware might support these specific parameters.
Yes, in the future, I will use the core functionality of audio processing within a GUI based application so that other devices with different setups have to be setup by the user.
- I created one input PCM device and one output PCM device handle
- I use the function "snd_async_add_pcm_handler" to install a callback function (ASYNC mode), one for input,
one for output. 4) I use "snd_pcm_link" to synchronize both pcm handles. 5) I use the mmap'ed area access
My motivation to work the way I do is to maximize the control of processing behavior and to minimize the latency. E.g., I have understood from the docs that the snd_pcm_read/snd_pcm_write functions do nothing else than addressing the memory mapped areas. As a conclusion, I realize this access myself to have more control about it.
Why do you want to duplicate snd_pcm_read/write? What do you "control" there, i.e., what are you doing differently?
The additional degree of freedom is that I see the amount of samples which are available in the mmap'ed buffer whereas with read and write, I only get the notification that a specific amount of samples has been available (based on the number of samples to be read/written specified when calling the function). I had the feeling that I can react in a more flexible way using mmap'ed buffers.
And by using the async callbacks, I do not have to deal with blocking or non-blocking read functions or polling related issues.
But instead you have to deal with signal delivery. Besides being nonportable, you are not allowed to do anything useful inside a signal handler.
Why is this nonportable? The sound APIs that I dealt with before more or less by definition work based on callback mechanisms (ASIO, CoreAudio). What is the restriction considering the processing that I plan within the signal handler? Is that a documented restriction? My understanding is that unless my code is too slow to be in time for the next delivery, there should be no problem.
A possible alternative realization would be to start a thread in which I do 1) pcm_read 2) process audio samples 3) pcm_write in an infinite loop. In this case, however, the "read" would also block the "write" for a specific time. This architecture would a) introduce additional delay if I miss the next required "write" due to the blocking "read". b) might reduce the available processing time (operation "process audio samples") since I have "wasted" time in the blocking "read".
And using two distinct threads for input and output, one looping over "pcm_read" and the other looping over "process audio samples" followed by "pcm_write" would be a third option. This, however, would not be so different from my approach but would increase the programming effort from my point of view (effort to start threads).
c) The function "snd_pcm_info_get_sync" is supposed to return a description of the synchronization behavior of a soundcard. In my case, I called this function for two soundcards (one USB and the laptop integrated soundcard). In both cases, the returned content is all zeros. Should not this be different for both devices?
These functions return useful values only if snd_pcm_hw_params_can_sync_start().
Ah, ok, I will test that.
d) By default, it seems that the callbacks for audio frames come within a thread with normal priority.
Please don't mix signals and threads.
Maybe I should be more precise at this point: I assume that the asynchronous callback handler functions are triggered repeatedly from within one thread which is started by the ALSA Lib on processing startup (that is: one thread for input callbacks, one for output callbacks). I would want to raise the priority of these two threads. Maybe my assumption is wrong?
However, what does this means for audio processing on the frame level: If I use two callbacks for signal processing for input and output respectively installed based on the function "snd_async_add_pcm_handler", will these callbacks occur simultaneously?
This depends. If both buffers are configured with the same parameters, and if both devices run from the same sample clock, then both devices should be ready at approximately the same time. (A playback device needs to fill it FIFO before playing these samples, while a capture device needs to write its FIFO to memory after recording the samples, so you could expect the capture notification to be a little bit later, unless the hardware specifically avoids this.)
I have no clue how two simultaneous signals behave. You should use poll() so that you can wait for both devices being ready.
So, the conclusion is that it is not really defined and I have to deal with synchronization of input and output myself, is that the right interpretation?
Thank you again and best regards
HK