ha7ilm / openwebrx

Open source, multi-user SDR receiver software with a web interface
https://sdr.hu/openwebrx
GNU Affero General Public License v3.0
982 stars 464 forks source link

High latency #57

Open dh1tw opened 7 years ago

dh1tw commented 7 years ago

Hi,

out of curiosity (without having dived into the code), why is the latency so high in Openwebrx? It take between 1-2 seconds after moving the receiving slice until the changes are hearable.

ha7ilm commented 7 years ago

Every stage of signal processing is running in a separate csdr process. IPC between them is implemented using OS pipes. A standalone example is like this:

rtl_sdr -s 240000 -f 89500000 -g 20 - | csdr convert_u8_f | csdr fmdemod_quadri_cf | csdr fractional_decimator_ff 5 | csdr deemphasis_wfm_ff 48000 50e-6 | csdr convert_f_s16 | mplayer -cache 1024 -quiet -rawaudio samplesize=2:channels=1:rate=48000 -demuxer rawaudio -

Scheduling is done by the OS, which typically means that a block runs until it has no more input, or it is out of its time frame.

The GNU Radio framework has its own scheduler that could be fine tuned in the code for low latency. My approach with csdr takes many problems of a dataflow system to the OS level, which made this project certainly easier to implement, but it is harder to fine tune things like buffer sizes, scheduling, etc. that affects latency. (A similar approach with pipes is used in LuaRadio.)

I've put some effort into making latency lower. Some things helped it, some other things did not: e.g. I've implemented automatic buffer size determination, but it does not make much difference.

The latency could be improved by writing a wrapper in C that would schedule calling the already existing signal processing functions, but that would decrease flexibility (now a new demodulator can be added by just adding a few lines to plugin.py, as demodulators are defined by the command line to run).

ha7ilm commented 7 years ago

The other thing that affects latency is the Javascript code at the client side. The client_audio_buffer_size option in config_webrx.py is related to that.

dh1tw commented 7 years ago

Hi András,

thanks for the detailed description. If I understand your answer and your bachelor theses correctly, you create an entire receiver chain for each browser connected via the OpenWebRX interface.

Have you done any benchmarking which part of the receiver chain is consuming how much CPU? I can imagine that the FFT will consume quite some CPU. In particular if you are calculating the FFT up to 4 times over the same data (once per receiver chain).

Maybe It would make sense to perform the FFT just once for all the receivers and then share the FFT results via shared memory or a Publish/Subscribe middleware like ZeroMQ.

ha7ilm commented 7 years ago

FFT (for the original input signal) is calculated only once and shared among all receivers, to draw the waterfall diagram.

There is a filter later in the audio processing chain that uses FFT, but this works on a different signal for each receiver, so the result cannot be shared here.

The latency is not caused by high CPU load, rather from the way the OS schedules the operations.