Pipeline tracing
It would be very handy for debugging and experimenting to have a feature of tracing the path through the pipeline of every bunch of samples.
The suggested solution is to add a stats object that contains timestamps for all important pipeline steps, attach this object to every packet and frame, fill while it goes through the pipeline, and write to a file at the end.
This object will be created when a frame is retrieved from a soundcard or packet is received from the network.
While the frame or packet travels through the pipeline, different pipeline elements will fill the timestamps in the stats objects that correspond to the element.
When a packet is split into frames (or frame is split into packets), the stats object should be inherited by the newly created frames (or packets). We should somehow take into account that one frame may be formed from multiple packets, and vise versa.
When a packet or frame ends its life cycle (a packet is sent or a frame is written to the soundcard), its stats object should be written to a file.
The suggested trace format is CSV. It is human-readable and is easy to format and parse both in C++ and in scripts or environments like MATLAB. Every line would correspond to a single stats object. It would be also handy to generate a CSV header describing the fields.
Writing to a file should be likely performed in a background thread to avoid blocking the pipeline.
Here is the rough path of an audio sample:
on sender:
- the sample is retrieved from an audio source (soundcard or file) and added to an audio frame
- the audio frame goes through some processing
- the audio frame is splitted and encoded into packets
- the packet is enqueued for send
- the packet is sent
and then on receiver:
- the packet is received and stored into receiver queue
- the packet is routed to session and stored into the session queue
- the packet is stored into the current FEC block table
- the packet is decoded and the samples are written to an audio frame
- the audio frame goes through some processing, including resampling
- the audio frame is written to an audio sink (soundcard or file)
Besides that, samples can be lost by the network or be dropped on receiver:
- if kernel buffer is full
- if packet queue is full
- if packet is from the previous FEC block
- if packet's timestamp is before than the playback timestamp
- if samples were written to the sound card too late
Also, lost samples can be recovered in the FEC reader.
Docs: https://roc-streaming.org/toolkit/docs/internals/data_flow.html