Skip to main content
rockbox_ffi_nif is the common native layer for every binding that runs on the BEAM. The Elixir (rockbox_ex_ffi) and Gleam (rockbox_ffi) packages both depend on it instead of vendoring their own copy of the C shim and loader — the ergonomic wrappers live in those packages. Requires OTP 27+ (JSON is decoded with the built-in json module). The Hex package ships only a checksum manifest; the loader’s -on_load hook downloads the matching prebuilt .so for your platform on first use (see NIF delivery).
This page documents the raw NIF surface. For application code prefer the Elixir or Gleam wrappers — they add named enums, pipe-friendly setters, and typed return values on top of the same native functions.
Every function is a raw NIF: strings and paths are UTF-8 binaries, *_json functions return raw JSON binaries (decode with OTP 27’s json module), and handles (RbDecoder, RbPlayer, RbDsp) are opaque reference()s freed by the GC — there is no explicit close.

Read metadata

Decode a file to PCM

decoder_next_chunk/1 hands back interleaved-stereo little-endian int16 PCM until it returns nil at end of track.
Seek before decoding more:
The codec state is process-wide — only one RbDecoder can decode at a time. decoder_open/1 blocks until any previous decoder is freed by the GC.

Run PCM through the DSP pipeline

Play a queue

A player owns a live audio device and a background engine thread; dropping the last reference to the handle stops playback.
The player exposes the same DSP chain as the standalone pipeline — player_set_eq_band/5, player_set_tone/5, player_set_crossfade/7, player_set_replaygain/4, player_set_balance/2 / player_balance/1, and more (see the module docs).

API

  • Handles (RbDecoder, RbDsp, RbPlayer) are NIF resources freed by the BEAM garbage collector — no explicit close.
  • PCM crosses the boundary as an int16 LE binary.
  • Rich values (*_json) come back as raw JSON binaries — decode with OTP 27’s built-in json module.
  • The DSP chain mirrors Rockbox’s own; see the official Rockbox sound-settings manual for what each control does.
The DSP and player use different ReplayGain mode integers: dsp_set_replaygain/40 track, 1 album, 2 shuffle, 3 off; player_set_replaygain/40 off, 1 track, 2 album. See the overview.

NIF delivery

The compiled NIF statically links the Rust librockbox_ffi.a, making it a multi-megabyte shared object — too large to bundle in a Hex tarball. So the Hex package ships only the checksum manifest, and rockbox_ffi_nif.erl’s -on_load hook downloads the matching rockbox_ffi_nif-<triple>.so from the named GitHub release into the user cache on first use, verifying it against the manifest sha256. Both the Elixir and Gleam bindings get their native code the same way. Prebuilt targets: aarch64-apple-darwin, x86_64-apple-darwin, aarch64-linux-gnu, x86_64-linux-gnu, x86_64-unknown-freebsd, x86_64-unknown-netbsd. Other platforms build from source.

Local development

Inside a full monorepo checkout (needs the Cargo workspace + include/ header):
The Elixir / Gleam bindings pick up this locally-built .so via a path dependency on ../erlang — the loader prefers a local priv/*.so over any cached download.

Docs

Read the published module docs at hexdocs.pm/rockbox_ffi_nif, or generate them locally with rebar3 ex_doc.