1 /* GStreamer
2 * Copyright (C) 2018 Matthew Waters <matthew@centricular.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #endif
23
24 #include <stdio.h>
25
26 #include "sctptransport.h"
27 #include "gstwebrtcbin.h"
28
29 #define GST_CAT_DEFAULT gst_webrtc_sctp_transport_debug
30 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
31
32 enum
33 {
34 SIGNAL_0,
35 ON_RESET_STREAM_SIGNAL,
36 LAST_SIGNAL,
37 };
38
39 enum
40 {
41 PROP_0,
42 PROP_TRANSPORT,
43 PROP_STATE,
44 PROP_MAX_MESSAGE_SIZE,
45 PROP_MAX_CHANNELS,
46 };
47
48 static guint gst_webrtc_sctp_transport_signals[LAST_SIGNAL] = { 0 };
49
50 #define gst_webrtc_sctp_transport_parent_class parent_class
51 G_DEFINE_TYPE_WITH_CODE (GstWebRTCSCTPTransport, gst_webrtc_sctp_transport,
52 GST_TYPE_OBJECT, GST_DEBUG_CATEGORY_INIT (gst_webrtc_sctp_transport_debug,
53 "webrtcsctptransport", 0, "webrtcsctptransport"););
54
55 typedef void (*SCTPTask) (GstWebRTCSCTPTransport * sctp, gpointer user_data);
56
57 struct task
58 {
59 GstWebRTCSCTPTransport *sctp;
60 SCTPTask func;
61 gpointer user_data;
62 GDestroyNotify notify;
63 };
64
65 static void
_execute_task(GstWebRTCBin * webrtc,struct task * task)66 _execute_task (GstWebRTCBin * webrtc, struct task *task)
67 {
68 if (task->func)
69 task->func (task->sctp, task->user_data);
70 }
71
72 static void
_free_task(struct task * task)73 _free_task (struct task *task)
74 {
75 gst_object_unref (task->sctp);
76
77 if (task->notify)
78 task->notify (task->user_data);
79 g_free (task);
80 }
81
82 static void
_sctp_enqueue_task(GstWebRTCSCTPTransport * sctp,SCTPTask func,gpointer user_data,GDestroyNotify notify)83 _sctp_enqueue_task (GstWebRTCSCTPTransport * sctp, SCTPTask func,
84 gpointer user_data, GDestroyNotify notify)
85 {
86 struct task *task = g_new0 (struct task, 1);
87
88 task->sctp = gst_object_ref (sctp);
89 task->func = func;
90 task->user_data = user_data;
91 task->notify = notify;
92
93 gst_webrtc_bin_enqueue_task (sctp->webrtcbin,
94 (GstWebRTCBinFunc) _execute_task, task, (GDestroyNotify) _free_task);
95 }
96
97 static void
_emit_stream_reset(GstWebRTCSCTPTransport * sctp,gpointer user_data)98 _emit_stream_reset (GstWebRTCSCTPTransport * sctp, gpointer user_data)
99 {
100 guint stream_id = GPOINTER_TO_UINT (user_data);
101
102 g_signal_emit (sctp,
103 gst_webrtc_sctp_transport_signals[ON_RESET_STREAM_SIGNAL], 0, stream_id);
104 }
105
106 static void
_on_sctp_dec_pad_removed(GstElement * sctpdec,GstPad * pad,GstWebRTCSCTPTransport * sctp)107 _on_sctp_dec_pad_removed (GstElement * sctpdec, GstPad * pad,
108 GstWebRTCSCTPTransport * sctp)
109 {
110 guint stream_id;
111
112 if (sscanf (GST_PAD_NAME (pad), "src_%u", &stream_id) != 1)
113 return;
114
115 _sctp_enqueue_task (sctp, (SCTPTask) _emit_stream_reset,
116 GUINT_TO_POINTER (stream_id), NULL);
117 }
118
119 static void
_on_sctp_association_established(GstElement * sctpenc,gboolean established,GstWebRTCSCTPTransport * sctp)120 _on_sctp_association_established (GstElement * sctpenc, gboolean established,
121 GstWebRTCSCTPTransport * sctp)
122 {
123 GST_OBJECT_LOCK (sctp);
124 if (established)
125 sctp->state = GST_WEBRTC_SCTP_TRANSPORT_STATE_CONNECTED;
126 else
127 sctp->state = GST_WEBRTC_SCTP_TRANSPORT_STATE_CLOSED;
128 sctp->association_established = established;
129 GST_OBJECT_UNLOCK (sctp);
130
131 g_object_notify (G_OBJECT (sctp), "state");
132 }
133
134 static void
gst_webrtc_sctp_transport_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)135 gst_webrtc_sctp_transport_set_property (GObject * object, guint prop_id,
136 const GValue * value, GParamSpec * pspec)
137 {
138 // GstWebRTCSCTPTransport *sctp = GST_WEBRTC_SCTP_TRANSPORT (object);
139
140 switch (prop_id) {
141 default:
142 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
143 break;
144 }
145 }
146
147 static void
gst_webrtc_sctp_transport_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)148 gst_webrtc_sctp_transport_get_property (GObject * object, guint prop_id,
149 GValue * value, GParamSpec * pspec)
150 {
151 GstWebRTCSCTPTransport *sctp = GST_WEBRTC_SCTP_TRANSPORT (object);
152
153 switch (prop_id) {
154 case PROP_TRANSPORT:
155 g_value_set_object (value, sctp->transport);
156 break;
157 case PROP_STATE:
158 g_value_set_enum (value, sctp->state);
159 break;
160 case PROP_MAX_MESSAGE_SIZE:
161 g_value_set_uint64 (value, sctp->max_message_size);
162 break;
163 case PROP_MAX_CHANNELS:
164 g_value_set_uint (value, sctp->max_channels);
165 break;
166 default:
167 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
168 break;
169 }
170 }
171
172 static void
gst_webrtc_sctp_transport_finalize(GObject * object)173 gst_webrtc_sctp_transport_finalize (GObject * object)
174 {
175 GstWebRTCSCTPTransport *sctp = GST_WEBRTC_SCTP_TRANSPORT (object);
176
177 g_signal_handlers_disconnect_by_data (sctp->sctpdec, sctp);
178 g_signal_handlers_disconnect_by_data (sctp->sctpenc, sctp);
179
180 gst_object_unref (sctp->sctpdec);
181 gst_object_unref (sctp->sctpenc);
182
183 g_clear_object (&sctp->transport);
184
185 G_OBJECT_CLASS (parent_class)->finalize (object);
186 }
187
188 static void
gst_webrtc_sctp_transport_constructed(GObject * object)189 gst_webrtc_sctp_transport_constructed (GObject * object)
190 {
191 GstWebRTCSCTPTransport *sctp = GST_WEBRTC_SCTP_TRANSPORT (object);
192 guint association_id;
193
194 association_id = g_random_int_range (0, G_MAXUINT16);
195
196 sctp->sctpdec =
197 g_object_ref_sink (gst_element_factory_make ("sctpdec", NULL));
198 g_object_set (sctp->sctpdec, "sctp-association-id", association_id, NULL);
199 sctp->sctpenc =
200 g_object_ref_sink (gst_element_factory_make ("sctpenc", NULL));
201 g_object_set (sctp->sctpenc, "sctp-association-id", association_id, NULL);
202
203 g_signal_connect (sctp->sctpdec, "pad-removed",
204 G_CALLBACK (_on_sctp_dec_pad_removed), sctp);
205 g_signal_connect (sctp->sctpenc, "sctp-association-established",
206 G_CALLBACK (_on_sctp_association_established), sctp);
207
208 G_OBJECT_CLASS (parent_class)->constructed (object);
209 }
210
211 static void
gst_webrtc_sctp_transport_class_init(GstWebRTCSCTPTransportClass * klass)212 gst_webrtc_sctp_transport_class_init (GstWebRTCSCTPTransportClass * klass)
213 {
214 GObjectClass *gobject_class = (GObjectClass *) klass;
215
216 gobject_class->constructed = gst_webrtc_sctp_transport_constructed;
217 gobject_class->get_property = gst_webrtc_sctp_transport_get_property;
218 gobject_class->set_property = gst_webrtc_sctp_transport_set_property;
219 gobject_class->finalize = gst_webrtc_sctp_transport_finalize;
220
221 g_object_class_install_property (gobject_class,
222 PROP_TRANSPORT,
223 g_param_spec_object ("transport",
224 "WebRTC DTLS Transport",
225 "DTLS transport used for this SCTP transport",
226 GST_TYPE_WEBRTC_DTLS_TRANSPORT,
227 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
228
229 g_object_class_install_property (gobject_class,
230 PROP_STATE,
231 g_param_spec_enum ("state",
232 "WebRTC SCTP Transport state", "WebRTC SCTP Transport state",
233 GST_TYPE_WEBRTC_SCTP_TRANSPORT_STATE,
234 GST_WEBRTC_SCTP_TRANSPORT_STATE_NEW,
235 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
236
237 g_object_class_install_property (gobject_class,
238 PROP_MAX_MESSAGE_SIZE,
239 g_param_spec_uint64 ("max-message-size",
240 "Maximum message size",
241 "Maximum message size as reported by the transport", 0, G_MAXUINT64,
242 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
243
244 g_object_class_install_property (gobject_class,
245 PROP_MAX_CHANNELS,
246 g_param_spec_uint ("max-channels",
247 "Maximum number of channels", "Maximum number of channels",
248 0, G_MAXUINT16, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
249
250 /**
251 * GstWebRTCSCTPTransport::reset-stream:
252 * @object: the #GstWebRTCSCTPTransport
253 * @stream_id: the SCTP stream that was reset
254 */
255 gst_webrtc_sctp_transport_signals[ON_RESET_STREAM_SIGNAL] =
256 g_signal_new ("stream-reset", G_TYPE_FROM_CLASS (klass),
257 G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_generic,
258 G_TYPE_NONE, 1, G_TYPE_UINT);
259 }
260
261 static void
gst_webrtc_sctp_transport_init(GstWebRTCSCTPTransport * nice)262 gst_webrtc_sctp_transport_init (GstWebRTCSCTPTransport * nice)
263 {
264 }
265
266 GstWebRTCSCTPTransport *
gst_webrtc_sctp_transport_new(void)267 gst_webrtc_sctp_transport_new (void)
268 {
269 return g_object_new (GST_TYPE_WEBRTC_SCTP_TRANSPORT, NULL);
270 }
271