Implement MPD idling and Local Push support

Good day

For now MPD component is implemented as Local Poll device. But it is possible to get state updates using idle MPD command: https://pythonhosted.org/python-mpd2/topics/commands.html#MPDClient.idle.

In short, if idle command was sent to MPD server, then MPD disables any timeouts and keeps TCP socket opened. If there is any “noteworthy” change on server (like player stopped/started or playlist changed, whatever), then MPD sends a string like b'changed: player\nOK\n' to socket’s buffer.

At the same time any other command is prohibited in idle state. To perform any other command, idle must be canceled using noidle command. In response to noidle command server sends b'OK\n' string. And after that any other command can be sent and executed by server. If idle was not canceled, MPD closes TCP connection.

So, to implement idling and event-based status update for MPD component:

  1. Separated idle thread must be started
  2. Function in this thread must perform something like this (python-like pseudo-code):
def idle_thread():
    while True:
        event_idling_allowed.wait()  # wait until idling was allowed
        mpd.idle()   # block until some change happened
        if not idling_canceled:
            mpd.update_state()  # update state of the mpd client
  1. Any MPD command must perform something like this:
def send_command():
    event_idling_allowed.clear()  # disallow idle thread to start new loop iteration
    mpd.noidle()  # send `noidle` command to MPD server, cancel idling
    mpd.command()  # send some command to server
    event_idling_allowed.clear()  # allow idle thread to start new loop iteration

Or async libraries can be used.

For examples of implementation of MPD idling and event-based state updates, see this repository: https://github.com/s-kostyuk/sockets_samples/tree/devel/nih_mpd_lib

1 Like