NoSignal Documentation
Complete usage manual for operators, integrators, and system administrators running NoSignal in production broadcast and IPTV environments.
Introduction
NoSignal is a pure-Rust Linux application for MPEG-TS stream processing. It ingests transport streams from multiple sources, maintains channel health with automatic failover, optionally transforms the stream (PID remapping, PSI rewriting, CBR pacing), and delivers to multiple outputs simultaneously.
Key characteristics:
- Single binary — no C library dependencies, no runtime installations
- Embedded web UI — operator console baked into the binary, served on the API port
- Embedded data store — uses redb (pure Rust key-value store), no external database
- Multi-input failover — automatic switchover with anti-flap, probe-based revert
- Stream conditioning — VBR passthrough or CBR null-packet padding, PID remapping, SI rewriting
- EPG support — EIT extraction from inputs and XMLTV import, standalone SPTS multiplex output
- Prometheus telemetry — per-channel bitrate, CC errors, PCR jitter with historical charts
- External API — full REST API with API key authentication for third-party integrations
Key Concepts
Before diving in, here are the core concepts used throughout this manual:
| Concept | Description |
|---|---|
| Channel | A logical stream unit with one or more inputs, zero or more outputs, optional failover and pipeline configuration. Each channel runs independently. |
| Input | A source of MPEG-TS data. Each input has a priority (0 = primary). Supported types: UDP multicast, HTTP TS, HLS, SRT. |
| Output | A destination for the processed stream. Same transport types as inputs. All outputs receive identical post-pipeline data. |
| Pipeline | Optional per-channel processing: PID remapping via slot configuration, CBR pacing, SI rewriting, time table injection. |
| Failover | Automatic switching from a failed input to the next healthy backup, with configurable thresholds and anti-flap protection. |
| Slug | URL-friendly identifier auto-generated from the channel name (e.g., "BBC One HD" becomes bbc-one-hd). Used in API paths. |
Installation
Prerequisites
- Linux server (Ubuntu 20.04+ or similar)
- ffmpeg (for offline banner image-to-MPEG-TS conversion)
- ImageMagick (for offline banner image resizing)
- nginx with Let's Encrypt (for TLS reverse proxy, recommended)
Download
Download the latest binary from download.nosignal.ro. The binary is a statically-linked executable that runs on any Linux system.
wget https://download.nosignal.ro/nosignal
chmod +x nosignal
Fresh Install
The binary includes a built-in installer that creates everything needed for a production deployment:
sudo ./nosignal --install-service
This command:
- Creates the
nosignalsystem user - Sets up
/srv/nosignal/with correct permissions - Generates a JWT secret at
/srv/nosignal/.env - Installs a hardened systemd service unit
- Sets up daily backup cron job
- Creates two fixed accounts —
admin(full access) anduser(read-only viewer) — each with a randomly generated 16-character password
Then start the service:
sudo systemctl start nosignal
sudo systemctl enable nosignal
Directory Layout
/srv/nosignal/
├── nosignal # runtime binary
├── nosignal.redb # data store
├── .env # runtime secrets (JWT secret, tuning)
├── backups/ # automatic redb backups (max 10 rotating)
├── credentials.txt # initial admin + user passwords (delete after first login)
└── slate/ # custom offline banner images
Systemd Service
The service runs as the unprivileged nosignal user with hardened security settings:
ProtectSystem=strict— read-only filesystem except/srv/nosignalCAP_NET_RAWandCAP_NET_ADMIN— for UDP multicast socket operations- Automatic restart on failure with 5-second delay
- Logs to journald
# Check status
sudo systemctl status nosignal
# View logs
sudo journalctl -u nosignal -f
# Restart after update
sudo systemctl restart nosignal
Nginx Reverse Proxy
NoSignal binds to localhost only (default 127.0.0.1:8080). Use nginx for TLS termination:
server {
listen 443 ssl http2;
server_name nosignal.example.com;
ssl_certificate /etc/letsencrypt/live/nosignal.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/nosignal.example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# SSE events — disable buffering
location ~ ^/api/v1/channels/.*/events$ {
proxy_pass http://127.0.0.1:8080;
proxy_buffering off;
proxy_cache off;
proxy_set_header Connection '';
proxy_http_version 1.1;
chunked_transfer_encoding off;
}
# Restrict Prometheus metrics to localhost
location = /metrics {
allow 127.0.0.1;
deny all;
proxy_pass http://127.0.0.1:8080;
}
}
Firewall
Required network access (nftables example):
# Allow nginx (HTTP/HTTPS)
nft add rule inet filter input tcp dport { 80, 443 } accept
# Allow multicast UDP (adjust port ranges to your setup)
nft add rule inet filter input ip daddr 239.0.0.0/8 udp dport 1000-65535 accept
First Login
On first startup, NoSignal creates two fixed accounts — admin (full access) and user (read-only viewer) — each with a randomly generated 16-character password. Both passwords are written to /srv/nosignal/credentials.txt (mode 0600) and printed to the journal:
sudo cat /srv/nosignal/credentials.txt
Open the web UI in your browser (e.g., https://nosignal.example.com) and log in with username admin and the generated password.
/srv/nosignal/credentials.txt.User Roles
NoSignal ships with exactly two fixed accounts — this is the complete user model. There is no user CRUD; the only way to alter the user account is the admin-only password reset.
| Account | Role | Permissions |
|---|---|---|
admin | Full access | Create/modify/delete channels, manage license, API keys, config backup/restore, reset the user password |
user | Read-only viewer | See all channel status, telemetry, and logs — cannot make changes |
Dashboard
The dashboard is the landing page after login. It provides an at-a-glance view of your system health:
- Channel counts — total channels, running, stopped, errored
- License status — current license state and expiry
- Alerts — offline channels, offline always-on inputs, and recent failover events
- System health — quick access to performance and resource usage
Channel Management
Channels are the core unit in NoSignal. Each channel represents a single MPEG-TS service with its own inputs, outputs, failover, and pipeline configuration.
Creating a Channel
Navigate to Channels in the sidebar and click New Channel. Fill in:
- Name — a display name (e.g., "BBC One HD"). A URL slug is auto-generated.
- Description — optional free-text note for your team.
- Inputs — add one or more inputs with priorities (0 = primary). See Input Types below.
- Outputs — add one or more outputs. See Output Types below.
- Failover — configure failover behavior (thresholds, hold times, auto-revert). See Failover section.
- Pipeline — optional stream processing (CBR, slots, SI overrides). See Pipeline section.
Click Save to create the channel. If enabled, it starts automatically.
Input Types
UDP Multicast
Standard MPEG-TS over UDP multicast, the most common delivery method in IPTV headends.
| Field | Example | Description |
|---|---|---|
| Address | udp://[email protected]:1234 | Multicast group and port. Prefix with interface@ to bind to a specific NIC. |
| PNR | 1 | Optional program number to extract a single service from an MPTS. |
HTTP Transport Stream
Pull a persistent HTTP stream. Useful for remote contribution feeds or HTTP-based encoders.
| Field | Example | Description |
|---|---|---|
| Address | http://source.example.com:8080/stream | Full HTTP or HTTPS URL. |
SRT (Secure Reliable Transport)
Low-latency, encrypted transport for contribution over the public internet.
| Field | Example | Description |
|---|---|---|
| Address | srt://source.example.com:9000 | SRT endpoint address. |
| Mode | caller / listener | Caller connects out; listener waits for connections. |
| Latency | 120 ms | SRT latency buffer. Higher values tolerate more jitter. |
| Passphrase | (optional) | AES encryption passphrase. Both ends must match. |
HLS (HTTP Live Streaming)
Pull an HLS playlist and reconstruct a live MPEG-TS stream. Useful for ingesting from OTT sources or CDN-fronted feeds that only publish HLS.
| Field | Example | Description |
|---|---|---|
| Address | https://cdn.example.com/live/bbc/master.m3u8 | Master or media playlist URL. HTTPS supported. |
NoSignal follows the latest rendition of the playlist and splices TS segments into a continuous stream with monotonic PCR. Suitable as an input for full-pipeline processing (failover, CBR pacing, PSI rewrite, and any output type).
Common Input Options
These options apply to all input types:
| Field | Description |
|---|---|
| Priority | Integer (0 = primary, higher = lower priority). Determines failover order. |
| Source Name | Optional friendly label (e.g., "Telekom Primary", "SRT Backup"). Shown in the UI and event log for easier identification. |
| Always Active | When enabled, this input runs as an auxiliary feed even when not the active input. Useful for monitoring a backup source's telemetry (bitrate, CC errors) continuously without waiting for a probe. |
Channel Logos
Each channel can have a custom logo image. Upload a PNG or JPG via the channel detail page. Logos appear in the channel list, explorer, and overview pages for quick visual identification.
Output Types
UDP Multicast
Standard multicast output for local network distribution.
| Field | Example | Description |
|---|---|---|
| Address | 239.2.1.1:5000 | Multicast group and port. |
| Interface | eth0 | Optional: bind to a specific NIC. |
| TTL | 16 | Multicast time-to-live (hop count). |
HTTP Transport Stream
HTTP server that clients can connect to and pull a live TS stream.
| Field | Example | Description |
|---|---|---|
| Address | 0.0.0.0:8085 | Bind address and port. |
SRT Output
SRT output for reliable delivery over lossy networks.
| Field | Example | Description |
|---|---|---|
| Address | 0.0.0.0:9100 | Bind address for listener mode, or target for caller. |
| Mode | listener / caller | Listener waits for connections; caller connects out. |
| Latency | 200 ms | SRT latency buffer. |
| Passphrase | (optional) | AES encryption passphrase. |
HLS is not in this list. Starting with v0.8.56, HLS is a top-level origin subsystem rather than a per-channel output type — see HLS Origin below.
Channel Operations
- Start / Stop — click the play/stop button on the channel list or detail page. Starting begins ingesting from the highest-priority available input.
- Edit — modify any channel configuration. Running channels are automatically restarted when saved — no manual restart needed.
- Delete — stops the channel and removes it along with all inputs, outputs, and configuration.
- Bulk actions — select multiple channels for batch start/stop from the channels list.
Failover
Each channel can have multiple inputs ordered by priority. NoSignal automatically switches between inputs based on health, with configurable thresholds and protection against oscillation.
Failover Triggers
Silence (No Data)
If no TS packets arrive for source_timeout_ms (default 5000 ms), the input is marked as down and failover begins.
Sustained CC Errors
If the continuity counter error rate exceeds cc_error_rate errors/sec and remains above that threshold for the full cc_error_window_ms window (default 10 s), failover is triggered. Brief spikes that drop back below threshold within the window do not trigger failover.
Fast Failover
Background probing continuously checks backup health. If the next backup has already been confirmed healthy by a recent probe, the switch is near-instant. If no cached-healthy backup exists, NoSignal probes each backup in priority order sequentially.
Hold Time
After any switch, the channel stays on the new input for at least hold_time_ms (default 30 s) before another switch is allowed. This prevents rapid oscillation.
Failback (Auto-Revert)
When auto_revert is enabled (default), NoSignal automatically returns to a higher-priority input when it recovers. Three gates must be passed:
- Probe gate — the higher-priority input must pass
revert_after_probes(default 3) consecutive successful background probes. - Quality gate — a deep probe receives data for ~3 seconds and checks CC error rate. If errors are above threshold, the failback is deferred.
- Minimum delay — failback will not happen before
revert_delay_ms(default 60 s) has elapsed since the original failover.
Anti-Flap Protection
Input Lockout
If a specific input fails 3 or more times within 10 minutes, it is locked out for 30 minutes. During lockout the input is skipped during failover, but background probes continue. Lockout clears automatically after 30 minutes or with a manual channel restart.
Escalating Hold Time
If more than 2 failovers occur within 5 minutes, the hold time automatically doubles on each subsequent switch, up to a maximum of 10 minutes. It resets after 10 minutes of stability.
Failover Configuration Reference
| Field | Default | Description |
|---|---|---|
source_timeout_ms | 5000 | Silence duration before triggering failover |
cc_error_rate | 10 | CC errors/sec threshold |
cc_error_window_ms | 10000 | Duration errors must sustain above threshold |
hold_time_ms | 30000 | Minimum time on any input after a switch |
revert_delay_ms | 60000 | Minimum floor before failback can occur |
auto_revert | true | Automatically switch back to higher-priority input |
revert_after_probes | 3 | Consecutive healthy probes needed before failback |
probe_interval_ms | 60000 | Background probe frequency (base, ±20% jitter) |
probe_timeout_ms | 10000 | How long a probe waits for data |
no_signal_slate | false | Show offline banner when all inputs are exhausted |
HLS Origin
NoSignal acts as an HLS origin: each enabled channel publishes a media playlist plus rotating .ts segments, all served by a small HTTP server that binds once globally (--hls-bind, default 127.0.0.1:8090). Manage HLS from the HLS → Origin page in the operator UI.
HLS is not a per-channel output — it's a top-level subsystem with its own toggle. Toggling it on or off is hot: the HLS subscriber attaches to (or detaches from) the channel's broadcast bus without restarting the pipeline.
Enabling HLS for a channel
Open the HLS → Origin page, find the channel and flip its toggle. The page shows the live state of every channel side-by-side with its HLS toggle, playlist URL, master URL, and current output bitrate.
- Toggling on a running channel: subscriber attaches immediately; the first segment lands after ~6 seconds.
- Toggling off: subscriber is cancelled and the segment directory is wiped to keep disk clean.
- Channel start/stop: HLS state is preserved. A toggled-on channel re-attaches its HLS subscriber automatically on every (re)start.
- Bulk action: select multiple rows and use the bulk toggle to enable or disable HLS across many channels at once.
HLS publishing is opt-in. Channels never pay HLS CPU or disk cost unless explicitly enabled.
Endpoints
The origin server exposes five endpoint families. All return Access-Control-Allow-Origin: *.
| Endpoint | Purpose |
|---|---|
GET /hls/{slug}/index.m3u8 | Media playlist for one channel. Updates as new segments are cut. |
GET /hls/{slug}/seg<NNNNNN>.ts | Individual MPEG-TS segment, ~6 seconds, immutable. |
GET /hls/{slug}/master.m3u8 | Single-variant master playlist. Required by some strict clients. |
GET /playlist.m3u | IPTV bouquet listing every enabled, running, HLS-enabled channel. Served as audio/x-mpegurl so VLC and IPTV apps treat it as a regular playlist (not an HLS multivariant). Carries tvg-id / tvg-name / tvg-logo / group-title attributes and a url-tvg pointer to /epg.xml. /index.m3u8 is kept as an alias. |
GET /epg.xml | XMLTV export for IPTV-client EPG. Channel IDs match the tvg-id in /playlist.m3u (= channel slug). Programmes come from the imported XMLTV catalogue for epg_mode=xmltv channels and from the per-channel live EIT scanner for epg_mode=input channels. Cached for 60 s. |
Segment rotation is automatic. The playlist carries the last PLAYLIST_DEPTH (10) segments; the segmenter keeps an extra GRACE_SEGMENTS (2) on disk for in-flight downloads. Disk usage per channel is bounded at 12 segments while HLS is running.
Per-channel master playlist
The master playlist at /hls/{slug}/master.m3u8 declares one variant pointing at index.m3u8, with a BANDWIDTH attribute derived from the running channel's measured output bitrate. Strict HLS clients that require a multivariant playlist (rather than a bare media playlist) should hit the master URL.
The master is generated on demand from runtime state — there is no separate persisted file. If HLS is disabled for the slug, the master endpoint returns 404.
Origin channel index
Loading http://<hls-bind>/playlist.m3u in VLC, an IPTV app, or any M3U-aware player yields the full bouquet — every channel that is currently HLS-enabled and running, with #EXTINF entries pointing at each channel's media playlist. The link host adapts to the inbound Host header so the bouquet keeps working unchanged behind nginx.
The bouquet is served with Content-Type: audio/x-mpegurl (generic M3U) rather than application/vnd.apple.mpegurl (HLS). The HLS content type would push players into the HLS demuxer, which then mis-parses each per-channel playlist URL as a TS segment. /index.m3u8 is kept as an alias for backwards compatibility with v0.8.56 docs.
The HLS Origin page in the app shows the bouquet URL prominently with a copy-to-clipboard button — share it with downstream operators to give them a single-URL entry point to all channels.
IPTV EPG (XMLTV)
The bouquet pairs with an XMLTV export at /epg.xml on the same host:port. The playlist's #EXTM3U header declares url-tvg="http://<host>/epg.xml", which most modern IPTV clients (Tivimate, IPTV Smarters, Kodi, TVHeadend) auto-discover — so loading just the bouquet gives the client both the channel list and the EPG.
tvg-id in the M3U equals <channel id="..."> in the XMLTV, both set to the channel's slug. No per-client mapping step is needed.
Programme data sources, per channel:
epg_mode = xmltvchannels: full schedule from the imported XMLTV catalogue (typically 7 days).epg_mode = inputchannels: present + following + whatever schedule sections the upstream EIT carried (usually 1–2 days).epg_mode = nonechannels: appear in the channel list but with no programme entries (clients show a blank EPG row).
The response is cached for 60 seconds (Cache-Control: public, max-age=60) so high-volume IPTV-client polls don't rebuild the document every request.
Stream Processing Pipeline
The pipeline is an optional per-channel processing stage between input and output. When no pipeline is configured, packets pass through unmodified (VBR passthrough).
Output Modes
VBR Passthrough (Default)
Packets are forwarded as-is. The output bitrate follows the input bitrate. This is the simplest mode and introduces no additional latency.
CBR (Constant Bitrate)
Set target_bitrate_kbps to enable CBR output. NoSignal inserts null packets (PID 0x1FFF) to pad the stream to the target bitrate. The P-controller pacing ensures smooth, DVB-compliant output timing.
On-Demand Mode
When enabled, the channel defers input activation until a consumer connects to one of its unicast outputs (HTTP TS or SRT listener). Output ports bind immediately so clients can connect at any time — only the input and processing pipeline are deferred. When the last consumer disconnects, a configurable grace period (default 30 seconds, NOSIGNAL_ON_DEMAND_GRACE_S) elapses before the input is stopped. The channel shows Standby status while idle.
On-demand works with channels that have no outputs (telemetry-only) or only unicast outputs (HTTP TS, SRT listener). If any UDP multicast or SRT caller output is configured, on-demand is ignored and the channel runs normally. Enabling the HLS origin for a channel is independent of on-demand — when consumers wake the channel, the HLS subscriber attaches and starts producing segments. Enable on-demand in the Add Channel form or the channel edit form under On-Demand Mode.
While in standby, the channel generates no telemetry at all — no input bitrate, no CC error counters, no PCR metrics, no Prometheus samples. Telemetry resumes the moment a consumer connects and the input activates.
Preview, Analyse, and Extended Analysis all work with standby channels — opening any of them temporarily wakes the input. When closed, the 30-second grace period starts and the channel returns to standby if no other consumers are connected. When no consumers are connected, the output pipeline skips serialization and bus publishing entirely (zero CPU overhead).
Slot Configuration (PID Remapping)
Slots define semantic PID mappings — you specify what you want (e.g., "the first video stream") and NoSignal resolves it against the actual input PMT at runtime.
Slot Types
| Type | Description |
|---|---|
video | Video elementary stream (H.264, H.265, MPEG-2, etc.) |
audio | Audio elementary stream (AAC, AC-3, MP2, etc.) |
subtitle | DVB subtitles or teletext |
data | Data broadcast or application streams |
scte35 | SCTE-35 ad insertion cue messages |
Match Strategies
| Strategy | Description |
|---|---|
first | First stream of the matching category (default) |
by_language | Match by ISO 639 language code (e.g., eng, fra) |
by_stream_type | Match by MPEG stream type byte (e.g., 0x1B for H.264) |
by_pid | Match a specific input PID number |
Each slot also specifies an output_pid (the PID number in the output stream), and can be marked optional (if the match fails, the slot is simply omitted rather than causing an error).
Service Information Overrides
Override the service metadata in the output stream:
| Field | Description |
|---|---|
override_pnr | Change the output program number (service ID) |
override_tsid | Change the transport stream ID |
service_provider | Override the service provider name in SDT |
service_name | Override the service name in SDT |
inject_time_tables | Inject TDT/TOT from system UTC on PID 0x14 |
pmt_guard_max_ms | Safety PMT re-inject interval if source goes silent (100–400 ms) |
Electronic Program Guide (EPG)
The EPG subsystem ingests programme schedules from two sources — XMLTV feeds and live EIT scraped from each channel's input — and re-emits a unified guide on a standalone DVB SPTS multiplex that downstream SI-injection headends (Teleste Luminato and similar) bind into the QAM output. The same data also powers the /epg.xml export consumed by IPTV clients (see IPTV EPG (XMLTV)).
Open the EPG sidebar entry. Six tabs run top-to-bottom in a typical workflow:
| Tab | Purpose |
|---|---|
| Active Input | Live EIT scraped from each channel right now — present + following + 7-day schedule sections, grouped by channel. Read-only. |
| XMLTV | Browse the entire imported XMLTV catalogue (every channel + programme). Filter by locale. Channel names are non-clickable here — these rows are XMLTV entries, not platform channels. |
| XMLTV Sources | CRUD for upstream XMLTV feeds. RO + HU iptv-epg.org are seeded on first boot. Each source carries an optional locale tag. |
| EPG Mapper | Per-channel EPG configuration — EPG mode, language preference, XMLTV mapping, SID/TSID editor. The control surface for everything below. |
| SPTS Output | Standalone DVB SPTS multiplex carrying the consolidated EIT. Bind the multicast targets here. |
| Scanning | Tune the background EIT sweep cadence + parallelism. |
EPG modes
Each channel picks one of three modes (column EPG Mode in the Mapper). The mode decides what — if anything — that channel contributes to the SPTS multiplex and to /epg.xml.
| Mode | Behaviour |
|---|---|
none | Not in EPG. The channel still streams, but no EIT carries its events. It appears in /playlist.m3u with an empty EPG row. |
input | Use active input. The per-channel scanner reads EIT from the upstream feed, filters to this channel's effective service_id, and re-emits those sections. Best for upstreams that already publish EIT (DVB, Romanian DTT, etc.). |
xmltv | Use XMLTV. NoSignal synthesises EIT sections from the imported XMLTV programme list, keyed to this channel's service_id. Best for channels whose upstream carries no EIT (HLS, HTTP, SRT pull-from-CDN). |
The full carousel is delivered only through the SPTS multiplex — per-channel TS outputs never carry the consolidated EIT. /epg.xml re-uses the same data so IPTV clients get the same view that downstream QAMs do.
XMLTV sources
The XMLTV Sources tab lists each configured upstream feed: an ID, the URL, a locale tag, the cron schedule, last-fetch timestamp, event count, and HTTP status. Click Add Source to add another.
- URL — plain XML or gzipped
.xml.gz. Most community feeds (iptv-epg.org, iptv-org/epg) publish gzip; both are detected from the gzip magic byte. - Locale — short language code (e.g.
ro,hu,en). Used by the Mapper's Map all channels action to restrict auto-match candidates to feeds in the language a given channel prefers. Optional — leaving it empty makes the source eligible for every channel. - Schedule — currently informational. The fetcher always runs once daily at 06:00 local time; the cron field is forward-compatibility for per-source schedules.
Fresh installs are seeded with two default rows: ro-iptv-epg (epg-ro.xml.gz) and hu-iptv-epg (epg-hu.xml.gz) from iptv-epg.org. Delete or replace them if your region uses a different feed; iptv-org/epg's per-country files are a common fallback.
Manual fetch. The Fetch now button (top right of both the XMLTV and XMLTV Sources tabs) wakes the fetcher immediately and polls the import status for up to 60 s. Status badges flip to ok on success or carry the error text on failure.
XMLTV browse
The XMLTV tab is a read-only browser over the entire imported catalogue — every channel from every configured source, regardless of whether it's mapped to a platform channel. Use it to confirm a fetch landed, to look up a specific xmltv_id before pasting it into the Mapper, or to verify a feed's coverage for a given day.
- The Table view is a paginated list — expand a row to see that channel's full schedule.
- The Grid view is the 24-hour timeline. Programme tiles tied to a mapped platform channel navigate to the channel detail's EPG tab; unmapped tiles are read-only (the tooltip still shows the programme details).
- Channel names are intentionally non-clickable here — XMLTV channels are catalogue entries, not platform channels, and clicking them used to land on a 404. Use the Mapper to bind one to a platform channel.
- The Locale dropdown appears once you have sources tagged in more than one language; filtering shrinks both the browse list and the background fetch.
EPG Mapper — per-channel configuration
The Mapper is where most operators spend their EPG time. It shows every configured platform channel on one screen with four editable columns and two bulk-action buttons in the header. Every change applies live — the affected channel hot-reloads its EPG configuration; no manual restart is ever required.
Columns
| Column | What it does |
|---|---|
| Channel | Channel name. The grey badges underneath are SID:<n> (effective service_id) and TSID:<n> (transport_stream_id the EIT will carry). Click either badge to edit it inline. A yellow ⚠ TSID means it's inherited from the live input PAT — set an override to match the QAM where this channel lives downstream. |
| EPG Mode | The three-mode dropdown above (none / input / xmltv). A yellow warning appears when the mode is xmltv but no mapping is set — the channel would emit nothing without one. |
| Preferred XMLTV Lang | Per-channel hint used only by the Map all channels button. With ro set, the auto-matcher only considers XMLTV sources tagged ro for that channel. Does not restrict what you can pick manually — the dropdown still shows every catalogue entry. |
| XMLTV mapping | The XMLTV channel to use when EPG Mode is xmltv. Type to search by display name or xmltv_id. (auto-match) defers to the name-normaliser at every run; an explicit pick wins over auto. The greyed placeholder shows what auto would pick — a ~ prefix means a fuzzy (sub-1.0) score. |
The two bulk-action buttons
Map all channels. Iterates every channel and runs the auto-matcher against the XMLTV catalogue. For each channel:
- If Preferred XMLTV Lang is set, candidates are restricted to sources tagged with that locale.
- Matching ignores common cosmetic noise — leading/trailing locale codes (
RO -,HU), trailing format suffixes (HD,FHD,4K,HEVC,DVB), the trailing wordTV, and all non-alphanumerics. SoRO - TVR 1 HDmatchesTVR 1;AMC ROmatchesRO - AMC;Agro TV ROmatchesAgro. Names with no separator are protected —rotornever collapses totor. - A unique exact match (score 1.0) wins unambiguously. A prefix match wins only if score ≥ 0.7 AND no other candidate also scores ≥ 0.7 (so
HBOvsHBO 2+HBO 3is rejected as ambiguous). - When a match is found and the channel is currently
none, its EPG Mode flips toxmltvso it joins the carousel automatically. Channels already oninputorxmltvkeep their chosen mode; only the mapping is updated. - Typed
CONFIRMgate — bulk updates can churn many channels and the operator needs to acknowledge before they fire.
Fix output service IDs. Resolves duplicate or missing SIDs across the platform. The button counter shows how many channels need attention; the yellow banner above the table lists which SIDs are colliding.
- The oldest channel in each collision group keeps its SID. Every newer collider — and every channel with no resolvable SID — is assigned the next free value.
- This applies regardless of EPG mode. A channel with
epg_mode=nonestill needs a unique SID so its PAT/PMT don't clash with another channel's on the same QAM. - Running channels are restarted to publish the new PAT/PMT.
The (ONID, TSID, SID) triplet
Receivers bind EIT events to services by matching the triplet (original_network_id, transport_stream_id, service_id) against the QAM's PAT/SDT. If the EIT we emit carries the wrong ONID or TSID, the events arrive on the wire but the STB silently drops them — they don't match any service. So:
- ONID is set per-multiplex on the SPTS Output tab (
Network IDfield). It must equal the ONID the downstream headend advertises in its SDT. The factory default1is rarely correct in real deployments. - TSID is set per-channel from the Mapper. Yellow ⚠ means it's inheriting from the live input PAT — fine for a passthrough, dangerous for a downstream QAM that asserts its own ts_id. Click and type the ts_id of the QAM where that channel will land. Empty input clears the override and reverts to the live PAT.
- SID is set per-channel. Click the SID badge to type a new value, or use Fix output service IDs to bulk-resolve collisions.
How the effective SID is computed
For every channel, NoSignal walks this chain to pick the SID the EIT will reference:
override_pnrfrom the slot config (typed in the SID badge).- The
program_numberfrom a single-service input PAT carve. - The PAT of the running channel as observed by the manager.
If none yield a value, the channel is skipped in the EPG carousel with a warning in the log — emitting EIT with a default SID would corrupt the downstream multiplex. Set an explicit override_pnr from the Mapper to fix this.
SPTS output
The standalone EPG SPTS is a small DVB-spec transport stream that carries the consolidated EIT for every participating channel, plus optional SDT-other / PAT / PMT framing. It binds one or more multicast targets at 239.255.1.100:5100 by default and runs at a configurable minimum bitrate (200 kbps default — enough for ~60 channels at default cadences; the stream pads with NULL packets below this floor so receivers stay locked even on a quiet catalogue).
Output mode picks the wire shape:
| Mode | What goes on the wire | Use when |
|---|---|---|
raw_eit_pid | Pure EIT on PID 18 + NULL padding. No PAT, no SDT, no PMT. | You feed an SI-injection multiplexer (Teleste Luminato, cherryEpg-compatible chains) that re-emits your EIT into its own QAM. Cleanest possible input. |
full_dvb_ts | PAT + PMT + SDT-actual + per-channel SDT-other + EIT. | You feed a receiver that auto-detects the input against a full multiplex (binds EIT by service triplet rather than ingesting raw PID 18). |
Cadences — pf_cycle_s (present/following repetition, default 2 s) and sched_cycle_s (full schedule repetition, default 30 s) — control how often each event window is re-emitted. The Sizing card under the form estimates the wire rate at the current cadences and warns when it exceeds the floor (so the operator can raise the floor or relax cadences).
The SDT advertises a single service per multiplex — name (EPG) and provider (NoSignal) are configurable. Per-channel events ride inside as EIT, referenced by service_id.
Scanning cadence
The background EIT sweep runs on every channel on a fixed schedule (default every 6 hours, 60 s after daemon start). Each sweep refreshes the per-channel monitor's EIT snapshot — the data that feeds the Active Input tab, the epg_mode=input contribution to the SPTS carousel, and the input branch of /epg.xml.
- Sweep Interval (hours) — 1–72, default 6. Higher = less load, more stale EIT. Lower = fresher EIT, more on-demand wakes (sweep scans every channel including standby).
- Parallel Channels — 1–64, default 10. Cap on concurrent per-channel scans inside one sweep. Also the default for the manual Scan All button on the EPG page.
Manual Scan All (top-right of the Active Input tab) resets the sweep timer to now + interval. Useful right after editing channel inputs to confirm the new feed publishes valid EIT.
Monitoring & Telemetry
NoSignal provides extensive real-time and historical monitoring for every channel.
Metrics
Per-channel telemetry includes:
Per-Input Metrics
| Metric | Description |
|---|---|
bitrate_bps | Current ingress bitrate |
cc_errors_per_sec | Continuity counter errors per second |
pcr_bitrate_bps | Bitrate derived from PCR deltas (sanity cross-check) |
pcr_jitter_us | PCR jitter in microseconds |
pmt_cadence_mean_ms | Mean interval between PMT sections |
pmt_cadence_max_ms | Maximum observed PMT interval (DVB spec: ≤500 ms) |
psi_changes_total | Total PSI version changes since start |
Post-Pipeline Output Metrics
| Metric | Description |
|---|---|
output_bitrate_bps | Egress bitrate after pipeline processing |
output_cc_errors_per_sec | CC errors on the emitted stream (should be 0) |
output_pcr_jitter_us | PCR jitter on the output stream |
Channel States
| State | Meaning |
|---|---|
stopped | Channel is not running |
starting | Channel is initializing |
running | Normal operation on primary or backup input |
degraded | Running on a backup input (failover active) |
error | All inputs failed |
slate | Showing offline banner (all inputs exhausted, slate enabled) |
standby | On-demand mode: waiting for a consumer to connect before activating input |
Live Preview
The channel detail page includes a live stream preview. This uses server-side FFmpeg transcoding to provide a browser-playable preview of the MPEG-TS stream. Both input (unprocessed) and output (post-pipeline) previews are available.
Event Log
Every channel maintains a structured event log (up to 200 events per channel in memory). Event types include:
| Event | Severity | Description |
|---|---|---|
started | info | Channel started |
stopped | info | Channel stopped |
failover | warning | Switched to backup input |
revert | info | Returned to higher-priority input |
cc_error | warning | Continuity counter errors detected |
no_data | warning | Input silence detected |
pid_change | warning | PID set changed in the input stream |
pat_change | info | PAT table version change |
pmt_change | info | PMT table version change |
sdt_change | info | SDT table version change |
probe | info | Background probe result |
error | error | Channel error (lockout, socket failure, etc.) |
Events with identical type and message are merged — a count field shows how many times the event repeated.
Prometheus Integration
NoSignal exposes a /metrics endpoint in Prometheus exposition format. Prometheus scrapes this endpoint and stores historical data with 30-day retention. The web UI charts query Prometheus through the NoSignal API proxy.
Setup
# Install Prometheus
sudo apt-get install -y prometheus
# Use the provided config template
sudo cp /opt/nosignal/docs/prometheus.yml /etc/prometheus/prometheus.yml
# Set 30-day retention and localhost binding
# In /etc/default/prometheus:
ARGS="--web.listen-address=127.0.0.1:9090 --storage.tsdb.retention=30d"
# Restart
sudo systemctl restart prometheus
sudo systemctl enable prometheus
scrape_interval in prometheus.yml must match NOSIGNAL_METRICS_INTERVAL_S in .env (default: 60 seconds). If you change one, update the other.Prometheus Metric Families
| Metric | Labels | Description |
|---|---|---|
nosignal_channel_input_bitrate_bps | channel, input | Per-input bitrate |
nosignal_channel_input_cc_errors_per_sec | channel, input | Per-input CC errors/sec |
nosignal_channel_input_pcr_jitter_us | channel, input | Per-input PCR jitter |
nosignal_channel_output_bitrate_aggregate_bps | channel | Post-pipeline output bitrate |
nosignal_channel_output_cc_errors_per_sec | channel | Output CC errors/sec |
nosignal_channel_output_pcr_jitter_us | channel | Output PCR jitter |
Multicast Scanner
The scanner discovers active multicast streams on your network interfaces.
Running a Scan
- Navigate to Scanner in the sidebar.
- Select the network interface to scan on.
- Optionally specify a multicast range (e.g.,
239.0.0.0/8). Leave blank for passive blind scan. - Click Start Scan.
The scan runs for up to 5 minutes. Results show each discovered multicast group with:
- Multicast address and port
- Detected services (program names from SDT/PAT)
- Bitrate
- Whether the stream is already configured as a channel
Channel Explorer
The Explorer provides a compact table view of all channels with their multicast addresses, service IDs, input/output mapping, and current state. It is designed for quick lookups — "which multicast group does this channel use?" — and includes:
- Channel name with logo, service ID badge, and status pill
- Input and output addresses at a glance
- Search and filter by name, address, or state
- Sortable columns
- Copy any address to clipboard with a single click
Overview (Live Data)
The Overview page shows a real-time summary of all running channels on a single screen. For each channel it displays:
- Current state and active input
- Input and output bitrate
- CC error rate
- PCR jitter
Values update in real time. This is the go-to page for NOC operators monitoring a headend at a glance.
Consumers
The Consumers page shows all currently connected output subscribers — HTTP TS clients and SRT peers. For each consumer you can see:
- Client IP address and port
- Connected channel
- Connection duration
- Bytes delivered
This is useful for monitoring who is pulling streams and diagnosing delivery issues.
System
Performance
The Performance page shows real-time system resource usage: CPU usage, memory consumption, and process statistics. Use this to ensure your server has enough headroom for the number of channels you're running.
Network Interfaces
View all network interfaces with per-interface statistics: RX/TX bitrate, packet drops, and errors. You can also set friendly descriptions for each interface to identify them in the channel configuration.
Settings
The Settings page provides:
- API Keys — create, list, and revoke API keys for external integrations. Each key has a label, permission level (ro/rw), and optional IP whitelist.
- Multicast defaults — configure default multicast output settings (next available address suggestion).
- EPG tuning — sweep cadence and XMLTV fetch intervals.
- Public status page — master on/off switch and CC-error reporting toggle for the
/statuspage (see below).
Config Backup & Restore
Export your entire configuration (all channels, inputs, outputs, failover, pipeline, EPG mappings) as a JSON file:
- Export — Settings → Config Backup → Download. Saves everything needed to rebuild the instance.
- Import — Settings → Config Backup → Upload. Replaces the current configuration with the imported JSON.
Offline Banner (Slate)
When all inputs for a channel are exhausted and no_signal_slate is enabled, NoSignal can display a custom offline banner image as a looping MPEG-TS stream.
- Upload a custom PNG or JPG image via Slate Settings.
- The image is automatically converted to MPEG-TS using FFmpeg.
- If no custom image is uploaded, a built-in default slate is used.
- Preview the current slate image in the settings page.
Public Status Page
NoSignal ships with an unauthenticated status surface at /status that subscribers can bookmark to check for outages. Only channels with the public flag are ever exposed — private channels are invisible regardless of state so internal channel names don't leak.
The underlying endpoint is GET /api/v1/public/status. It returns the total count of public channels, an ok_count, and an issues[] array of the ones considered affected. The response is cached in-process for 60 seconds — every visitor within a cache window sees an identical snapshot and an identical generated_at timestamp, so hitting refresh does not reset the "updated Ns ago" counter.
Issue rule
By default a channel is listed as an issue only when it is in the stopped state. Channels that fell back to a secondary input are state degraded and are not flagged — the viewer still sees a working signal. Turn on Also report CC errors (Settings → Public status page) to additionally flag channels with cc_errors_per_sec > 0.
Disabling the page
Operators who don't want a subscriber-facing status surface at all can flip Enable public status page off. With the toggle off, both /status and /api/v1/public/status return 404; the page then renders a polite "not available" notice instead. The toggle is read on every recompute, so changes take effect at the next 60-second cache refresh.
Logs
The Logs page aggregates events from all channels into a single searchable, filterable timeline. Filter by event type, channel, severity, or free-text search.
License Management
NoSignal instances run in one of two licensing modes. Both use Ed25519-signed leases, but behave very differently at runtime.
Modes
| Mode | Network | Renewal | Binding |
|---|---|---|---|
| Subscription | Requires a live TLS connection to the license server. | Heartbeats every ~1 h with a multi-day grace window on transient outages. | Keypair + soft fingerprint (machine-id, interfaces, hostname). |
| Perpetual | Fully offline. Never contacts the license server after install. | Never — the lease has no expiry. | 2-of-3 quorum over machine-id + primary MAC + hostname, plus a major.minor version pin. |
License States
| State | Applies To | Behavior |
|---|---|---|
| NoLease | Both | No lease installed. Channel starts are blocked. |
| Licensed | Subscription | Valid lease. Full operation. |
| Grace | Subscription | License server unreachable but lease still valid. Channels continue running normally. |
| OfflineExpired | Subscription | Grace window ended without a successful heartbeat. New starts blocked; running channels keep going but are read-only until reconnection. |
| Restricted | Subscription | Server returned a soft reject (e.g. instance converted to perpetual, binary mismatch). Mutations blocked; existing channels unaffected. |
| Perpetual | Perpetual | Quorum ≥ 2/3 and version line matches. Full operation, no network dependency. |
| Locked | Both | Hard stop. All channels are stopped. Triggered by failed perpetual quorum, version mismatch, or explicit server revoke (subscription only — perpetual leases are non-revocable by design). |
Subscription Configuration
Navigate to License in the sidebar and fill in:
- Instance ID — unique identifier for this installation (generated when you register with the license server).
- License server URL — e.g.
https://license.nosignal.ro. - Server public key — the license server's Ed25519 public key (base64) used to verify lease signatures. Modern builds ship with the production key baked in, so this is only needed for staging or self-hosted license servers.
You can regenerate the instance's Ed25519 keypair from this page; the new public key must be registered with the license server before the next heartbeat.
Perpetual Install
A perpetual license is delivered as a single text block (the NSL1 key) — everything the instance needs is in that text, including the signature. No server round-trip is ever made.
- The operator (or Cloud Craft sales) generates the key on the license server by entering the customer's
/etc/machine-id, primary MAC, hostname, allowed version line (e.g.0.8), and max channels. - The customer installs the key by one of three routes:
- GUI — paste the entire NSL1 block into the License page textarea and submit. Surrounding email text is tolerated; the parser finds the
BEGIN/ENDmarkers. - CLI —
nosignal --install-license /path/to/key.txt(persists and exits; does not start the server). - Drop-in file — place the key text at
license.txtnext to the nosignal data file. It is picked up on the next startup.
- GUI — paste the entire NSL1 block into the License page textarea and submit. Surrounding email text is tolerated; the parser finds the
- On install, the instance verifies the Ed25519 signature, checks the 2-of-3 machine-identifier quorum, and confirms the binary's
major.minorversion matchesbind_version. A quorum < 2 or a version mismatch rejects the install.
To pre-flight a key without committing to install, run nosignal --verify-license /path/to/key.txt. It prints mode, bind_version, max channels, and the local quorum (N/3) without touching state.
Perpetual Runtime Behavior
- Offline forever — no heartbeat task is spawned. The license server may be decommissioned without affecting the instance.
- 24-hour re-check — a background task re-evaluates machine-identifier quorum and version pin once per day. Quorum < 2 or a version upgrade to a new minor line transitions the instance to Locked.
- Bugfix upgrades are free — a lease bound to
0.8accepts any0.8.xbuild. Upgrading to0.9.0or1.0.0requires a new key from sales. - Non-revocable — by design there is no kill-switch. To relocate a perpetual instance (hardware swap, hostname change) the admin re-mints the key with the new bound identifiers; the old key is replaced on the target machine.
External API Reference
The external API allows third-party systems (monitoring dashboards, automation scripts, broadcast controllers) to interact with NoSignal. All endpoints live under /api/v1/ext/.
Authentication
API keys are created in Settings → API Keys. Each key has a label, permission level (ro or rw), and optional IP whitelist.
Pass the key in the X-API-Key header:
curl -H "X-API-Key: nsk_xxxxx" https://nosignal.example.com/api/v1/ext/channels
Key format: nsk_ prefix + 48 random alphanumeric characters. Keys are SHA-256 hashed before storage and cannot be retrieved after creation.
IP Whitelisting
Each key can have an IP whitelist. Supported formats: exact IP (192.168.1.50), CIDR (10.0.0.0/24), or comma-separated. Empty whitelist allows all IPs.
Channel Endpoints
List All Channels
GET /api/v1/ext/channels
Returns all channels with current status and summary metrics.
Channel Status
GET /api/v1/ext/channels/{slug}/status
Returns channel state, active input, and per-input health.
Combined Status + Live Telemetry
GET /api/v1/ext/channels/{slug}/live
Returns both status and live telemetry in a single response. Recommended for dashboard polling.
Telemetry Endpoints
Live Telemetry Snapshot
GET /api/v1/ext/channels/{slug}/telemetry
Historical Telemetry
GET /api/v1/ext/channels/{slug}/telemetry?range=1h|6h|1d|7d|30d
Returns time-series data from Prometheus. Step sizes: 1h→30s, 6h→60s, 1d→5m, 7d→15m, 30d→1h.
Event Endpoints
GET /api/v1/ext/channels/{slug}/events?limit=50&search=failover&since=2026-01-01T00:00:00Z
| Parameter | Type | Description |
|---|---|---|
limit | int | Max events to return (default 50) |
offset | int | Pagination offset |
event_type | string | Filter by type (e.g., failover, cc_error) |
search | string | Free-text search in event messages |
since | ISO 8601 | Events after this timestamp |
until | ISO 8601 | Events before this timestamp |
Write Operations (rw keys only)
Create Channel
POST /api/v1/ext/channels
Content-Type: application/json
{
"name": "BBC One HD",
"enabled": true,
"inputs": [
{"type": "udp_multicast", "address": "udp://[email protected]:1234", "priority": 0},
{"type": "srt", "address": "srt://backup.example.com:9000", "priority": 1,
"config": {"latency_ms": 200}}
],
"outputs": [
{"type": "udp_multicast", "address": "239.2.1.1:5000", "config": {"ttl": 16}}
],
"failover": {
"source_timeout_ms": 5000,
"auto_revert": true
}
}
Update Channel
PUT /api/v1/ext/channels/{slug}
Same body as create. Running channels are automatically restarted.
Delete Channel
DELETE /api/v1/ext/channels/{slug}
Stops the channel if running, then deletes it with all associated configuration.
Input & Output CRUD
# Add input
POST /api/v1/ext/channels/{slug}/inputs
# Update input
PUT /api/v1/ext/channels/{slug}/inputs/{id}
# Delete input
DELETE /api/v1/ext/channels/{slug}/inputs/{id}
# Add output
POST /api/v1/ext/channels/{slug}/outputs
# Update output
PUT /api/v1/ext/channels/{slug}/outputs/{id}
# Delete output
DELETE /api/v1/ext/channels/{slug}/outputs/{id}
Start / Stop Channel
POST /api/v1/ext/channels/{slug}/start
POST /api/v1/ext/channels/{slug}/stop
Error Codes
| Status | Meaning |
|---|---|
401 | Missing or invalid API key |
403 | Permission denied (ro key on write endpoint, IP not whitelisted) |
404 | Resource not found (channel, input, or output) |
422 | Validation error (invalid request body) |
502 | Upstream unavailable (Prometheus unreachable) |
Recommended Polling Intervals
| Use Case | Interval | Endpoint |
|---|---|---|
| Live dashboard | 2–5 seconds | GET .../live |
| Status monitoring | 10–30 seconds | GET .../status |
| Event ingestion | 30–60 seconds | GET .../events?since=... |
| Periodic reporting | 5–15 minutes | GET .../telemetry?range=1h |
Download API Reference
The full API reference is also available as a Markdown download from any running instance:
GET /api/v1/ext/docs
No API key required. Returns text/markdown.
CLI Reference
nosignal [OPTIONS]
Options
| Flag | Default | Description |
|---|---|---|
--data <PATH> | ./nosignal.redb | Path to the redb data store |
--api-bind <ADDR> | 127.0.0.1:8080 | API and web UI bind address |
--hls-bind <ADDR> | 127.0.0.1:8090 | HLS server bind address |
--log-level <LEVEL> | info | Log level: trace, debug, info, warn, error |
--jwt-secret <SECRET> | random | JWT secret for session tokens. Random if absent (tokens won't survive restart). |
--install-service | — | Install systemd service, create user, directories, and cron backup (requires root). Fresh installs only. |
--update-service | — | Refresh the systemd unit + sysctl drop-in on an existing install. Backs up the old unit, runs daemon-reload, restarts the service. Does not touch .env, the data store, or credentials. Use after upgrading the binary to a release that needs new capabilities (v0.8.71+ requires CAP_SYS_NICE + LimitRTPRIO=40 for SCHED_FIFO promotion of the UDP pacer threads). |
--generate-prometheus-conf | — | Write prometheus.yml to current directory |
--generate-sysctl-conf | — | Write multicast sysctl config to /etc/sysctl.d/ (requires root) |
--reset-password | — | Reset admin password, print new credentials, and exit |
--install-license <FILE> | — | Install a perpetual license from an NSL1 text key file, then exit. Does not start the server. |
--verify-license <FILE> | — | Verify a perpetual license key without installing. Prints mode, bind_version, max channels, and local quorum N/3. Read-only. |
--suggest-network-tuning | — | Inspect NIC ring buffers and print an advisory on recommended ethtool -G settings for high channel counts. Read-only. |
Environment Variables
Defaults aim for lowest PCR jitter on the wire (what TVs downstream of professional re-multiplexers see). Trade CPU for jitter only when the downstream tolerates it. All vars are read from /srv/nosignal/.env; restart the service for changes to take effect.
General
| Variable | Default | Description |
|---|---|---|
NOSIGNAL_API_BIND | 127.0.0.1:8080 | Override --api-bind |
NOSIGNAL_JWT_SECRET | — | Override --jwt-secret |
NOSIGNAL_WORKER_THREADS | 8 | Cap tokio worker threads |
NOSIGNAL_METRICS_INTERVAL_S | 60 | Prometheus scrape interval (10–300). Must match prometheus.yml. |
NOSIGNAL_PROMETHEUS_URL | http://127.0.0.1:9090 | Prometheus URL for telemetry query proxy |
UDP Output Pacer (DVB-critical, v0.8.71+)
The pacer determines PCR arrival jitter at downstream re-multiplexers (Teleste Luminato, Cisco RX-1, professional headends). Default is one dedicated OS thread per UDP output, promoted to SCHED_FIFO priority 20. CPU cost is roughly 1.5–2× the async pacer; turn knobs down only if measurements warrant.
| Variable | Default | Description |
|---|---|---|
NOSIGNAL_UDP_PACER_ASYNC | unset | Set to 1 to revert to the tokio-async pacer (shared workers). Lower CPU, higher PCR jitter under load. |
NOSIGNAL_UDP_PACER_LEGACY_THREAD | unset (= dedicated thread) | Set to 0/false/no/off to opt out of the dedicated thread (same as ASYNC=1). Back-compat env name with inverted semantics. |
NOSIGNAL_UDP_PACER_RTPRIO | 20 | SCHED_FIFO priority for the pacer thread. 0 skips RT promotion (still dedicated thread but SCHED_OTHER). Range 1..=49. Requires CAP_SYS_NICE + LimitRTPRIO=40 in the systemd unit. |
NOSIGNAL_UDP_PACER_BATCH | 1 | Datagrams coalesced per sendmmsg(2) (1–16). K=1 paces every datagram individually. K>1 trades K×datagram_interval of intra-burst smear for fewer syscalls. |
NOSIGNAL_UDP_PACER_CPUSET | unset | Pin pacer threads to a CPU set (e.g. 2-5). Multi-NUMA only. |
UDP Input + Monitor
| Variable | Default | Description |
|---|---|---|
NOSIGNAL_UDP_RX_BATCH | 8 | Datagrams drained per recvmmsg(2) on UDP input (1–32). K=1 ≈ legacy recv. |
NOSIGNAL_UDP_RX_LEGACY | unset | Set to 1 to force pre-0.8.11 single-recv UDP input loop (per-host rollback). |
NOSIGNAL_DISABLE_PCR_JITTER | unset | Set to 1 to skip per-packet PCR jitter sampling on the monitor hot path. |
Verifying the pacer is at SCHED_FIFO
ps -eLo pid,tid,nice,rtprio,policy,comm | grep udp-out
# Expect: POL=FF (SCHED_FIFO), RTPRIO=20 on every udp-out-* thread
If you see POL=TS instead of FF, the systemd unit is missing CAP_SYS_NICE / LimitRTPRIO=40. Run sudo /srv/nosignal/nosignal --update-service to refresh it.
Troubleshooting
Channel keeps flapping between two inputs
Symptoms: Repeated failover/revert events every few minutes.
Cause: Both inputs are marginal — primary recovers just long enough to pass the probe gate, then fails again.
Fix:
- Increase
revert_after_probes(e.g., to 5) to require longer proof of stability. - Increase
revert_delay_msto give the primary more settling time. - Check the underlying transport (packet loss, jitter) on both inputs.
Failover is too slow
Symptoms: Several seconds of dead air before the backup activates.
Fix:
- Lower
source_timeout_ms(e.g., 2000–3000 ms). - Reduce
probe_interval_ms(e.g., 10000–30000 ms for critical channels) so backup health is always fresh.
Backup never activates despite primary being down
Symptoms: Channel shows no_data warnings but stays on the failed primary.
Fix:
- Check backup input URL and network connectivity.
- Review
probeevents in the channel log — look for consecutive probe failures. - Verify firewall rules (backup source IP/port reachable from the NoSignal server).
Failback never happens
Symptoms: Channel stays on backup even though primary is working again.
Fix:
- Confirm
auto_revertistrue. - Check
probeandcc_errorevents — if the primary has CC errors during deep probe, it won't pass the quality gate. - Investigate the primary source for intermittent CC errors.
No historical telemetry charts
Symptoms: Telemetry page shows "No data" for historical ranges.
Fix:
- Verify Prometheus is running:
sudo systemctl status prometheus - Check the scrape target is healthy:
curl -s http://127.0.0.1:9090/api/v1/targets | jq '.data.activeTargets[].health' - Ensure
NOSIGNAL_METRICS_INTERVAL_Smatchesscrape_intervalinprometheus.yml.
Input locked out
Symptoms: Event log shows "input locked out" error.
Fix:
- The lockout clears automatically after 30 minutes.
- To clear immediately, restart the channel (stop + start).
- Investigate and fix the underlying input issue.
Cannot start channels
Symptoms: Start button is disabled or returns an error.
Fix:
- Check license status —
ExpiredorLockedstates block new starts. - Navigate to License page and verify the configuration.
Lost admin password
sudo /srv/nosignal/nosignal --reset-password
This prints a new random password and exits. The service does not need to be stopped.
Glossary
| Term | Definition |
|---|---|
| MPEG-TS | MPEG Transport Stream — the packet-based container format used in digital television broadcast and IPTV. |
| PID | Packet Identifier — a 13-bit field in each TS packet header identifying the stream it belongs to. |
| PAT | Program Association Table — maps program numbers to their PMT PIDs. Always on PID 0. |
| PMT | Program Map Table — lists the elementary streams (video, audio, etc.) belonging to a program. |
| SDT | Service Description Table — carries service names, provider names, and service type. |
| EIT | Event Information Table — carries programme schedule data (now/next and schedule). |
| NIT | Network Information Table — describes the physical network (transport streams, frequencies). |
| PSI | Program Specific Information — collective term for PAT, PMT, CAT, and NIT. |
| PCR | Program Clock Reference — timestamp in the TS adaptation field used for decoder clock synchronization. |
| CC | Continuity Counter — 4-bit counter in each TS packet. Discontinuities indicate packet loss. |
| SPTS | Single Program Transport Stream — a TS carrying exactly one service. |
| MPTS | Multi Program Transport Stream — a TS carrying multiple services. |
| CBR | Constant Bitrate — output mode where null packets pad the stream to a fixed rate. |
| VBR | Variable Bitrate — output mode where packets pass through at their natural rate. |
| SRT | Secure Reliable Transport — open-source protocol for low-latency video over unreliable networks. |
| HLS | HTTP Live Streaming — Apple's playlist-based adaptive streaming protocol (RFC 8216). NoSignal supports HLS as an input (pull a remote playlist and splice TS segments) and as a top-level origin subsystem (per-channel .m3u8 + ~6 s segments served from --hls-bind). See HLS Origin. |
| XMLTV | XML-based format for exchanging TV programme schedule data. |
| Perpetual | A fully offline license mode — the instance never contacts the license server after install. Lease is bound to machine identifiers and a major.minor version line. |
| Quorum | The perpetual license match policy: at least 2 of 3 identifiers (machine-id, primary MAC, hostname) must match the bound hashes for the license to hold. |
| NSL1 | NoSignal License v1 — the ASCII key block format for perpetual licenses. PEM-style wrapper around a signed JSON payload. |
| PNR | Program Number — identifies a service within a transport stream (used in PAT/PMT). |
| TTL | Time To Live — multicast packet hop count limit. |
| TDT/TOT | Time and Date Table / Time Offset Table — carry UTC time in the transport stream. |