Dugan Chen's Homepage

Various Things

I’m starting to write a reactive MPD client library for PyQt.

The Music Player Daemon commonly known as MPD targets Linux, runs as a daemon, requires you to set a port number, and allows clients to connect to it and send it commands. The commands are plain text: you can connect to the daemon via telnet and send it commands from there.

Now, if you have any knowledge of socket-level programming at all, you will have deduced that all a client needs to do is open a socket and then send and receive. You send the command and then you receive the results. Furthermore the commands always consist of a line starting with the actual command, followed by its parameters. So why not just use blocking sockets, and wrap the sends and receives in method calls? For example, a status() method would write “statusn” to the socket, immediately do a receive, and then return what’s sent back. This is, in fact, exactly what almost all MPD client libraries do.

Where does this abstraction start to leak? It starts with the idle and noidle commands, which were introduced to MPD long after any client library that I can think of was designed. If you send the server an idle command, then it will wait until there was a change in the server’s state (for example, a playlist being saved) before sending back any output. During this time, the only command that the server would accept on that socket is noidle, which cancels the wait. You could be waiting indefinitely. And if you do it with the synchronous code that most MPD libraries were written with, then your program will freeze indefinitely.

There are ways around this. You could use multiple threads, as I did in the first released version of Quetzalcoatl. If the library provides access to the underlying sockets, you could use mechanisms like select to manipulate them and get the asynchronous behavior you need (see this python-mpd example). Personally, I think it would be better to use a client library which is designed to be used asynchronously in the first place. And because Quetzalcoatl uses Qt, I want it to be integrated with Qt’s event loop.

Today, I started work on an asynchronous MPD client library for PyQt. It will encapsulate Qt’s QTcpSocket and QLocalSocket classes, which are optimized for use with the framework, and will make heavy use of signals and slots. Do I have any code to show? Not yet; I do not believe that I can do better than all of my predecessors after only half a day of work. Suffice to say, however, that the next version of Quetzalcoatl will not have python-mpd as a dependency.