AVTP Audio Format (AAF) Plugin ============================== Overview -------- The AAF plugin is a PCM plugin that uses Audio Video Transport Protocol (AVTP) to transmit/receive audio samples through a Time-Sensitive Network (TSN) capable network. The plugin enables media applications to easily implement AVTP Talker and Listener functionalities. AVTP is designed to take advantage of generalized Precision Time Protocol (gPTP) and Forwarding and Queuing Enhancements for Time-Sensitive Streams (FQTSS). gPTP ensures AVTP talkers and listeners share the same time reference so the presentation time from AVTP can be used to inform when PCM samples should be presented to the application layer. FQTSS provides bandwidth reservation and traffic prioritization for the AVTP stream. gPTP functionality is provided by the Linuxptp project while FQTSS functionality is provided by Linux Traffic Control system since kernel version 4.15. gPTP Setup ---------- The Linuxptp project provides the ptp4l daemon, which synchronizes the PTP clock from NIC, and the pmc tool which communicates with ptp4l to get/set some runtime settings. The project also provides the phc2sys daemon which synchronizes the PTP clock and system clock. The AAF Plugin requires system clock is synchronized with PTP clock and TAI offset is properly set in the kernel. ptp4l and phc2sys can be set up in many different ways, below we provide an example that fullfils the plugin requirements. For further information check ptp4l(8) and phc2sys(8). In the following instructions, replace $IFNAME by your PTP capable NIC interface. The gPTP.cfg file mentioned below can be found in /usr/share/ doc/linuxptp/ (depending on your distro). Synchronize PTP clock with PTP time: $ ptp4l -f gPTP.cfg -i $IFNAME Enable TAI offset to be automatically set by phc2sys: $ pmc -u -t 1 -b 0 'SET GRANDMASTER_SETTINGS_NP \ clockClass 248 clockAccuracy 0xfe \ offsetScaledLogVariance 0xffff \ currentUtcOffset 37 leap61 0 leap59 0 \ currentUtcOffsetValid 1 pTimescale 1 \ timeTraceable 1 frequencyTraceable 0 timeSource 0xa0' Synchronize system clock with PTP clock: $ phc2sys -f gPTP.cfg -s $IFNAME -c CLOCK_REALTIME -w The commands above should be run on both AVTP Talker and Listener hosts. Traffic Control Setup --------------------- The Linux Traffic Control system provides the mqprio and cbs qdiscs which enable FQTSS on Linux. Below we provide an example to configure those qdiscs in order to transmit an AAF stream with the following features: class A, 6 audio frames per AVTPDU, 48 kHz sampling rate, 16-bit sample size, stereo. For further information on how to configure these qdiscs check tc-mqprio(8) and tc-cbs(8) man pages. On the host that will run as AVTP Talker (i.e. plugin in playback mode), run the following commands: Configure mpqrio qdisc (replace $MQPRIO_HANDLE_ID by an unused handle ID): $ tc qdisc add dev $IFNAME parent root handle $MQPRIO_HANDLE_ID \ mqprio num_tc 3 map 2 2 1 0 2 2 2 2 2 2 2 2 2 2 2 2 \ queues 1@0 1@1 2@2 hw 0 Configure cbs qdisc (replace $CBS_HANDLE_ID by an unused handle ID): $ tc qdisc replace dev $IFNAME parent $MQPRIO_HANDLE_ID:1 \ handle $CBS_HANDLE_ID cbs idleslope 5760 \ sendslope -994240 hicredit 9 locredit -89 offload 1 The plugin implements a transmission mechanism that relies on ETF qdisc so make sure it is properly configured in the system. It could be configured many way, below follows an example. $ tc qdisc add dev $IFNAME parent $CBS_HANDLE_ID:1 etf \ clockid CLOCK_TAI delta 500000 offload No Traffic Control configuration is required at the host running as AVTP Listener. Plugin Dependencies ------------------- The AAF plugin uses libavtp to handle AVTP packetization. Libavtp source code can be found in https://github.com/AVnu/libavtp as well as instructions to build and install it. The plugin also depends on some kernel API headers such as linux/if_ether.h so make sure you have them installed in your system. If libavtp or the kernel headers aren't detected by configure, the plugin isn't built. Plugin Configuration -------------------- The plugin parameters are passed via ALSA configuration file. They are defined as follows: * ifname: Network interface used to transmit/receive AVTP packets. * addr: Stream destination MAC address. * prio: Priority used by the plugin to transmit AVTP traffic. This option is relevant only when operating in playback mode. * streamid: Stream ID associated with the AAF stream transmitted or received by the plugin. * mtt: Maximum Transit Time (in microseconds) as defined in AVTP spec section 4.3.3. This option is relevant only when operating in playback mode. * time_uncertainty: Maximum Time Uncertainty (in microseconds) as defined by AVTP spec section 4.3.3. This option is relevant only when operating in playback mode. * frames_per_pdu: Number of audio frames transmitted in one AVTPDU. * ptime_tolerance: Presentation time tolerance in microseconds. AVTPDUs with presentation time off by +- ptime_tolerance are not considered invalid. This option is relevant only when operating in capture mode. Plugin Usage ------------ The plugin provides the PCM type "aaf". Configure an AAF PCM virtual device according to the AAF stream you want to transmit or receive. A hypothetical configuration for the stream described in the 'FQTSS Setup' section is shown below: pcm.aaf0 { type aaf ifname eth0 addr 01:AA:AA:AA:AA:AA prio 3 streamid AA:BB:CC:DD:EE:FF:0000 mtt 2000 time_uncertainty 125 frames_per_pdu 6 ptime_tolerance 100 } Put the above to ~/.asoundrc (or /etc/asound.conf), and use the AAF PCM virtual device 'aaf0' with your favorite alsa-utils tool. Note that the plugin requires the period size is multiple of the 'frames_per_pdu' configuration. For example, to stream the pink noise generated by 'speaker-test', run: $ speaker-test -F S16_BE -c 2 -r 48000 -D aaf0 -p 12500 To receive the AAF stream generated by the command above, run the following command in another host: $ arecord -t raw -f S16_BE -c 2 -r 48000 -D aaf0 -vv /dev/null -F 12500 If you want to playback the contents of the AAF stream, change the command-line above so the output from 'arecord' is redirected to 'aplay', or simply use the 'alsaloop' tool.