π Visualizing clocks and sources
Liquidsoap scripts can grow complex: multiple clocks, many sources, transitions, and time-dependent behaviors interacting together. To help reason about this, Liquidsoap can now display graphs of clocks and sources, giving you a visual overview of how time flows, how sources are connected, and which sources are actively animated.
These graphs are useful while writing or debugging a script, inspecting unexpected timing behavior, or explaining a setup to others.
π§ What is displayed?
Liquidsoap can generate two related graphs:
- Clock graph β shows clocks, their relationships, and which sources are active on each clock
- Source graph β shows sources and how they are connected
To build these graphs, Liquidsoap needs to run the script for a short time so it can observe clocks, sources, activations, and time flows. No actual output needs to be produced, but time must advance for clocks to be observable.
π°οΈ Understanding clocks
Clocks control how time advances for sources. The clock graph displays:
- Parent/child relationships between clocks
- Each clockβs internal time and tick count
- Which sources are active on each clock
The internal time is especially useful for reasoning about operators
such as crossfade and stretch, which may
accelerate their clock relative to real time to prepare transitions
before they play. When a clock or source is marked with
self_sync = true, it can not be
accelerated β an important detail when reasoning about timing and
transitions.
π₯ Active sources
The clock graph also highlights active sources. Active sources are always animated by their clock even if they are not currently producing output.
This includes for example:
input.harbor, which must actively pull data from a remote Icecast stream when connectedinput.ffmpeg, which may be need to be configured to be active or passive depending on whether itβs reading from a file or a remote URL
Understanding which sources are active helps explain background activity you might otherwise miss.
π Understanding source graphs
The source graph shows how sources are connected, and β crucially β how they are animated:
- The graph is animated from top to bottom
- The top is usually an output, but it can also be a regular source
that is animated by an external source such as a
crossfade.
For example, a crossfade or stretch
operator may accelerate its clock and animate its inputs faster than
real time to prepare transitions or resampling.
This top-to-bottom animation direction makes it easier to see:
- Which source is driving evaluation
- How transitions or clock acceleration affect lower sources
π» Using the CLI
You can generate these graphs directly from the command line:
liquidsoap --display-clocks script.liq
liquidsoap --display-sources script.liqWhen these options are used:
- The script is started
- It runs briefly so clock and source information can be gathered
- The script is stopped
- The requested graph is displayed
Adjust run duration with:
--dump-delay <seconds>This offers a quick, non-intrusive way to inspect a script.
π Using the server / telnet interface
If your script is already running with the server enabled, you can request graphs interactively:
clocks.dumpβ display the clock graphclocks.dump_sourcesβ display the source graph
Great for live inspection without restarting.
π Using the scripting API
Graphs can also be accessed programmatically:
clock.dump()β dump the clock graphclock.dump_all_sources()β dump the source graph
This makes it easy to integrate visualization into custom tooling or monitoring.
π Examples
Here are example outputs showing typical clock and source graphs:
π Clock graph
Β· output.icecast (ticks: 3, time: 0.06s, self_sync: false)
βββ outputs: output.icecast [output.icecast], output.file [output.file]
βββ active sources:
βββ passive sources: audio.producer [ffmpeg_encode_audio],
β ffmpeg_encode_audio [output.icecast, output.file]
βββ audio.producer (ticks: 6, time: 0.12s, self_sync: false)
βββ outputs: audio.consumer [audio.producer, audio.consumer]
βββ active sources:
βββ passive sources: safe_blank.1 [mksafe.1], safe_blank [mksafe],
β cross [track_metadata_deduplicate, metadata_deduplicate],
β track_metadata_deduplicate [metadata_deduplicate],
β metadata_deduplicate [mksafe, insert_initial_track_mark.6],
β mksafe [metadata_map.2, metadata_map.3],
β metadata_map.2 [metadata_map.3],
β metadata_map.3 [mksafe.1, insert_initial_track_mark.1],
β mksafe.1 [audio.consumer], insert_initial_track_mark [],
β insert_initial_track_mark.1 [mksafe.1],
β insert_initial_track_mark.6 [mksafe]
βββ cross (ticks: 132, time: 2.64s, self_sync: false)
βββ outputs:
βββ active sources:
βββ passive sources: source [switch, switch.1],
audio [switch, switch.1, insert_initial_track_mark.2],
switch [switch.1, insert_initial_track_mark.3],
switch.1 [switch.2, insert_initial_track_mark.4],
request_queue [switch.2],
switch.2 [switch.3, insert_initial_track_mark.5],
request_queue_1 [switch.3], switch.3 [metadata_map, metadata_map.1],
metadata_map [metadata_map.1],
metadata_map.1 [track_amplify, amplify], track_amplify [amplify],
amplify [cross, cross], insert_initial_track_mark.2 [switch],
insert_initial_track_mark.3 [switch.1],
insert_initial_track_mark.4 [switch.2],
insert_initial_track_mark.5 [switch.3], cross.eos_buffer [cross]
π Source graph
Clock output.icecast:
Outputs:
Β· output.icecast [output]
βββ ffmpeg_encode_audio [passive]
βββ audio.producer [passive]
Β· output.file [output]
βββ ffmpeg_encode_audio [passive] (*)
Clock audio.producer (controlled by output.icecast):
Outputs:
Β· audio.producer [external activation]
βββ audio.consumer [output]
βββ mksafe.1 [passive]
βββ safe_blank.1 [passive]
βββ metadata_map.3 [passive]
β βββ mksafe [passive]
β β βββ safe_blank [passive]
β β βββ metadata_deduplicate [passive]
β β β βββ cross [passive]
β β β βββ track_metadata_deduplicate [passive]
β β β βββ cross [passive] (*)
β β βββ insert_initial_track_mark [passive]
β β βββ safe_blank [passive] (*)
β βββ metadata_map.2 [passive]
β βββ mksafe [passive] (*)
βββ insert_initial_track_mark.1 [passive]
βββ metadata_map.3 [passive] (*)
These outputs make it easy to see how clocks relate, which sources are active, and how evaluation flows from top (outputs) to bottom (inputs).
β When to use this feature
Clock and source graphs are particularly helpful when:
- βοΈ Designing or refactoring a script
- π Debugging timing, synchronization, or activation issues
- π§ Understanding
self_syncand clock acceleration - π’ Explaining how a script works to others
By making time, structure, and activation visible, these graphs provide a new way to reason about Liquidsoap scripts β beyond reading code alone.