Class: Rocksky::RemoteController
- Inherits:
-
Object
- Object
- Rocksky::RemoteController
- Defined in:
- lib/rocksky/remote.rb
Overview
RemoteController — build a Rocksky remote UI in a few lines.
The other half of the remote-control WebSocket protocol: where RemotePlayer is a controllable player, a controller lists the user's players, observes what each is playing (now-playing / status / queue), picks the primary device, and sends commands. Heartbeat, reconnect, and the register handshake are handled for you inside the core.
Events arrive over a blocking poll (#next_event). Register handlers with #on and call #listen to spawn a background dispatch thread.
controller = Rocksky::RemoteController.connect(token, "My Controller")
controller.on(:devices) { |e| render(e[:devices]) }
controller.on(:now_playing) { |e| show_track(e[:deviceId], e[:track]) }
controller.listen
# …then drive a device:
controller.set_primary(device_id)
controller.pause(device_id)
controller.seek(device_id, 42_000)
A nil / omitted target broadcasts a command to all of the user's devices.
Class Method Summary collapse
-
.connect(token, name, url: nil) ⇒ Object
Connect and register a controller in the background.
Instance Method Summary collapse
-
#close ⇒ Object
Release the native handle.
-
#command(action, target = nil) ⇒ Object
Send a simple command ("play" | "pause" | "next" | "previous").
-
#disconnect ⇒ Object
Disconnect and stop the background task.
-
#enqueue(target, tracks, mode: "now", shuffle: false, start_index: 0) ⇒ Object
Enqueue
tracks(array of camelCase queue-item Hashes) ontarget. -
#initialize(ptr) ⇒ RemoteController
constructor
A new instance of RemoteController.
-
#listen ⇒ Object
Spawn a background thread that polls #next_event and dispatches each event to its registered handler until the controller disconnects.
- #next(target = nil) ⇒ Object
-
#next_event ⇒ Object
Block until the next update, returned as a symbol-keyed Hash (each carries a
:type), ornilonce disconnected. -
#on(event_type, &block) ⇒ Object
Register a handler for a server event type, one of
:devices,:device_registered,:device_unregistered,:primary_changed,:now_playing,:status,:queue. - #pause(target = nil) ⇒ Object
-
#play(target = nil) ⇒ Object
play. - #previous(target = nil) ⇒ Object
-
#queue_jump(target, index) ⇒ Object
Jump to
indexin +target+'s queue (nil target = broadcast). -
#queue_remove(target, index) ⇒ Object
Remove queue item
indexontarget(nil target = broadcast). -
#seek(target, position_ms) ⇒ Object
Seek
targettoposition_ms(nil target = broadcast). -
#set_primary(device_id) ⇒ Object
Choose the primary (scrobble/profile) device.
Constructor Details
#initialize(ptr) ⇒ RemoteController
Returns a new instance of RemoteController.
158 159 160 161 162 |
# File 'lib/rocksky/remote.rb', line 158 def initialize(ptr) @ptr = ptr @handlers = {} @thread = nil end |
Class Method Details
.connect(token, name, url: nil) ⇒ Object
Connect and register a controller in the background. url defaults to the
public endpoint when omitted.
151 152 153 154 155 156 |
# File 'lib/rocksky/remote.rb', line 151 def self.connect(token, name, url: nil) ptr = C.rocksky_remote_controller_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 controller is unusable afterwards.
253 254 255 256 257 258 259 260 261 262 263 264 265 |
# File 'lib/rocksky/remote.rb', line 253 def close return if @ptr.null? # Stop the background task so a blocked #next_event 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_controller_disconnect(@ptr) @thread&.join unless @thread == Thread.current @thread = nil C.rocksky_remote_controller_free(@ptr) @ptr = Fiddle::Pointer.new(0) end |
#command(action, target = nil) ⇒ Object
Send a simple command ("play" | "pause" | "next" | "previous").
219 220 221 |
# File 'lib/rocksky/remote.rb', line 219 def command(action, target = nil) Rocksky.unwrap(C.rocksky_remote_controller_command(@ptr, action.to_s, target.to_s)) end |
#disconnect ⇒ Object
Disconnect and stop the background task. #next_event then returns nil, which ends the #listen thread. The handle stays valid until #close.
248 249 250 |
# File 'lib/rocksky/remote.rb', line 248 def disconnect Rocksky.unwrap(C.rocksky_remote_controller_disconnect(@ptr)) end |
#enqueue(target, tracks, mode: "now", shuffle: false, start_index: 0) ⇒ Object
Enqueue tracks (array of camelCase queue-item Hashes) on target. mode
is "now" | "next" | "last"; nil target = broadcast.
240 241 242 243 244 |
# File 'lib/rocksky/remote.rb', line 240 def enqueue(target, tracks, mode: "now", shuffle: false, start_index: 0) Rocksky.unwrap(C.rocksky_remote_controller_enqueue( @ptr, target.to_s, JSON.generate(tracks), mode.to_s, shuffle ? 1 : 0, start_index )) end |
#listen ⇒ Object
Spawn a background thread that polls #next_event and dispatches each event to its registered handler until the controller disconnects. Returns the Thread.
185 186 187 188 189 190 191 192 193 194 |
# File 'lib/rocksky/remote.rb', line 185 def listen @thread ||= Thread.new do loop do ev = next_event break if ev.nil? dispatch(ev) end end end |
#next(target = nil) ⇒ Object
210 211 212 |
# File 'lib/rocksky/remote.rb', line 210 def next(target = nil) command("next", target) end |
#next_event ⇒ Object
Block until the next update, returned as a symbol-keyed Hash (each carries a
:type), or nil once disconnected.
175 176 177 178 179 180 |
# File 'lib/rocksky/remote.rb', line 175 def next_event return nil if @ptr.null? ev = Rocksky.unwrap(C.rocksky_remote_controller_next_event(@ptr)) ev && Rocksky.symbolize(ev) end |
#on(event_type, &block) ⇒ Object
Register a handler for a server event type, one of :devices,
:device_registered, :device_unregistered, :primary_changed,
:now_playing, :status, :queue. The block receives the full
symbol-keyed event Hash. Returns self for chaining.
168 169 170 171 |
# File 'lib/rocksky/remote.rb', line 168 def on(event_type, &block) @handlers[event_type.to_sym] = block self end |
#pause(target = nil) ⇒ Object
206 207 208 |
# File 'lib/rocksky/remote.rb', line 206 def pause(target = nil) command("pause", target) end |
#play(target = nil) ⇒ Object
play. target is a device id, or omit/nil to broadcast to all devices.
202 203 204 |
# File 'lib/rocksky/remote.rb', line 202 def play(target = nil) command("play", target) end |
#previous(target = nil) ⇒ Object
214 215 216 |
# File 'lib/rocksky/remote.rb', line 214 def previous(target = nil) command("previous", target) end |
#queue_jump(target, index) ⇒ Object
Jump to index in +target+'s queue (nil target = broadcast).
229 230 231 |
# File 'lib/rocksky/remote.rb', line 229 def queue_jump(target, index) Rocksky.unwrap(C.rocksky_remote_controller_queue_jump(@ptr, target.to_s, index)) end |
#queue_remove(target, index) ⇒ Object
Remove queue item index on target (nil target = broadcast).
234 235 236 |
# File 'lib/rocksky/remote.rb', line 234 def queue_remove(target, index) Rocksky.unwrap(C.rocksky_remote_controller_queue_remove(@ptr, target.to_s, index)) end |