1INTRODUCTION 2============ 3This document is an attempt to describe the basics of the DTLS element. 4It hasn't been written by the author(s) and so, besides being incomplete, 5*IT MIGHT ALSO BE INCORRECT*. So take it with a pinch of salt. 6 7As always, if in doubt ask the #gstreamer IRC channel. 8 9THE INTERNALS 10============= 11This plugin provides two main elements (dtlssrtpdec and dtlssrtpenc) and a few 12minor elements necessary to implement them. The two elements dtlssrtpdec and 13dtlssrtpenc are the only ones you are supposed to include in, respectively, the 14RX and TX pipelines of your DTLS-enabled application. This means you're not 15supposed to directly include those minor elements in your pipelines. 16 17dtlssrtpenc 18----------- 19This element is to be included in the TX pipeline and will initiate the DTLS 20handshake if configured to be the client. Its main configuration parameters are: 21 22 - connection-id: a string that must match the connection-id in dtlssrtpdec; 23 - is-client: a boolean that indicates whether this is going to be the client 24 or the server during the DTLS handshake. 25 26Internally this element comprises the standard srtpenc element, the dtlsenc 27element and a funnel to connect both these elements to one single output. 28The srtpenc can be used to encrypt SRTP/SRTCP packets while the dtlsenc can be 29used to encrypt generic data, e.g. for non-SRTP applications. 30 31NB With the current implementation the TX pipeline containing the dtlssrtpenc 32 must be created *AFTER* the RX pipeline. 33 34dtlssrtpdec 35----------- 36It is to be included in the RX pipeline. Its main configuration parameters are: 37 38 - connection-id: a string that must match the connection-id in dtlssrtpenc; 39 - pem: a string that can be used to provide your own certificate *AND* private 40 key in PEM format. The private key is required to carry out the 41 handshake so do not forget it or the DTLS negotiation will fail; 42 - peer_pem: a read only parameter that can be used to retrieve the 43 certificate sent from the other party in PEM format once the 44 handshake is completed. 45 46Internally this element comprises a dtlssrtpdemux, a standard srtpdec element 47and the dtlsdec element. The dtlssrtpdemux element switches SRT(C)P packets to 48the srtpdec element and DTLS packets to the dtlsdec element and discards any 49other unknown packet. So, similarly for the dtlssrtpenc case, DTLS-SRTP 50applications would exercise the srtpdec element and any other non-SRTP 51application would exercise the dtlsdec element. 52 53NB With the current implementation the RX pipeline containing the dtlssrtpdec 54 must be created *BEFORE* the TX pipeline. 55 56EXAMPLE PIPELINE 57================ 58The following is an example usage of the DTLS plugin. It is a python script that 59creates two endpoints that exchange encrypted audio using DTLS to exchange the 60encryption keys. 61 62NB In theory we would show an example gst-launch command. However that would not 63 be enough because you need two pairs of TX/RX pipelines for a proper 64 handshake and you can't use gst-launch two start 4 different pipelines. 65 This why there is a python script in here. 66 67``` 68#!/usr/bin/env python3 69 70# create two endpoints, each with tx and rx pipelines using the DTLS 71# elements and let audio flowing for a while to give time for a packet capture 72 73import time 74from gi.repository import Gst, GObject, GLib 75GObject.threads_init() 76Gst.init(None) 77 78 79def _start_pipeline(pipeline): 80 pipeline.set_state(Gst.State.PLAYING) 81 pipeline.get_state(Gst.CLOCK_TIME_NONE) 82 83 84def _sleep_while_iterating_gloop(secs): 85 """ block for secs seconds but iterate the gloop while you do """ 86 for _ in range(10 * secs): 87 gloop = GLib.MainLoop() 88 gloop_context = gloop.get_context() 89 gloop_context.iteration(may_block=False) 90 time.sleep(0.1) 91 92def dtls_tx_pipeline_description(name, is_client, port): 93 return ' ! '.join([ 94 'audiotestsrc is-live=true', 95 'audio/x-raw, rate=8000, format=S16LE, channels=1', 96 'opusenc frame-size=10', 97 'rtpopuspay pt=103', 98 '.rtp_sink_0 dtlssrtpenc connection-id={name} is-client={client} .src', 99 'udpsink port={port}' 100 ]).format(name=name, client=is_client, port=port) 101 102 103def dtls_rx_pipeline_description(name, port): 104 return ' ! '.join([ 105 'udpsrc port={port}', 106 '.sink dtlssrtpdec connection-id={name} .rtp_src', 107 'queue', 108 'fakesink async=false' 109 ]).format(name=name, port=port) 110 111 112class Endpoint: 113 def __init__(self, name, is_client, tx_port, rx_port): 114 self.name = name 115 tx_pipeline_description = dtls_tx_pipeline_description( 116 name, is_client, tx_port 117 ) 118 rx_pipeline_description = dtls_rx_pipeline_description(name, rx_port) 119 print(rx_pipeline_description) 120 print(tx_pipeline_description) 121 122 self.rx_pipeline = Gst.parse_launch(rx_pipeline_description) 123 self.tx_pipeline = Gst.parse_launch(tx_pipeline_description) 124 125 def start(self): 126 # Start RX first, otherwise it fails due to the current implementation 127 self.start_rx_pipeline() 128 self.start_tx_pipeline() 129 130 def start_rx_pipeline(self): 131 _start_pipeline(self.rx_pipeline) 132 133 def start_tx_pipeline(self): 134 _start_pipeline(self.tx_pipeline) 135 136 def stop(self): 137 def stop_pipeline(p): 138 p.set_state(Gst.State.NULL) 139 p.get_state(Gst.CLOCK_TIME_NONE) 140 stop_pipeline(self.tx_pipeline) 141 stop_pipeline(self.rx_pipeline) 142 143blue = Endpoint("blue", is_client=True, tx_port=23000, rx_port=23002) 144red = Endpoint("red", is_client=False, tx_port=23002, rx_port=23000) 145 146red.start() 147blue.start() 148 149_sleep_while_iterating_gloop(3) 150 151red.stop() 152blue.stop() 153``` 154