Something went wrong. Try again.
A modern, network-enabled music player platform built on Rockbox technology. rockboxd.tsiry-sandratraina.com
rust deno navidrome airplay libadwaita zig mpris snapcast mpd rockbox audio subsonic
Something went wrong. Try again.
3.6 kB · 115 lines
TypeScript
at master
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116// Node.js backend + full API, using koffi for FFI. Import under Node:// import { Dsp, Player, metadata } from "rockbox-ffi/node";//// Node has no built-in FFI, so this backend depends on `koffi`// (https://koffi.dev) — install it with `npm install koffi`.
import { existsSync } from "node:fs";import { dirname, join } from "node:path";import { fileURLToPath } from "node:url";import { createRequire } from "node:module";
import { makeApi, sineStereo } from "./api.ts";import { platformLibName, platformPackageName, resolveLibPath, SPEC, type Raw, type Tok,} from "./ffi.ts";
// koffi ships as CommonJS; load it via require to keep ESM interop simple.const require = createRequire(import.meta.url);// deno-lint-ignore no-explicit-anyconst koffi: any = require("koffi");
/** Resolve the prebuilt binary from the per-platform npm package, if present. */function bundledLibPath(): string | undefined { try { const pkg = platformPackageName(process.platform, process.arch); return require.resolve(`${pkg}/${platformLibName(process.platform)}`); } catch { return undefined; }}
const TOK: Record<Tok, string> = { void: "void", ptr: "void *", u32: "uint32", i32: "int32", u64: "uint64", usize: "size_t", f32: "float", bool: "bool", strbuf: "str", // koffi marshals a JS string to a NUL-terminated char* i16in: "void *", // we pass a Buffer view of the Int16Array outsize: "void *", // we pass a Buffer.alloc(8) and read it back outu32: "void *", // we pass a Buffer.alloc(4) and read it back outi32: "void *", // we pass a Buffer.alloc(4) and read it back};
function makeRaw(): Raw { const here = dirname(fileURLToPath(import.meta.url)); const libPath = resolveLibPath( here, (k) => process.env[k], existsSync, join, dirname, bundledLibPath(), );
const lib = koffi.load(libPath); const sym: Record<string, (...a: any[]) => any> = {}; for (const [name, spec] of Object.entries(SPEC)) { sym[name] = lib.func(name, TOK[spec.ret], spec.args.map((t) => TOK[t])); }
return { sym, cstr(s: string) { // The `strbuf` params are typed "str"; koffi marshals the JS string. return s; }, i16in(a: Int16Array) { return Buffer.from(a.buffer, a.byteOffset, a.byteLength); }, sizeOut() { const buf = Buffer.alloc(8); return { arg: buf, value: () => Number(buf.readBigUInt64LE(0)) }; }, u32Out() { const buf = Buffer.alloc(4); return { arg: buf, value: () => buf.readUInt32LE(0) }; }, i32Out() { const buf = Buffer.alloc(4); return { arg: buf, value: () => buf.readInt32LE(0) }; }, takeString(p: unknown) { if (p === null || p === undefined) return null; // Read a NUL-terminated char* of unknown length. (koffi's "str" type // is unreliable for longer strings in 2.16 — this form is robust.) const str = koffi.decode(p, "char", -1) as string; sym.rb_string_free(p); return str; }, takeI16(p: unknown, len: number) { const arr = koffi.decode(p, koffi.array("int16_t", len)) as number[]; const copy = Int16Array.from(arr); sym.rb_buffer_free(p, len); return copy; }, isNull(p: unknown) { return p === null || p === undefined; }, };}
const api = makeApi(makeRaw());export const { abiVersion, metadata, Dsp, Decoder, Player, loadResume, m3uRead, m3uWrite, isUrl } = api;export { sineStereo };export * from "./enums.ts";export type { M3uEntry, Metadata, PlayerConfig, PlayerStatus, ResumeState } from "./types.ts";