IEEE 1722, AVB, and PCs

related: avb , audio , work , networking

We’re playing around with Audio/Video Bridging (AVB) at work, the new, unfinished IEEE standards for sending high-priority, high-fidelity audio over an ethernet network.

There isn’t much info about it yet, and we’ve had to pick through demos and unfinished specs and all sorts of wrong information. 

We have demo boards from XMOS and DSP4YOU that stream audio to each other over the network.  One of the questions we were investigating is: what can a PC do with AVB?  The spec basically doesn’t allow for them, and it’s generally assumed that a PC cannot be an endpoint.  There’s just no way a non-real-time OS can handle the strict timing requirements (IEEE 1722AS), or get the latency low enough (2ms end-to-end for Class A AVB), without hardware assistance.

However, I have been testing out ‘sniffing’ the AVB traffic with a PC.  I originally tried writing an OS X kernel extension (kext), but ran into a strange problem.  AVB packets are a special case of a VLAN (802.1Q), and the frickin’ OS X kernel doesn’t pass VLAN packets to Kernel Interface Filters.  In a bizarre twist, though, VLAN packets are accessible in user space through the Berkeley Packet Filter API… but they aren’t available in kernel space.  Go figure.

Anyway, I wrote a sniffer in user-space that uses BPF to filter and process AVB packets.  I can play them in near-real-time with PortAudio, and record them to a file with libsndfile.  Hooking PortAudio up to SoundFlower lets me pass them off to GarageBand, where I can use AU plugins to modify the sound.  The delay probably blows the AVB spec, but my untrained ear can’t hear it.

Lookin’ good:

$ ./avbsniffer
Device 0: Built-in Microphone
Device 1: Built-in Input
Device 2: Built-in Output
Device 3: Soundflower (2ch)
Device 4: Soundflower (16ch)
Using device 2
Buflen: 524288
Filled AVB buffer!
Recieved: 2006388
Dropped: 0
Drop rate: 0.00%
Total packets: 1000000
Skipped packets: 0 (0.000000%)

No source code for this one, but I’ll give you my BPF filter to extract an AVB packet:

struct bpf_insn insns[] = {
  BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12), // load short from 12-bytes into packet (vlan tag)
  BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x8100, 0, 3), // Exit if not VLAN packet (pkt[12] == 0x8100)
  BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 16), // load short from 16-bytes into packet (ethertype)
  BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x22F0, 0, 1), // Exit if not AVB packet (pkt[16] == 0x22F0)
  BPF_STMT(BPF_RET+BPF_K, AVB_PKT_SIZE), // Accept AVB packet!
  BPF_STMT(BPF_RET+BPF_K, 0), // Refuse packet ("accept 0 bytes")