Skip to content

About

Audio player for any device (Rasberry PI or anything). Web radio, network disk, CD, ... Developped in Rust for safety and extendable via plugins

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

Ritornello

A standalone internet radio and CD player, in Rust, for the Raspberry Pi — and any Linux box.

CI Back end in Rust armv7, aarch64, x86_64 Vue 3 Latest release MIT OR Apache-2.0

The web UI home page: a Player card with the current track and where the information came from, a full remote control below

Ritornello turns a Raspberry Pi plugged into an amplifier into a radio and CD player that is driven by an infrared remote, displays on the HDMI screen, and is administered from a browser on the local network. The core is a small Rust orchestrator driving mpv; everything else — content sources, inputs, displays, metadata — lives in plugins running as separate processes, replaceable without touching the core.

The reference machine is a Raspberry Pi 2 — 32-bit ARM, 1 GB of RAM, in daily use — and the same binaries build for armv7, aarch64 (Pi 3, 4 and 5) and x86_64, so a plain Linux PC runs it just as well.

Download

Everything is installed onto the device from your own computer by one program, ritornello-install, over ssh — nothing to build:

Your computer Installer
Windows (64-bit) ritornello-install-x86_64-pc-windows-msvc.zip
macOS, Apple Silicon ritornello-install-aarch64-apple-darwin.tar.gz
macOS, Intel ritornello-install-x86_64-apple-darwin.tar.gz
Linux or WSL, x86_64 ritornello-install-x86_64-unknown-linux-musl.tar.gz
Linux, 64-bit ARM ritornello-install-aarch64-unknown-linux-musl.tar.gz

Then ./ritornello-install --host user@device and follow the screens — the details per system are in docs/installation.md. These links always point at the newest installer, whatever the state of the product's own releases: the installer has its own releases, and the program itself installs the newest Ritornello release (the newest prerelease while no final one exists). It tells you when a newer installer exists.

Highlights

  • Internet radio — presets on the remote's number pad, station management in the browser, search in the community directory Radio Browser (by name and by country), stations reorderable by drag and drop.
  • CD player — disc detection, track list, album recognition and cover art through MusicBrainz; arriving at the source plays nothing, starts at track 1 or resumes the last track, as you prefer.
  • Audio files — from a USB stick, a folder of the device, or an authenticated SMB share mounted on demand; a file browser with search; playlists built by adding folders recursively, saved and loaded again. A root can also be armed to keep the covers it finds: the picture fetched for an album is written beside the tracks as a cover.jpg, or under the name you pick for every source (folder, front…) — never into a folder that already has a cover — so any other player finds it too.
  • Shuffle, repeat all and repeat one — on any source that has a finite list (a folder, a disc), driven from the web page, from a key on the remote or from an MPD client. Shuffle draws the list once and then stops rather than rolling dice at every track, and both modes belong to the device: they survive a source change, a stop and a restart.
  • Now-playing metadata, with provenance — the stream's ICY header, enriched by dedicated plugins (MusicBrainz for discs and for cutting up an ICY string, OUI FM's metadata feed, Radio France's live endpoint for its 74 stations — which broadcast no ICY at all — and the NRJ group's 365 webradios). Each field says where it came from, down to the release year and the links to the streaming platforms.
  • Any remote control — any Linux input device (evdev) will do, including a USB infrared receiver; keys are learned from the browser, presets ship with the project (MCE, keyboard). Beside the fixed actions, every installed source gets a row of its own, so a key can jump straight to the radio rather than cycling to it.
  • MPD server — the device shows up as an MPD server on port 6600, so existing phone clients (tested with M.A.L.P.) drive playback, volume and cover art out of the box, each source appearing as a stored playlist. A deliberate subset of the protocol, cut to what the device is: there is no tag database, so searching or browsing a music library answers empty, and the queue — the active source's presets — is neither reorderable nor savable.
  • Embedded web UI — Vue 3, served by the core binary: player state pushed continuously (SSE), full remote control, light/dark toggle and 42 themes, English built in and French, German, Spanish and Italian as installable TOML language packs, a system page (CPU, memory and the Ritornello process tree, temperature, under-voltage, shutdown/reboot).
  • HDMI screen — the console plugin composes now-playing and clock screens on the framebuffer console, no X11 or Wayland involved.
  • Self-update and plugin management — the core and each plugin check GitHub releases and install what changed from the browser, with an automatic rollback if the new binary fails to start; a plugin can also be installed, removed or reordered live. Third-party repositories can be added as sources: a plugin from one is installed after a confirmation naming the repository, a language pack with its source named on its row.

The same home page in dark mode The radio plugin's administration page: reorderable stations and directory search

The configuration page's update section: what has been checked, the automatic policy with its prerelease switch, and the plugins table with each plugin's version and state The system page: CPU, memory, a history graph, load average, storage — and shutdown/reboot further down

The home page on a phone: the remote control fits the screen

Architecture

flowchart LR
    ir["IR remote"] --> input
    browser["Browser<br/>(embedded Vue 3 UI)"] <--> core
    mpdclient["MPD client<br/>(phone)"] <--> mpd
    subgraph device["Raspberry Pi — or any Linux"]
        core["ritornello-core<br/>orchestrator + web server"]
        mpv["mpv (JSON-IPC)"]
        radio["radio plugin"] <--> core
        cd["cd plugin"] <--> core
        files["files plugin<br/>(local folders, SMB)"] <--> core
        core <--> mb["musicbrainz plugin"]
        core <--> ouifm["ouifm-metas plugin"]
        core <--> rf["radiofrance-metas plugin"]
        core <--> nrj["nrj-metas plugin"]
        input["generic-input plugin<br/>(evdev)"] --> core
        core --> console["console plugin<br/>(HDMI screen)"]
        mpd["mpd plugin"] <--> core
        core <--> mpv
    end
    mpv --> hp["ALSA → amplifier"]
Loading

Plugins speak a line-delimited JSON protocol over Unix sockets, in four kinds: source (what to play: radio, CD, files…), input (where commands come from), display (where to show things) and metadata (what exactly is playing). A plugin announces itself to the core at startup — its kinds and, optionally, an administration page that the web UI mounts as its own tab. plugins.toml only lists a name and an executable.

Plugin Kind What it does
radio source Internet radio, presets, Radio Browser directory, admin page
cd source CD drive (/dev/sr0), disc identification, eject
files source Local folders, USB, SMB shares mounted on demand, playlists, file browser, covers archived beside the tracks
generic-input input Any evdev device: IR receiver, keyboard, remote; key learning in the browser, one key per source
console display Now-playing and clock screens on the Linux console (HDMI)
musicbrainz metadata Album, year, cover art and platform links for discs and streams
ouifm-metas metadata OUI FM's now-playing feed (21 webradios)
radiofrance-metas metadata Radio France's live endpoint (74 stations without ICY)
nrj-metas metadata NRJ group's on-air endpoint (NRJ, Nostalgie, Chérie FM, Rire & Chansons — 365 stations)
mpd server Exposes the device as an MPD server for existing clients — a protocol subset: no tag database, no queue editing

A Rust SDK (ritornello-plugin-sdk) provides the traits and the runtime for each kind; the wire protocol (ritornello-proto) is plain JSON, so a plugin can equally be a Python or Go program.

Hardware and portability

Status
Raspberry Pi 2 (armv7, 32-bit) — Raspberry Pi OS Lite, DietPi Reference hardware, in daily use
Raspberry Pi 3/4/5 (aarch64) Builds; untested for lack of hardware, no known reason it would not work
x86_64 Linux PC or server Builds and runs; used for development and CI
Audio output Whatever ALSA sees: the Pi's jack, HDMI, a USB DAC — selectable from the web UI
Remote control Any evdev input device (USB IR receiver, keyboard…)
Display HDMI screen through the Linux console; other displays are a plugin away
CD drive Any drive Linux exposes as /dev/sr0

Runtime dependencies on the target are a handful of Debian packages: mpv cd-discid eject (plus cifs-utils for network shares).

Quick start

To install on a device without building anything, take ritornello-install for your computer from Download above and run it against the device over ssh.

To build it yourself, on the development machine (Node 20+, Rust stable, cross for ARM):

./deploy/build.sh                              # npm, then cargo, then cross ARM
RITORNELLO_HOST=pi@raspberrypi.local ./deploy/deploy.sh   # builds, packages, installs over SSH

deploy.sh packages what it built exactly as a release would and hands it to ritornello-install, which copies the binaries, language packs and remote presets, installs the hardened systemd unit and provisions plugins.toml and every plugin's own data directory from the example TOML files (without overwriting yours). The web UI is then at http://<host>:8080. The step-by-step details, for a Pi or a plain Linux PC, are in docs/installation.md.

To try it without any hardware, a local instance runs in five minutes: docs/development.md.

Why Ritornello?

It started as a personal itch. A Raspberry Pi 2, a CD drive and an amplifier were sitting in the living room, and the software that used to run them had moved on: the current releases of Volumio and moOde no longer target that generation of hardware. What the household actually wanted was simpler than either — press 3 on the remote, hear the third station; put a disc in, hear the disc; glance at the screen to know what is playing. (Mopidy might well have done the job; the author only came across it long after this had started.)

So Ritornello is opinionated about a few things:

  • Runs on modest hardware, for real. The Pi 2 (1 GB of RAM, 32-bit ARM) is the daily-use reference machine, not a best effort. Rust and mpv keep the footprint small; there is no interpreter, no database server, no desktop stack.
  • Portable by construction. Nothing in the code is Pi-specific: the remote goes through evdev, sound through ALSA/mpv, IPC through Unix sockets. The same binaries build for armv7, aarch64 and x86_64, and the whole thing runs on a laptop for development.
  • Robust by construction. Every plugin is a supervised process — its death is tolerated and reported, never propagated. The service runs unprivileged under a hardened systemd unit (dedicated user, device access through groups, ProtectSystem=strict).
  • Built to be extended. A Bluetooth source, an OLED display, a rotary encoder or another metadata provider is one more binary that speaks a small line-delimited JSON protocol — in any language. The core and the other plugins do not change.

It was written for one household first, but it is meant to be shared: the plugin boundary, the two-language UI, the TOML configuration and the end-to-end test suite are all there so that the next person can add their station directory, their screen or their remote without asking anyone.

Extending it

Writing a plugin means implementing one of the SDK traits (SourcePlugin, InputPlugin, DisplayPlugin, MetadataPlugin) in a binary, and pointing plugins.toml at it. Optionally, ship a Vue page built on the project's component kit and it appears as a tab of the web UI. The full contract, the bundled plugins as worked examples, and the UI recipe are in docs/plugins.md.

Ideas that fit the boundary as it is today: a Bluetooth or Spotify Connect source, an OLED/LCD display, a GPIO rotary encoder input, another radio network's metadata feed, another language pack.

Documentation

Document Contents
docs/installation.md Building, installing on a Pi or a Linux PC, deploying, unprivileged service, installing from a release and publishing one, prereleases, arming the self-update, tuning the audio buffers
docs/plugins.md The bundled plugins, the metadata kind, writing your own plugin and its UI, publishing a third-party plugin
docs/interface.md The web UI, the command API, the physical remote, updates and plugin management, languages, themes
docs/development.md Local instance without hardware, tests, e2e journeys, cutting a release, regenerating embedded data
AGENTS.md Where each answer lives, and the project rules that are invisible from the code — written for a coding agent, useful to a newcomer

The project is developed through written specifications, implementation plans and systematic reviews; the design record is kept outside this repository, and the durable decisions live in the code comments and in the documents above.

Status and contributing

Ritornello is at 0.2.x: it runs every day in one living room and the feature set above is real, but the plugin protocol and the configuration files may still change before a 1.0. CI builds the UI, runs clippy with warnings denied, the Rust test suite and the Playwright end-to-end journeys on every push; a v* tag drafts a GitHub release with per-component archives for three architectures (armv7, arm64, x86_64) — see docs/installation.md.

Contributions are welcome — especially reports from other boards, other DACs and other remotes, since the author only owns one of each. Open an issue before a large change so the design can be discussed first; small fixes and language packs can go straight to a pull request. Please keep scripts/ci-local.sh green: it runs exactly what CI runs.

License

Licensed under either of Apache License, Version 2.0 or MIT license, at your option — the usual Rust convention.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in Ritornello by you shall be dual licensed as above, without any additional terms or conditions.

About

Audio player for any device (Rasberry PI or anything). Web radio, network disk, CD, ... Developped in Rust for safety and extendable via plugins

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Used by

Contributors

Languages