Skip to content

Reference App

The SDK package includes a reference app: a complete player written in C that drives every part of the SDK and is controlled from a web UI in your browser.

Why it exists

We designed and wrote the reference app to show how we think the SDK could be used. The reference app shows how the SDK functions fit together in a running player, including the obligations that come with them, who owns a returned object, when a result has to be consumed, how to poll asynchronous operations, and in which order to shut things down.

Use it to:

  • Learn our patterns. Every interaction an integration needs is implemented in plain C, with comments at the points where the SDK contract places obligations on the caller.
  • Experiment. Build it on your development machine or target hardware, pair it with your test account and try things out before you write your own integration. Change the code and see what happens.
  • See the SDK working end to end. When your own integration behaves unexpectedly, the reference app can give you a baseline to compare against on the same hardware.

Free to reuse

Everything in the reference app, including the automatic updater, may be used in your own project. Copy individual functions, adapt whole files, or use it as the starting point for your player.

Your code, your responsibility

Code you take from the reference app becomes part of your player. Testing, maintaining and certifying it is your responsibility, just like code you wrote yourself.

The reference app is not a certified product. It shows the patterns, but your own player still has to meet the requirements and pass certification on your hardware, including any parts used from the reference app.

Where to look

SDK concept Demonstrated in
Loading the SDK (dlopen and entry symbol) src/splayer_context.c
Player configuration and options src/splayer_context.c
Pairing (browser redirect and manual code) src/routes.c
Playback control and state polling src/routes.c, src/splayer_json.c
Track metadata and album art src/splayer_json.c
Asynchronous library fetch (submit, poll, consume) src/library_fetch.c
Troubleshooting report (error codes) src/splayer_json.c (build_troubles)
Automatic updater src/updater.c, run.sh
Clean shutdown ordering src/main.c
Audio output callbacks ../src/audio_output_*.c

The C code in src/ is where the patterns live. The web frontend in html/ only exists to give you something to click, it is not a pattern to follow.

Getting started

The reference app ships as source in splayerapi-v5/reference-app/. Build and run instructions, the architecture, the REST endpoints and the file layout are described in README.md in that directory.

The app runs everything on a single thread, so it uses only the non-blocking SDK functions (fetch_library, initiate_pair_with_code, unpair) and never the blocking *_sync variants.

Automatic updater

We release new versions of the Player Library on a regular schedule, and every player must pick them up automatically to follow it. The updater is therefore a certification requirement, and the reference app includes an updater that we wrote ourselves, in src/updater.c. It shows one way to meet the Upgrade and Provisioning requirements, and you are free to use it in your own player.

What it does

The updater is a small state machine driven by a libuv timer:

IDLE --> CHECKING --> DOWNLOADING --> AWAITING_SHUTDOWN
  ^                               |
  |_______________________________|   (on any failure)
  1. Poll the release channel every 15 minutes (the first check runs 15 minutes after start).
  2. Compare versions. If version in the response equals the running library's version get_current_version(), there is nothing to do.
  3. Download the file from link to a temporary file next to the library, computing the SHA-1 checksum while writing.
  4. Verify the checksum against checksum in the response. On a mismatch the file is discarded and the updater returns to idle.
  5. Replace the library by renaming the downloaded file over the current one.
  6. Exit by calling request_exit() with SPLAYER_EXIT_UPGRADE. The SDK finishes the current track, then should_exit() returns 1, the app shuts down cleanly and exits with code 0.
  7. Restart. run.sh starts the app again as soon as it exits, and the app dlopens the new library.

Configuring it

  • Release channel: set MANIFEST_URL to the release channel endpoint we give you. The updater is disabled while it is empty, which is the default in the SDK package's build (CMakeLists.txt).
  • Library path: the file that is replaced is SDK_LIB_PATH, the same path the app loads the library from.

Start the app through run.sh rather than running the binary directly, otherwise nothing restarts it after an update. run.sh also restarts the app after a crash, two seconds after a non-zero exit.

Testing the update flow locally

src/webserver.py in the SDK package is a small local provisioning server. Point it at one or more library files and it serves a response for them at /latest.json, in the same format as the release channel. Set MANIFEST_URL to that address to exercise the whole flow on your desk. The mock libraries built from the package's top-level CMakeLists.txt (splayer-mock-123 and splayer-mock-321) report different versions, which makes them useful for testing a library swap.