An embedded audio product built with Swift

Admittedly, a slight bending of the truth here – we are using embedded Swift, not Embedded Swift, and there's no Swift (yet) in the realtime code. But the vast majority of code is the control plane, which is almost all Swift, save for the UI which is a thin stateless wrapper written in Flutter.

Much of it is open source and permissively licensed:

  • Integration between Flutter and Swift on eLinux, iOS, macOS and Android
  • OCA (AES70) implementation
  • SRP (802.1q) implementation
  • Swift wrappers for L-Acoustics’ AVDECC library
  • ocacli command line tool for navigating and scripting OCA
  • io_uring and I2C/SPI/UART integration with Swift's structured concurrency
  • patches for building Swift 6 packages under Yocto
  • Swift Java support for Android (WIP)
  • Swift Logging integration with both systemd and Android native logging

More technical details: we are using Swift 6.0.2 built as part of a custom Yocto distribution, on a Raspberry Pi CM4. Realtime processing happens on an XMOS XE232. There is also a Brooklyn 3, Marvell switch chip, a bunch of DACs, op amps, etc...

22 Likes

Great to see this, got a question: what percentage of the lines of code you/PADL wrote for this product would you estimate was in Swift?

You should submit an official Swift blog post proposal about the development of your product in Swift, would make for interesting reading. :smiley:

2 Likes

I’ll do a proper analysis but I reckon it’s at least 75%. I wrote very little new C code bar the real time audio code.

2 Likes

OK, noting that this is not SLOC, but just wc, and counts new code written by me specifically for this project (i.e. excluding many C and C++ libraries that are wrapped in Swift):

  • C and XC: 16%
  • C++: 4%
  • Swift: 75%
  • Dart: 5%
2 Likes

Not quite the latest UI but, a snapshot of it running (left, clockwise) on embedded Linux, iOS, macOS and Android (in emulators, of course).

3 Likes

This is super cool! Love your work @lukeh keep it up!

1 Like

Started to do a bit of profiling on this as, whilst the CM4 is fairly hefty as far as embedded systems are concerned, it's no Apple Silicon.

Biggest performance sink was dealing with metering information coming from other MCUs onboard, which is at a fairly slow rate of 10Hz (well, was 30Hz, but I slowed it down). We are using Codable to implement the serialisation of the control protocol (OCP.1, part of AES70), and Codable is slooooow. More specifically, it's the Swift runtime cost (checking for protocol conformance). This also impacted some other errors where we were, for example, using protocol conformance to check whether a particular event was a metering event or not. Hand-rolling some of the serialisation code and also using more efficient checks elsewhere reduced CPU usage considerably.

The other culprit was malloc() in ContiguousArrayBuffer as used by AsyncChannel. Curtailing the use of AsyncChannel also improved things.

3 Likes

Yeah, another (non-)shout out for Codable. It's very handy but doesn't belong in a hot path like metering. Replacing it with hand-coded serialisation for the PDU encapsulation and metering resulted in an order of magnitude improvement. Thanks, perf!

1 Like