111 lines
8.2 KiB
Plaintext
111 lines
8.2 KiB
Plaintext
#import "Basic";
|
|
|
|
// Build the C library first (only .so — Jai links dynamically, which pulls in libsystemd automatically):
|
|
// cc -fPIC -shared -o linux/libmpris.so mpris.c -lsystemd
|
|
libmpris :: #library "linux/libmpris";
|
|
|
|
/* ── Types ──────────────────────────────────────────────────────────────── */
|
|
|
|
Mpris_Player :: *void;
|
|
|
|
// Callbacks must be #c_call. Pass your context pointer as userdata.
|
|
Mpris_Callback :: #type (userdata: *void) -> void #c_call;
|
|
Mpris_Seek_Callback :: #type (offset_us: s64, userdata: *void) -> void #c_call;
|
|
Mpris_Set_Position_Callback :: #type (track_id: *u8, position_us: s64, userdata: *void) -> void #c_call;
|
|
Mpris_Volume_Callback :: #type (volume: float64, userdata: *void) -> void #c_call;
|
|
|
|
/* ── Raw C bindings ─────────────────────────────────────────────────────── */
|
|
|
|
_mpris_player_create :: (player_name: *u8, identity: *u8) -> Mpris_Player #foreign libmpris "mpris_player_create";
|
|
_mpris_player_destroy :: (p: Mpris_Player) #foreign libmpris "mpris_player_destroy";
|
|
_mpris_set_playback_status :: (p: Mpris_Player, status: *u8) #foreign libmpris "mpris_set_playback_status";
|
|
_mpris_set_metadata :: (p: Mpris_Player, track_id: *u8, title: *u8, artist: *u8, album: *u8, length_us: s64) #foreign libmpris "mpris_set_metadata";
|
|
_mpris_set_position :: (p: Mpris_Player, position_us: s64) #foreign libmpris "mpris_set_position";
|
|
_mpris_set_volume :: (p: Mpris_Player, volume: float64) #foreign libmpris "mpris_set_volume";
|
|
_mpris_set_can_go_next :: (p: Mpris_Player, value: s32) #foreign libmpris "mpris_set_can_go_next";
|
|
_mpris_set_can_go_previous :: (p: Mpris_Player, value: s32) #foreign libmpris "mpris_set_can_go_previous";
|
|
_mpris_set_can_play :: (p: Mpris_Player, value: s32) #foreign libmpris "mpris_set_can_play";
|
|
_mpris_set_can_pause :: (p: Mpris_Player, value: s32) #foreign libmpris "mpris_set_can_pause";
|
|
_mpris_set_can_seek :: (p: Mpris_Player, value: s32) #foreign libmpris "mpris_set_can_seek";
|
|
_mpris_emit_seeked :: (p: Mpris_Player, position_us: s64) #foreign libmpris "mpris_emit_seeked";
|
|
_mpris_on_play :: (p: Mpris_Player, cb: Mpris_Callback, userdata: *void) #foreign libmpris "mpris_on_play";
|
|
_mpris_on_pause :: (p: Mpris_Player, cb: Mpris_Callback, userdata: *void) #foreign libmpris "mpris_on_pause";
|
|
_mpris_on_play_pause :: (p: Mpris_Player, cb: Mpris_Callback, userdata: *void) #foreign libmpris "mpris_on_play_pause";
|
|
_mpris_on_stop :: (p: Mpris_Player, cb: Mpris_Callback, userdata: *void) #foreign libmpris "mpris_on_stop";
|
|
_mpris_on_next :: (p: Mpris_Player, cb: Mpris_Callback, userdata: *void) #foreign libmpris "mpris_on_next";
|
|
_mpris_on_previous :: (p: Mpris_Player, cb: Mpris_Callback, userdata: *void) #foreign libmpris "mpris_on_previous";
|
|
_mpris_on_seek :: (p: Mpris_Player, cb: Mpris_Seek_Callback, userdata: *void) #foreign libmpris "mpris_on_seek";
|
|
_mpris_on_set_position :: (p: Mpris_Player, cb: Mpris_Set_Position_Callback, userdata: *void) #foreign libmpris "mpris_on_set_position";
|
|
_mpris_on_volume :: (p: Mpris_Player, cb: Mpris_Volume_Callback, userdata: *void) #foreign libmpris "mpris_on_volume";
|
|
_mpris_process :: (p: Mpris_Player) -> s32 #foreign libmpris "mpris_process";
|
|
|
|
/* ── Jai-friendly wrappers (handle string conversion) ───────────────────── */
|
|
|
|
// player_name: D-Bus name component, no spaces (e.g. "MyPlayer")
|
|
// identity: Human-readable name shown in media menus (e.g. "My Music Player")
|
|
mpris_player_create :: (player_name: string, identity: string) -> Mpris_Player {
|
|
n := temp_c_string(player_name);
|
|
i := temp_c_string(identity);
|
|
return _mpris_player_create(n, i);
|
|
}
|
|
|
|
mpris_player_destroy :: (p: Mpris_Player) {
|
|
_mpris_player_destroy(p);
|
|
}
|
|
|
|
// status: "Playing" | "Paused" | "Stopped"
|
|
mpris_set_playback_status :: (p: Mpris_Player, status: string) {
|
|
_mpris_set_playback_status(p, temp_c_string(status));
|
|
}
|
|
|
|
Mpris_Metadata :: struct {
|
|
track_id : string; // D-Bus object path, e.g. "/myapp/track/42". Leave empty for auto.
|
|
title : string;
|
|
artist : string;
|
|
album : string;
|
|
length_us : s64; // Duration in microseconds. 0 = unknown.
|
|
}
|
|
|
|
mpris_set_metadata :: (p: Mpris_Player, meta: Mpris_Metadata) {
|
|
tid := ifx meta.track_id then temp_c_string(meta.track_id) else null;
|
|
t := ifx meta.title then temp_c_string(meta.title) else null;
|
|
a := ifx meta.artist then temp_c_string(meta.artist) else null;
|
|
al := ifx meta.album then temp_c_string(meta.album) else null;
|
|
_mpris_set_metadata(p, tid, t, a, al, meta.length_us);
|
|
}
|
|
|
|
mpris_set_position :: (p: Mpris_Player, position_us: s64) {
|
|
_mpris_set_position(p, position_us);
|
|
}
|
|
|
|
mpris_set_volume :: (p: Mpris_Player, volume: float64) {
|
|
_mpris_set_volume(p, volume);
|
|
}
|
|
|
|
mpris_set_can_go_next :: (p: Mpris_Player, v: bool) { _mpris_set_can_go_next(p, cast(s32) ifx v then 1 else 0); }
|
|
mpris_set_can_go_previous :: (p: Mpris_Player, v: bool) { _mpris_set_can_go_previous(p, cast(s32) ifx v then 1 else 0); }
|
|
mpris_set_can_play :: (p: Mpris_Player, v: bool) { _mpris_set_can_play(p, cast(s32) ifx v then 1 else 0); }
|
|
mpris_set_can_pause :: (p: Mpris_Player, v: bool) { _mpris_set_can_pause(p, cast(s32) ifx v then 1 else 0); }
|
|
mpris_set_can_seek :: (p: Mpris_Player, v: bool) { _mpris_set_can_seek(p, cast(s32) ifx v then 1 else 0); }
|
|
|
|
mpris_emit_seeked :: (p: Mpris_Player, position_us: s64) {
|
|
_mpris_emit_seeked(p, position_us);
|
|
}
|
|
|
|
mpris_on_play :: (p: Mpris_Player, cb: Mpris_Callback, ud: *void) { _mpris_on_play(p, cb, ud); }
|
|
mpris_on_pause :: (p: Mpris_Player, cb: Mpris_Callback, ud: *void) { _mpris_on_pause(p, cb, ud); }
|
|
mpris_on_play_pause :: (p: Mpris_Player, cb: Mpris_Callback, ud: *void) { _mpris_on_play_pause(p, cb, ud); }
|
|
mpris_on_stop :: (p: Mpris_Player, cb: Mpris_Callback, ud: *void) { _mpris_on_stop(p, cb, ud); }
|
|
mpris_on_next :: (p: Mpris_Player, cb: Mpris_Callback, ud: *void) { _mpris_on_next(p, cb, ud); }
|
|
mpris_on_previous :: (p: Mpris_Player, cb: Mpris_Callback, ud: *void) { _mpris_on_previous(p, cb, ud); }
|
|
mpris_on_seek :: (p: Mpris_Player, cb: Mpris_Seek_Callback, ud: *void) { _mpris_on_seek(p, cb, ud); }
|
|
mpris_on_set_position :: (p: Mpris_Player, cb: Mpris_Set_Position_Callback, ud: *void) { _mpris_on_set_position(p, cb, ud); }
|
|
mpris_on_volume :: (p: Mpris_Player, cb: Mpris_Volume_Callback, ud: *void) { _mpris_on_volume(p, cb, ud); }
|
|
|
|
// Returns true if messages were processed, false if idle, exits on error.
|
|
mpris_process :: (p: Mpris_Player) -> bool {
|
|
r := _mpris_process(p);
|
|
if r < 0 { log_error("mpris_process failed: %", r); return false; }
|
|
return r > 0;
|
|
}
|