Realtime Requirements
A significant part of the fm_server has to run under strict requirements to be able to produce audio data within the deadlines imposed by the available buffer size.
A short explanation
Basically, the audio card has a small buffer that is regularly emptied to provide data to its analog output, usually (at CD quality) 44100 samples every second (each samples usually 16 bit * 2 channels). As the buffer is starting to run out, the operating system is notified and it immediately transfers execution to the program which has opened the device, in our case fm_server.
The program only has a limited time to execute and produce audio data to refill the buffer before it runs completely out of data. The unluckly case in which the buffer does eventually run empty is called an underrun - at which point the audio card will play some milliseconds of silence or loop over the old data already present in the buffer - the last thing we want to happen while playing.
To avoid this, the vast majority of media players simply use a bigger buffer, giving the application more time to fill the buffer. But every operation, such as pausing the stream or seeking, will have to wait for the bigger buffer to empty up before taking place (incrementing latency). An interactive audio application, such as FreeMix, has to run with the smallest latency possbile to be usable, so it can't use a "big buffer" approach.
Luckily for us, evolutions in OSes and audio systems such as JACK can allow applications to operate reliably even using very small buffers - a good audio card on a properly tuned system can use a buffer of 64 samples or lower (less than 0,7 ms of latency) - but they require the application core to be written respecting serious requirements.
For example, so-called realtime threads can't use blocking syncronization primitives, perform blocking calls or directly allocate memory, as these operations can cause the OS scheduler to pass execution to another process while waiting for their completion, making extremely likely for the buffer to run out before the application has finished its work and is ready to fill it again.
In addition, these threads work at an higher priority than the default for other applications (and often than parts of the operating system kernel) causing them to pre-empt lower priority threads. An error in one of these routines (for example an infinite loop) can cause the entire system to stall and become unusable, needing a reboot (as a command to kill the application can't run as it has a lower priority than the runaway thread).
