fairplay

06 July, 2023
3 min read

A year ago I traded my oligarchal home in suburban Johannesburg for Amsterdam's shoebox chic, In the midst of the new space constraints getting a big ol' TV just didn't make sense. However me and the mice in the apartment still need to be distracted from unfilled tax-forms and impending climate collapse.


The solution was to set-up a bussin' home-cinema system, having parted ways with my Rands for rental deposits, I sent for online market places and cob-webbed office basements. I found a second-hand projector, a bluetooth speaker and a Raspberry Pi 3 (with power supply issues) and to tie it all together I wrote a blazingly fast streaming library.


Software

For the software component I had to figure out how to get the devices to discover each other on the network, similar to how you can see other apple devices when you try to airdrop a file. I also wanted to figure out how to programmatically capture the screen and stream it and finally I thought it was a good excuse to use a bit of rust.

Discovery

mDNS is a protocol for service discovery on local networks, it's what allows you to see all the printers connected to your WiFi.

Browsing for a device with mDNS works by broadcasting a DNS lookup for a service type, for example _airdrop._tcp.local or fairplay._tcp.local to all device on your network, similar to how you would look up a domain name like google.com, mDNS is similar in that any device that knows of a airdrop._tcp.local service will respond with it's IP address.

Video Streaming

The capture is done using a library called scrap ,which uses the OS's windowing system [1] to capture frames, effectively taking a screenshot of the screen in a loop.

The reciever is a simple TCP server that listens for connections and writes the frames to a ffplay process, which is a command line tool for playing video.

Demo


So at 1FPS on the reciever it's actually blazingly slow (sorry r/rust), this might have something to do with pumping 7meg raw video frames over tcp and iterating over them on the cpu [2], but in all honestly the mice haven't been complaining.

Wrapping Up

Fun stuff

  • mDNS
    • on mac you can run dns-sd -B _airdrop._tcp local to see all the airdrop devices on your network
  • rust x networking
    • language makes it comfortable to deal with OS level structs (threads, sockets and byte arrays) without feeling the need for a higher level abstraction
  • dealing with video
    • learn't about encodings (didn't use any of it)
    • it's cool seeing your bugs result in contorted rick astleys stretching across the screen

Un-fun stuff

  • cross platform things
    • compiling for linux without x11 is a pain
    • difference in padding of frames between intel and m1 macs

Footnotes

  1. [1] On linux it uses x11, which meant I couldn't compile the binary for linux with out x11, so I split the project into two modules, one for the server and one for reciever.
  2. [2] The goal wasn't to try write my own streaming protocol, there's already HLS, RTSP, WebRTC etc.
  3. [3] Source code is https://github.com/phxtho/fairplay