mirror of
https://github.com/danbee/persephone
synced 2025-03-04 08:39:11 +00:00
MPDClient correctly sequences commands
In order to avoid getting disconnected from the server, it is necessary to send an "idle" command once you are connected. This tells the server that the client is going to wait for a status change message from the server. In the meantime if the client needs to send another command, it must first send "noidle", then send the command, then send "idle" once more. If the command results in a status change, the "idle" will return immediately, which must be dealt with and then the "idle" command must be sent once more. Phew!
This commit is contained in:
parent
ca55177c81
commit
c4cfd57d3d
@ -12,40 +12,93 @@ import mpdclient
|
|||||||
class MPDClient {
|
class MPDClient {
|
||||||
let HOST = "localhost"
|
let HOST = "localhost"
|
||||||
let PORT: UInt32 = 6600
|
let PORT: UInt32 = 6600
|
||||||
|
|
||||||
private let connection: OpaquePointer
|
private let connection: OpaquePointer
|
||||||
private var status: OpaquePointer?
|
private var status: OpaquePointer?
|
||||||
|
|
||||||
|
private let commandQueue = DispatchQueue(label: "commandQueue")
|
||||||
|
private var commandQueued = false
|
||||||
|
|
||||||
|
enum TransportCommand {
|
||||||
|
case prevTrack, nextTrack, playPause, stop
|
||||||
|
}
|
||||||
|
|
||||||
init?() {
|
init?() {
|
||||||
guard let connection = mpd_connection_new(HOST, PORT, 0)
|
guard let connection = mpd_connection_new(HOST, PORT, 0)
|
||||||
else { return nil }
|
else { return nil }
|
||||||
|
|
||||||
mpd_connection_set_keepalive(connection, true)
|
guard let status = mpd_run_status(connection)
|
||||||
|
else { return nil }
|
||||||
|
|
||||||
self.connection = connection
|
self.connection = connection
|
||||||
|
self.status = status
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
|
mpd_status_free(status)
|
||||||
mpd_connection_free(connection)
|
mpd_connection_free(connection)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getStatus() {
|
func fetchStatus() {
|
||||||
status = mpd_status_begin()
|
status = mpd_run_status(connection)
|
||||||
|
idle()
|
||||||
|
}
|
||||||
|
|
||||||
|
func getState() {
|
||||||
|
print(mpd_status_get_state(status))
|
||||||
|
idle()
|
||||||
}
|
}
|
||||||
|
|
||||||
func playPause() {
|
func playPause() {
|
||||||
mpd_run_toggle_pause(connection)
|
queueCommand(command: .playPause)
|
||||||
}
|
}
|
||||||
|
|
||||||
func stop() {
|
func stop() {
|
||||||
mpd_run_stop(connection)
|
queueCommand(command: .stop)
|
||||||
}
|
}
|
||||||
|
|
||||||
func prevTrack() {
|
func prevTrack() {
|
||||||
mpd_run_previous(connection)
|
queueCommand(command: .prevTrack)
|
||||||
}
|
}
|
||||||
|
|
||||||
func nextTrack() {
|
func nextTrack() {
|
||||||
mpd_run_next(connection)
|
queueCommand(command: .nextTrack)
|
||||||
|
}
|
||||||
|
|
||||||
|
func queueCommand(command: TransportCommand) {
|
||||||
|
commandQueued = true
|
||||||
|
noIdle()
|
||||||
|
commandQueue.async { [unowned self] in
|
||||||
|
self.sendCommand(command: command)
|
||||||
|
self.commandQueued = false
|
||||||
|
}
|
||||||
|
idle()
|
||||||
|
}
|
||||||
|
|
||||||
|
func sendCommand(command: TransportCommand) {
|
||||||
|
switch command {
|
||||||
|
case .prevTrack:
|
||||||
|
mpd_run_previous(connection)
|
||||||
|
case .nextTrack:
|
||||||
|
mpd_run_next(connection)
|
||||||
|
case .stop:
|
||||||
|
mpd_run_stop(connection)
|
||||||
|
case .playPause:
|
||||||
|
mpd_run_toggle_pause(connection)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func noIdle() {
|
||||||
|
mpd_send_noidle(connection)
|
||||||
|
}
|
||||||
|
|
||||||
|
func idle() {
|
||||||
|
commandQueue.async { [unowned self] in
|
||||||
|
mpd_send_idle(self.connection)
|
||||||
|
mpd_recv_idle(self.connection, true)
|
||||||
|
|
||||||
|
if !self.commandQueued { self.idle() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getLastErrorMessage() -> String! {
|
func getLastErrorMessage() -> String! {
|
||||||
|
|||||||
@ -20,8 +20,14 @@ class WindowController: NSWindowController {
|
|||||||
override func windowDidLoad() {
|
override func windowDidLoad() {
|
||||||
super.windowDidLoad()
|
super.windowDidLoad()
|
||||||
window?.titleVisibility = .hidden
|
window?.titleVisibility = .hidden
|
||||||
|
|
||||||
|
mpdInit()
|
||||||
|
}
|
||||||
|
|
||||||
|
func mpdInit() {
|
||||||
mpdClient = MPDClient()
|
mpdClient = MPDClient()
|
||||||
mpdClient?.getStatus()
|
mpdClient?.idle()
|
||||||
|
// let state = mpdClient?.getState()
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func handleTransportControl(_ sender: NSSegmentedControl) {
|
@IBAction func handleTransportControl(_ sender: NSSegmentedControl) {
|
||||||
@ -37,8 +43,6 @@ class WindowController: NSWindowController {
|
|||||||
mpdClient?.stop()
|
mpdClient?.stop()
|
||||||
case .nextTrack:
|
case .nextTrack:
|
||||||
mpdClient?.nextTrack()
|
mpdClient?.nextTrack()
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user