1
1
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:
Daniel Barber 2019-01-26 19:25:45 -05:00
parent ca55177c81
commit c4cfd57d3d
Signed by: danbarber
GPG Key ID: 931D8112E0103DD8
2 changed files with 67 additions and 10 deletions

View File

@ -12,40 +12,93 @@ import mpdclient
class MPDClient {
let HOST = "localhost"
let PORT: UInt32 = 6600
private let connection: OpaquePointer
private var status: OpaquePointer?
private let commandQueue = DispatchQueue(label: "commandQueue")
private var commandQueued = false
enum TransportCommand {
case prevTrack, nextTrack, playPause, stop
}
init?() {
guard let connection = mpd_connection_new(HOST, PORT, 0)
else { return nil }
mpd_connection_set_keepalive(connection, true)
guard let status = mpd_run_status(connection)
else { return nil }
self.connection = connection
self.status = status
}
deinit {
mpd_status_free(status)
mpd_connection_free(connection)
}
func getStatus() {
status = mpd_status_begin()
func fetchStatus() {
status = mpd_run_status(connection)
idle()
}
func getState() {
print(mpd_status_get_state(status))
idle()
}
func playPause() {
mpd_run_toggle_pause(connection)
queueCommand(command: .playPause)
}
func stop() {
mpd_run_stop(connection)
queueCommand(command: .stop)
}
func prevTrack() {
mpd_run_previous(connection)
queueCommand(command: .prevTrack)
}
func nextTrack() {
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! {

View File

@ -20,8 +20,14 @@ class WindowController: NSWindowController {
override func windowDidLoad() {
super.windowDidLoad()
window?.titleVisibility = .hidden
mpdInit()
}
func mpdInit() {
mpdClient = MPDClient()
mpdClient?.getStatus()
mpdClient?.idle()
// let state = mpdClient?.getState()
}
@IBAction func handleTransportControl(_ sender: NSSegmentedControl) {
@ -37,8 +43,6 @@ class WindowController: NSWindowController {
mpdClient?.stop()
case .nextTrack:
mpdClient?.nextTrack()
default:
break
}
}
}