Skip to content

Getting started

roon-internal-api is the TypeScript side of this experiment. It lives in the roon-internal-api/ directory of the repo. It’s not published to npm — use it from a clone. Expect rough edges; this is a proof-of-concept.

Terminal window
git clone https://github.com/arthursoares/roon-api-reverse-engineering
cd roon-api-reverse-engineering/roon-internal-api
npm install
npx tsc --noEmit # type-check
npx jest # the small test suite

Two values identify your Core. They aren’t secrets (there’s no auth here), but they’re specific to your install, so supply your own rather than copying mine:

ValueWhat it isHow to find it
hostCore IP / hostnameRoon → Settings → About, or your router
serverBrokerId16-byte Core id (hex)read it off a capture of the handshake — see Contributing

The RoonClient facade is the front door. A minimal, read-only program (placeholders below — swap in your own values):

import { RoonClient } from 'roon-internal-api'; // or '../src/proto/client' in-repo
const roon = new RoonClient({
host: process.env.ROON_HOST!, // e.g. '192.168.1.50'
serverBrokerId: Buffer.from(process.env.ROON_BROKER_ID!, 'hex'), // 16-byte hex
});
await roon.connect();
console.log('Library oid:', roon.serviceOid('Library').toString());
console.log('Zone oid:', roon.zoneByName('Living Room')?.toString());
const album = roon.findByTitle('AlbumLite', 'Kind of Blue');
console.log(album ? `found, oid=${album.oid}` : 'not loaded');
roon.close();

Run it with npx ts-node examples/demo.ts (set ROON_HOST).

On connect() the client does the handshake, resolves the root service, and starts ingesting the streaming object graph — so zones, devices, now-playing, and loaded library content are queryable via the helpers below. How reliable this is beyond my own setup, I genuinely don’t know.

MethodPurpose
connect() / close()open / close the session
serviceOid(name)object id of a singleton service ('Library', 'Transport'…)
zoneByName(name) / endpointByName(name)resolve a zone / endpoint oid
findByTitle(type, title)find a loaded object by title (e.g. 'AlbumLite')
titleOf(obj)best-effort display title of an object
call(service, method, params, args, oid?)low-level escape hatch to any method
structArg(typeName, fields)build a by-val struct argument

For doing things — favorites, playback, edits, search — see Recipes. For the full generated method surface, see the generated API.