Skip to main content
DVB-I over 5G Systems

Tutorial: DVB-I Service List Registry

A DVB-I client has to find service lists before it can show any channel. The DVB-I Service List Registry is the component it asks: an HTTP endpoint that answers a query with the entry points of the service lists that match it (ETSI TS 103 770 V1.2.1, clause 5.1.3.2). In this tutorial you run the registry, send it the queries of that clause, register a service list of your own, and check what it answers against the DVB-I schema.

Read the READMEs first

Read the README of rt-dvb-i-service-list-registry before you start. The other repositories below are only needed in the sections that name them.

DVB-I Application

rt-dvb-i-application
Open source

A browser DVB-I client that discovers a service list, presents its channels with their content guide, and plays them, per ETSI TS 103 770.

StandardsDVBIETSI
Runs onWebNode.jsDocker
Depends onExpressdash.jshls.js
License5G-MAG PL v1.0

Where the other repositories are used:

You wantGo to
A registry answering queries in a minute1. Run the registry
To see what it holds and try a query in a browser2. The page at /
Your own service list offered to clients3. Register a service list
To filter by country, delivery, language or provider4. Query it
To know the answer is valid DVB-I5. Check a response against the schema
A different port or registry file6. Configure it

You need: a Linux machine with git, Node.js 20 or later with npm, and curl; about 30 MB of disk. For section 5 you also need python3 with the venv module and the DVB-I schema files (see that section).

1. Run the registry​

cd ~
git clone https://github.com/5G-MAG/rt-dvb-i-service-list-registry.git
cd rt-dvb-i-service-list-registry
npm install
npm start

The registry prints where it listens (the first line is a log record, so its time differs):

{"time":"2026-10-20T22:36:22.147Z","level":"info","msg":"Service List Registry listening","port":7000}
DVB-I Service List Registry -> http://localhost:7000/query

In a second terminal, ask it for the service lists that target Switzerland:

curl -s 'http://localhost:7000/query?TargetCountry=CHE'
<?xml version="1.0" encoding="UTF-8"?>
<ServiceListEntryPoints
xml:lang="en"
xmlns="urn:dvb:metadata:servicelistdiscovery:2024"
xmlns:dvbisd-t="urn:dvb:metadata:servicediscovery-types:2023"
xmlns:mpeg7="urn:tva:mpeg7:2008"
xmlns:tva="urn:tva:metadata:2024">
<ServiceListRegistryEntity>
<Name>5G-MAG Reference Service List Registry</Name>
</ServiceListRegistryEntity>
<ProviderOffering>
<Provider>
<Name>5G-MAG</Name>
</Provider>
<ServiceListOffering>
<dvbisd-t:ServiceListName>5G-MAG</dvbisd-t:ServiceListName>
<dvbisd-t:ServiceListURI contentType="application/xml">
<dvbisd-t:URI>http://localhost:4000/service-list.xml</dvbisd-t:URI>
</dvbisd-t:ServiceListURI>
<dvbisd-t:Delivery>
<dvbisd-t:DASHDelivery/>
</dvbisd-t:Delivery>
<dvbisd-t:Language>en</dvbisd-t:Language>
<dvbisd-t:TargetCountry>CHE</dvbisd-t:TargetCountry>
<dvbisd-t:TargetCountry>DEU</dvbisd-t:TargetCountry>
<dvbisd-t:TargetCountry>ESP</dvbisd-t:TargetCountry>
<dvbisd-t:ServiceListId>tag:5g-mag.org,2026:servicelist:local-demo</dvbisd-t:ServiceListId>
</ServiceListOffering>
</ProviderOffering>
</ServiceListEntryPoints>

That is a Service List Entry Point: the name of a list, the URL where a client fetches it, and what it delivers. The one in the stock file points at http://localhost:4000/service-list.xml, where the DVB-I Application Provider publishes its list.

Ask for a country nothing targets:

curl -s 'http://localhost:7000/query?TargetCountry=ITA'

The answer is a valid document with the ServiceListRegistryEntity and no ProviderOffering, as clause 5.1.3.2 requires when nothing matches.

Leave the registry running

Sections 2 to 5 use this terminal's registry. Stop it with Ctrl+C when you reach section 7.

2. The page at /​

Open http://localhost:7000/ in a browser. The page lists what the registry holds, one row for each service list, and has a form for the queries of clause 5.1.3.2: type a country code, choose a delivery type, a provider and the regulator flag, then press Run. It shows the address it called and the response.

The registry page with two service lists and the response to TargetCountry=FRA

The page is read only. The registry holds its entries in registry.json, and you change them there, as the next section shows.

3. Register a service list​

Clause 5.1.3.2 leaves open how a registry collects and stores the entry points of the providers, so the repository keeps them in one file, registry.json. The registry reads it on every request: you edit it and query again, with no restart.

Open registry.json. Under providers is a list of providers, each with its offerings. Add a provider after the existing one:

{
"name": "Example Media",
"offerings": [
{
"id": "tag:example.com,2026:servicelist:tutorial",
"name": "DVB-I Demo Service List",
"uris": ["http://localhost:4000/service-list.xml"],
"delivery": ["dash"],
"languages": ["en", "fr"],
"genres": [],
"countries": ["CHE", "FRA"],
"regulator": false,
"extensions": []
}
]
}
FieldWhat to put
idThe identifier of your service list. It should be the id attribute of the list itself and never change (TS 103 770 V1.2.1, clause 5.3.5, table 12, ServiceListId)
nameThe name of the list. It shall be the same as the Name element of the list (same table, ServiceListName)
urisThe URL or URLs where a client fetches the list
deliveryOne or more of dash, dvb-t, dvb-c, dvb-s, rtsp, multicast-ts, application
languages, countriesAudio languages (en) and countries (ISO 3166 alpha-3 such as FRA) the list targets. An offering with none is returned for every value of that parameter
genres, regulator, extensionsLeave as shown. regulator is true only for the list a national regulator publishes

The values above match the list you make in Tutorial: DVB-I Application Provider; change them if your list differs.

Check that the registry now offers it:

curl -s 'http://localhost:7000/query?TargetCountry=FRA' | grep -E 'ServiceListName|ServiceListId|URI>'
<dvbisd-t:ServiceListName>DVB-I Demo Service List</dvbisd-t:ServiceListName>
<dvbisd-t:URI>http://localhost:4000/service-list.xml</dvbisd-t:URI>
<dvbisd-t:ServiceListId>tag:example.com,2026:servicelist:tutorial</dvbisd-t:ServiceListId>

If the file is not valid JSON the registry answers 500 Registry unavailable and logs the reason, so a typo shows at once.

4. Query it​

Every recipe is curl -g -s '<registry>/query?<parameters>'. The -g lets curl take the square brackets as they are. The parameters are those of clause 5.1.3.2, in the order it lists them: TargetCountry, regulatorListFlag, Delivery, Language, Genre, ProviderName, inlineImages.

You wantQueryOfferings returned with the two lists of section 3
The lists for one countryTargetCountry=CHE2
One country only the new list hasTargetCountry=FRA1
Either of two countriesTargetCountry[]=CHE&TargetCountry[]=FRA2
One providerProviderName=Example%20Media1
One audio languageLanguage=fr1
A country and a delivery method togetherTargetCountry=FRA&Delivery=dvb-t0

Repeated values of one parameter are alternatives (OR); different parameters narrow the result together (clause 5.1.3.2). The Delivery values are those of table 12b: dvb-dash, dvb-t, dvb-c, dvb-s, dvb-iptv and application, not the names used in registry.json.

Check: count the offerings in an answer.

curl -g -s 'http://localhost:7000/query?TargetCountry[]=CHE&TargetCountry[]=FRA' | grep -c '<ProviderOffering>'
2

Wrong queries are refused, as the clause requires:

curl -s -w '\n%{http_code}\n' 'http://localhost:7000/query?Foo=1'
curl -s -w '\n%{http_code}\n' 'http://localhost:7000/query?Delivery=dvb-xx'
Unknown query parameter "Foo". Accepted, in this order: TargetCountry, regulatorListFlag, Delivery, Language, Genre, ProviderName, inlineImages.
400
Invalid Delivery "dvb-xx". Accepted: dvb-dash, dvb-t, dvb-c, dvb-s, dvb-iptv, application.
400

A request URL longer than 2 048 characters, the limit of the clause, gets 414.

The registry's tests

The repository has unit tests that follow the clause: which parameters exist, how repeated values combine, and which status a bad query gets.

npm test

They finish with pass 14 and fail 0. Its last step, the schema check, skips until you give it the schema files (section 5) and then prints ALL VALID. The line that says NOT CHECKED is about the 5G broadcast extension, which the DVB schemas do not define; the DVB-I over 5G tutorials cover it.

5. Check a response against the schema​

A registry answer is a ServiceListEntryPoints document. Its schema is dvbi_service_list_discovery_v1.6.xsd (TS 103 770 V1.2.1, clause 5.3.1 and annex B). The repository does not carry schema files; you supply them from a folder outside the clone.

  1. Get the schema files. They come with the specification, in the electronic attachment archive of ETSI TS 103 770 (named in annex B and in the repository's README). Put them in one folder, for example ~/dvb-i-schemas. The folder needs dvbi_service_list_discovery_v1.6.xsd and the files it imports: dvbi_types_v1.0.xsd, tva_metadata_3-1_2024.xsd, tva_mpeg7.xsd and xml.xsd.

  2. Run the repository's own check:

    DVBI_SCHEMAS=~/dvb-i-schemas npm run test:xsd
    + fixture, no query parameters: VALID
    + fixture, TargetCountry=ITA: VALID
    + fixture, regulatorListFlag=true: VALID
    + fixture, Delivery[]=dvb-dash&Delivery[]=dvb-t: VALID
    + fixture, no matches: VALID
    + registry.json as shipped: VALID
    ~ fixture + LOCAL 5G delivery extension: NOT CHECKED ...

    ==== ALL VALID (1 not checked, see above) ====
  3. Check any answer yourself. Save this as check.py outside the clone:

    import sys
    from lxml import etree

    schema_file, doc_file = sys.argv[1], sys.argv[2]
    schema = etree.XMLSchema(etree.parse(schema_file))
    doc = etree.parse(doc_file)
    if schema.validate(doc):
    print("VALID:", doc_file)
    else:
    print("INVALID:", doc_file)
    for error in schema.error_log:
    print(f" line {error.line}: {error.message}")
    sys.exit(1)
    python3 -m venv ~/dvbi-check
    ~/dvbi-check/bin/pip install lxml
    curl -g -s 'http://localhost:7000/query?TargetCountry[]=CHE&TargetCountry[]=FRA' > answer.xml
    ~/dvbi-check/bin/python check.py ~/dvb-i-schemas/dvbi_service_list_discovery_v1.6.xsd answer.xml
    VALID: answer.xml
Where the schema files for this page came from

The run for this page used copies of the schema files from the schemas folder of a third-party repository, paulhiggs/dvb-i-tools, because a download of the ETSI archive from the command line was refused (HTTP 403). The ETSI archive was not opened for this page, so which of the five files it contains is taken from the repository's README and from annex B, not from the archive itself.

6. Configure it​

The registry reads three environment variables (README):

VariableDefaultWhat it does
PORT7000The port it listens on
REGISTRY_PATHregistry.jsonThe registry file to read
LOG_LEVELinfoerror, warn, info or debug

For example, a second registry with its own file on another port:

cp registry.json ~/my-registry.json
PORT=7001 REGISTRY_PATH=$HOME/my-registry.json npm start
TLS beyond a private network

TS 103 770 V1.2.1, clause 7.3, says a DVB-I client uses HTTP over TLS to reach a Service List Registry, and allows plain HTTP only when the registry is on the same private subnet as the client. The registry listens on plain HTTP, so for a client on another network put a reverse proxy that terminates TLS in front of it.

7. Stop and clean up​

Press Ctrl+C in the registry's terminal. To remove it, delete ~/rt-dvb-i-service-list-registry, ~/dvb-i-schemas and ~/dvbi-check.

To see a client use your registry, follow Tutorial: DVB-I Application, section 4.

What was run for this page

Every command above was run on a clean clone of main (commit 97721a6) on Ubuntu Linux with Node.js 24.21.0 and npm 11.19.0, Python 3.14.4 and lxml 6.1.3 (libxml2 2.14.6). The registry's dependencies were installed with the plain npm install of section 1.

Section by section: 1 run; 2 run in a headless Chromium (page loaded, query run, screenshot taken); 3 run (the second provider added, the answer read back with no restart); 4 run (every query in the table, the two refusals and the 414); 5 run with the schema files described in the note, npm run test:xsd and check.py both valid; 6 run once (second registry on port 7001 with a copy of the stock file); the TLS note is from the specification and the code and was not run. The registry's npm test printed 14 passes.

A VALID result means the response matches the schema.