Class: Rocksky::RemotePlayer
- Inherits:
-
Object
- Object
- Rocksky::RemotePlayer
- Defined in:
- lib/rocksky/remote.rb
Overview
RemotePlayer — build a Rocksky-controllable player in a few lines.
It speaks the remote-control WebSocket protocol (see remote-ws/PROTOCOL.md) over the shared Rust core: it registers as a device, advertises what you're playing (now-playing / status / queue), and invokes your handlers when a miniplayer sends a command (play/pause/next/previous/seek/enqueue/queue actions). Heartbeat, reconnect, and the device-id handshake are handled for you inside the core.
Commands arrive over a blocking poll (#next_command). Register handlers with #on and call #listen to spawn a background thread that dispatches them, so you never write the loop yourself.
player = Rocksky::RemotePlayer.connect(token, "My Player")
player.on(:play) { engine.play }
player.on(:pause) { engine.pause }
player.on(:seek) { |cmd| engine.seek(cmd[:position]) }
player.listen
# …then, as your engine plays:
player.(title: "Chaser", artist: "Calibro 35",
durationMs: 182_320, elapsedMs: 0, isPlaying: true)
player.set_status("playing")
player.set_queue(items, 0)
Records (now-playing / queue items) are passed as Hashes with camelCase keys (title, artist, album, albumArtist, albumArt, durationMs, elapsedMs, isPlaying / songUri, albumUri, trackNumber), matching the wire record shape.
Class Method Summary collapse
-
.connect(token, name, url: nil) ⇒ Object
Connect and register a controllable player in the background.
Instance Method Summary collapse
-
#close ⇒ Object
Release the native handle.
-
#disconnect ⇒ Object
Disconnect and stop the background task.
-
#initialize(ptr) ⇒ RemotePlayer
constructor
A new instance of RemotePlayer.
-
#listen ⇒ Object
Spawn a background thread that polls #next_command and dispatches each command to its registered handler until the player disconnects.
-
#next_command ⇒ Object
Block until the next controller command, returned as a symbol-keyed Hash (e.g.
{ action: "play" }), ornilonce disconnected. -
#on(action, &block) ⇒ Object
Register a handler for a command action, one of
:play,:pause,:next,:previous,:seek,:queue_jump,:queue_remove,:enqueue. -
#set_now_playing(track) ⇒ Object
Advertise the currently-playing track.
-
#set_queue(items, index) ⇒ Object
Advertise the playback queue (+items+ is an array of camelCase queue-item Hashes) and the active
index. -
#set_status(status) ⇒ Object
Advertise transport state: "playing", "paused", or "stopped".
Constructor Details
#initialize(ptr) ⇒ RemotePlayer
Returns a new instance of RemotePlayer.
42 43 44 45 46 |
# File 'lib/rocksky/remote.rb', line 42 def initialize(ptr) @ptr = ptr @handlers = {} @thread = nil end |
Class Method Details
.connect(token, name, url: nil) ⇒ Object
Connect and register a controllable player in the background. token is a
Rocksky access token (JWT); name is the device-picker label; url
defaults to the public endpoint when omitted.
35 36 37 38 39 40 |
# File 'lib/rocksky/remote.rb', line 35 def self.connect(token, name, url: nil) ptr = C.rocksky_remote_player_connect(token.to_s, name.to_s, url.to_s) raise Error, (Rocksky.take_string(C.rocksky_last_error()) || "connect failed") if ptr.null? new(ptr) end |
Instance Method Details
#close ⇒ Object
Release the native handle. The player is unusable afterwards.
105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/rocksky/remote.rb', line 105 def close return if @ptr.null? # Stop the background task so a blocked #next_command returns nil and the # #listen loop exits, then WAIT for that thread to leave the native call # before freeing — freeing the handle while a poll is in flight is a # use-after-free (segfault). C.rocksky_remote_player_disconnect(@ptr) @thread&.join unless @thread == Thread.current @thread = nil C.rocksky_remote_player_free(@ptr) @ptr = Fiddle::Pointer.new(0) end |
#disconnect ⇒ Object
Disconnect and stop the background task. #next_command then returns nil, which ends the #listen thread. The handle stays valid until #close.
100 101 102 |
# File 'lib/rocksky/remote.rb', line 100 def disconnect Rocksky.unwrap(C.rocksky_remote_player_disconnect(@ptr)) end |
#listen ⇒ Object
Spawn a background thread that polls #next_command and dispatches each command to its registered handler until the player disconnects. Returns the Thread.
69 70 71 72 73 74 75 76 77 78 |
# File 'lib/rocksky/remote.rb', line 69 def listen @thread ||= Thread.new do loop do cmd = next_command break if cmd.nil? dispatch(cmd) end end end |
#next_command ⇒ Object
Block until the next controller command, returned as a symbol-keyed Hash
(e.g. { action: "play" }), or nil once disconnected.
59 60 61 62 63 64 |
# File 'lib/rocksky/remote.rb', line 59 def next_command return nil if @ptr.null? cmd = Rocksky.unwrap(C.rocksky_remote_player_next_command(@ptr)) cmd && Rocksky.symbolize(cmd) end |
#on(action, &block) ⇒ Object
Register a handler for a command action, one of :play, :pause, :next,
:previous, :seek, :queue_jump, :queue_remove, :enqueue. The block
receives the full symbol-keyed command Hash (e.g. +{ action: "seek",
position: 42000 }+). Returns self for chaining.
52 53 54 55 |
# File 'lib/rocksky/remote.rb', line 52 def on(action, &block) @handlers[action.to_sym] = block self end |
#set_now_playing(track) ⇒ Object
Advertise the currently-playing track. Call whenever it changes, and
periodically (~every 1–4s) with a fresh elapsedMs so controllers show
smooth progress. track is a camelCase Hash.
83 84 85 |
# File 'lib/rocksky/remote.rb', line 83 def (track) Rocksky.unwrap(C.(@ptr, JSON.generate(track))) end |
#set_queue(items, index) ⇒ Object
Advertise the playback queue (+items+ is an array of camelCase queue-item
Hashes) and the active index.
94 95 96 |
# File 'lib/rocksky/remote.rb', line 94 def set_queue(items, index) Rocksky.unwrap(C.rocksky_remote_player_set_queue(@ptr, JSON.generate(items), index)) end |