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
- on mac you can run
- 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] 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] The goal wasn't to try write my own streaming protocol, there's already HLS, RTSP, WebRTC etc.
- [3] Source code is https://github.com/phxtho/fairplay