1 /*
2 * GStreamer AVTP Plugin
3 * Copyright (C) 2019 Intel Corporation
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later
9 * version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301 USA
20 */
21
22 /**
23 * plugin-avtp:
24 *
25 * ## Audio Video Transport Protocol (AVTP) Plugin
26 *
27 * The AVTP plugin implements typical Talker and Listener functionalities that
28 * can be leveraged by GStreamer-based applications in order to implement TSN
29 * audio/video applications.
30 *
31 * ### Dependencies
32 *
33 * The plugin uses libavtp to handle AVTP packetization. Libavtp source code can
34 * be found in https://github.com/AVnu/libavtp as well as instructions to build
35 * and install it.
36 *
37 * If libavtp isn't detected by configure, the plugin isn't built.
38 *
39 * ### The application/x-avtp mime type
40 *
41 * For valid AVTPDUs encapsulated in GstBuffers, we use the caps with mime type
42 * application/x-avtp.
43 *
44 * AVTP mime type is pretty simple and has no fields.
45 *
46 * ### gPTP Setup
47 *
48 * The Linuxptp project provides the ptp4l daemon, which synchronizes the PTP
49 * clock from NIC, and the pmc tool which communicates with ptp4l to get/set
50 * some runtime settings. The project also provides the phc2sys daemon which
51 * synchronizes the PTP clock and system clock.
52 *
53 * The AVTP plugin requires system clock is synchronized with PTP clock and
54 * TAI offset is properly set in the kernel. ptp4l and phc2sys can be set up
55 * in many different ways, below we provide an example that fullfils the plugin
56 * requirements. For further information check ptp4l(8) and phc2sys(8).
57 *
58 * In the following instructions, replace $IFNAME by your PTP capable NIC
59 * interface. The gPTP.cfg file mentioned below can be found in /usr/share/
60 * doc/linuxptp/ (depending on your distro).
61 *
62 * Synchronize PTP clock with PTP time:
63 *
64 * $ ptp4l -f gPTP.cfg -i $IFNAME
65 *
66 * Enable TAI offset to be automatically set by phc2sys:
67 *
68 * $ pmc -u -t 1 -b 0 'SET GRANDMASTER_SETTINGS_NP \
69 * clockClass 248 clockAccuracy 0xfe \
70 * offsetScaledLogVariance 0xffff \
71 * currentUtcOffset 37 leap61 0 leap59 0 \
72 * currentUtcOffsetValid 1 ptpTimescale 1 \
73 * timeTraceable 1 frequencyTraceable 0 timeSource 0xa0'
74 *
75 * Synchronize system clock with PTP clock:
76 *
77 * $ phc2sys -f gPTP.cfg -s $IFNAME -c CLOCK_REALTIME -w
78 *
79 * The commands above should be run on both AVTP Talker and Listener hosts.
80 *
81 * With clocks properly synchronized, applications using the AVTP plugin
82 * should use GstSytemClock with GST_CLOCK_TYPE_REALTIME as the pipeline
83 * clock.
84 *
85 * ### Clock Reference Format (CRF)
86 *
87 * Even though the systems are synchronized by PTP, it is possible that
88 * different talkers can send media streams which are out of phase or the
89 * frequencies do not exactly match. This is partcularly important when there
90 * is a single listener processing data from multiple talkers. The systems in
91 * this scenario can benefit if a common clock is distributed among the
92 * systems.
93 *
94 * This can be achieved by using the avtpcrfsync element which implements CRF
95 * as described in Chapter 10 of IEEE 1722-2016. avtpcrfcheck can also be used
96 * to validate that the adjustment conforms to the criteria specified in the
97 * spec. For further details, look at the documentation for the respective
98 * elements.
99 *
100 * ### Traffic Control Setup
101 *
102 * FQTSS (Forwarding and Queuing Enhancements for Time-Sensitive Streams) can be
103 * enabled on Linux with the help of the mqprio and cbs qdiscs provided by the
104 * Linux Traffic Control. Below we provide an example to configure those qdiscs
105 * in order to transmit a CVF H.264 stream 1280x720@30fps. For further
106 * information on how to configure these qdiscs check tc-mqprio(8) and
107 * tc-cbs(8) man pages.
108 *
109 * On the host that will run as AVTP Talker (pipeline that generates the video
110 * stream), run the following commands:
111 *
112 * Configure mpqrio qdisc (replace $MQPRIO_HANDLE_ID by an unused handle ID):
113 *
114 * $ tc qdisc add dev $IFNAME parent root handle $MQPRIO_HANDLE_ID mqprio \
115 * num_tc 3 map 2 2 1 0 2 2 2 2 2 2 2 2 2 2 2 2 \
116 * queues 1@0 1@1 2@2 hw 0
117 *
118 * Configure cbs qdisc (replace $CBS_HANDLE_ID by an unused handle ID):
119 *
120 * $ tc qdisc replace dev $IFNAME parent $MQPRIO_HANDLE_ID:1 \
121 * handle $CBS_HANDLE_ID cbs idleslope 27756 sendslope -972244 \
122 * hicredit 42 locredit -1499 offload 1
123 *
124 * Also, the plugin implements a transmission scheduling mechanism that relies
125 * on ETF qdisc so make sure it is properly configured in your system. It could
126 * be configured in many ways, below follows an example.
127 *
128 * $ tc qdisc add dev $IFNAME parent $CBS_HANDLE_ID:1 etf \
129 * clockid CLOCK_TAI delta 500000 offload
130 *
131 * No Traffic Control configuration is required at the host running as AVTP
132 * Listener.
133 *
134 * ### Capabilities
135 *
136 * The `avtpsink` and `avtpsrc` elements open `AF_PACKET` sockets, which require
137 * `CAP_NET_RAW` capability. Also, `avtpsink` needs `CAP_NET_ADMIN` to use ETF.
138 * Therefore, applications must have those capabilities in order to successfully
139 * use these elements. For instance, one can use:
140 *
141 * $ sudo setcap cap_net_raw,cap_net_admin+ep <application>
142 *
143 * Applications can drop these capabilities after the sockets are open, after
144 * `avtpsrc` or `avtpsink` elements transition to PAUSED state. See setcap(8)
145 * man page for more information.
146 *
147 * ### Elements configuration
148 *
149 * Each element has its own configuration properties, with some being common
150 * to several elements. Basic properties are:
151 *
152 * * streamid (avtpaafpay, avtpcvfpay, avtpaafdepay, avtpcvfdepay,
153 * avtpcrfsync, avtpcrfcheck): Stream ID associated with the stream.
154 *
155 * * ifname (avtpsink, avtpsrc, avtpcrfsync, avtpcrfcheck): Network interface
156 * used to send/receive AVTP packets.
157 *
158 * * dst-macaddr (avtpsink, avtpsrc): Destination MAC address for the stream.
159 *
160 * * priority (avtpsink): Priority used by the plugin to transmit AVTP
161 * traffic.
162 *
163 * * mtt (avtpaafpay, avtpcvfpay): Maximum Transit Time, in nanoseconds, as
164 * defined in AVTP spec.
165 *
166 * * tu (avtpaafpay, avtpcvfpay): Maximum Time Uncertainty, in nanoseconds, as
167 * defined in AVTP spec.
168 *
169 * * processing-deadline (avtpaafpay, avtpcvfpay, avtpsink): Maximum amount of
170 * time, in nanoseconds, that the pipeline is expected to process any
171 * buffer. This value should be in sync between the one used on the
172 * payloader and the sink, as this time is also taken into consideration to
173 * define the correct presentation time of the packets on the AVTP listener
174 * side. It should be as low as possible (zero if possible).
175 *
176 * * timestamp-mode (avtpaafpay): AAF timestamping mode, as defined in AVTP spec.
177 *
178 * * mtu (avtpcvfpay): Maximum Transmit Unit of the underlying network, used
179 * to determine when to fragment a CVF packet and how big it should be.
180 *
181 * Check each element documentation for more details.
182 *
183 *
184 * ### Running a sample pipeline
185 *
186 * The following pipelines uses debugutilsbad "clockselect" element to force
187 * the pipeline clock to be GstPtpClock. A real application would
188 * programmatically define GstPtpClock as the pipeline clock (see next section).
189 * It is also assumes that `gst-launch-1.0` has CAP_NET_RAW and CAP_NET_ADMIN
190 * capabilities.
191 *
192 * On the AVTP talker, the following pipeline can be used to generate an H.264
193 * stream to be sent via network using AVTP:
194 *
195 * $ gst-launch-1.0 clockselect. \( clockid=ptp \
196 * videotestsrc is-live=true ! clockoverlay ! x264enc ! \
197 * avtpcvfpay processing-deadline=20000000 ! \
198 * avtpcrfsync ifname=$IFNAME ! avtpsink ifname=$IFNAME \)
199 *
200 * On the AVTP listener host, the following pipeline can be used to get the
201 * AVTP stream, depacketize it and show it on the screen:
202 *
203 * $ gst-launch-1.0 clockselect. \( clockid=ptp avtpsrc ifname=$IFNAME ! \
204 * avtpcrfcheck ifname=$IFNAME ! avtpcvfdepay ! \
205 * vaapih264dec ! videoconvert ! clockoverlay halignment=right ! \
206 * queue ! autovideosink \)
207 *
208 * ### Pipeline clock
209 *
210 * The AVTP plugin elements require that the pipeline clock is in sync with
211 * the network PTP clock. As GStreamer has a GstPtpClock, using it should be
212 * the simplest way of achieving that.
213 *
214 * However, as there's no way of forcing a clock to a pipeline using
215 * gst-launch-1.0 application, even for quick tests, it's necessary to have
216 * an application. One can refer to GStreamer "hello world" application,
217 * remembering to set the pipeline clock to GstPtpClock before putting the
218 * pipeline on "PLAYING" state. Some code like:
219 *
220 * GstClock *clk = gst_ptp_clock_new("ptp-clock", 0);
221 * gst_clock_wait_for_sync(clk, GST_CLOCK_TIME_NONE);
222 * gst_pipeline_use_clock (GST_PIPELINE (pipeline), clk);
223 *
224 * Would do the trick.
225 *
226 * ### Disclaimer
227 *
228 * It's out of scope for the AVTP plugin to verify how it is invoked, should
229 * a malicious software do it for Denial of Service attempts, or other
230 * compromises attempts.
231 *
232 * Since: 1.18
233 */
234 #ifdef HAVE_CONFIG_H
235 #include <config.h>
236 #endif
237
238 #include <gst/gst.h>
239
240 #include "gstavtpaafdepay.h"
241 #include "gstavtpaafpay.h"
242 #include "gstavtpcvfdepay.h"
243 #include "gstavtpcvfpay.h"
244 #include "gstavtpsink.h"
245 #include "gstavtpsrc.h"
246 #include "gstavtpcrfsync.h"
247 #include "gstavtpcrfcheck.h"
248
249 static gboolean
plugin_init(GstPlugin * plugin)250 plugin_init (GstPlugin * plugin)
251 {
252 gboolean ret = FALSE;
253
254 ret |= GST_ELEMENT_REGISTER (avtpaafpay, plugin);
255 ret |= GST_ELEMENT_REGISTER (avtpaafdepay, plugin);
256 ret |= GST_ELEMENT_REGISTER (avtpsink, plugin);
257 ret |= GST_ELEMENT_REGISTER (avtpsrc, plugin);
258 ret |= GST_ELEMENT_REGISTER (avtpcvfpay, plugin);
259 ret |= GST_ELEMENT_REGISTER (avtpcvfdepay, plugin);
260 ret |= GST_ELEMENT_REGISTER (avtpcrfsync, plugin);
261 ret |= GST_ELEMENT_REGISTER (avtpcrfcheck, plugin);
262
263 return ret;
264 }
265
266 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR,
267 avtp, "Audio/Video Transport Protocol (AVTP) plugin",
268 plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
269