mpv-player/mpv — pull request #1182 by ghedo (2014-10-14 08:27:22+00:00)
Title: WIP: JSON-based IPC

This is essentially an alternative to #693 with the main difference that it uses JSON as serialization format and it supports events (FWIW, I initially tried to adapt the other pr to support this, but in the end it would have taken me more time than just rewriting it from scratch).

It uses the [jansson](https://github.com/akheron/jansson) library to do JSON encoding and decoding, so that's a new optional dependency.

### Protocol

The communication protocol is really simple:
* Clients can execute commands by sending messages that look like this:
```json
{"command": "loadfile", "params": ["/some/file.mp3", "append"]}
```
the `params` field can contain mixed type arguments, for example:
```json
{"command": "set", "params": ["pause", true]}
{"command": "set", "params": ["volume", 30.0]}
```
* mpv will then answer with a message of the type:
```json
{"error": "success"}
```
with `error` set to "success" or an error string, and additional fields depending on the command. For example, to request the value of a property:
```json
{"command": "get_property", "params": ["volume"]}
{"data": 50.0, "error": "success"}
```
* mpv will also send events to the client with messages of the type:
```json
{"event": "tracks-changed"}
```
with `event` being the name of the event and additional fields depending on the event. For example, the property-change event:
```json
{"command": "observe_property", "params": [1, "volume"]}
{"error": "success"}
{"event": "property-change", "id": "script-input-dispatch", "name": "volume", "data": 52.0}
```
`\n` is used to terminate JSON messages, however, since `\n` is also a valid JSON character, the receiver concatenates all the messages received and tries to JSON-decode whenever a `\n` is found: if the parsing fails it keeps concatenating until the next `\n`, if it succeeds it executes the decoded command and resets the command string.

The main problem with this is that there's no way to differentiate between malformed JSON strings (that should be rejected) and truncated messages (which are used as described above). This means that if a malformed JSON string is received it will be concatenated to the command string which will always fail to decode until the client is restarted.

The simple solution may be to use a different terminator character (something not valid in JSON), but that would mean that humans couldn't manually input commands anymore (e.g. by using `socat(1)`), which would be a pity.

### Windows support

Right now the code uses `AF_UNIX` sockets and `mpv_get_wakeup_pipe()` so there's no way it works on Windows. This can probably be fixed by using named pipes on Windows (as in #693) and then starting 2 threads for each client (one receiving events from mpv, and the other receiving commands from the client). However, I don't have any Windows machine so I can 't really test this.

### Testing

You can manually test this by using `socat(1)` as follows:

```bash
$ mpv --ipc-path=~/.config/mpv/ipc some_file.mp3
```
and in another terminal:
```bash
$ socat unix-connect:$HOME/.config/mpv/ipc stdin
```
Then write commands as described above on the socat terminal, or wait for events to arrive (or both).

### Todo

There are a few thing missing, here's a tentative list:

- [ ] Protocol documentation
- [ ] Windows support (see above)
- [ ] More commands (suspend, resume, set_option, get_option, unobserve_property, request_event, request_log_messages, ...)
- [ ] More testing

Also, there are probably all kinds of weird bugs, memory leaks and security issues too, but it seems to work pretty well (as long as you don't feed it invalid JSON, or try to use it on Windows).