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 "webrtcsctptransport.h"
27 #include "gstwebrtcbin.h"
28
29 #define GST_CAT_DEFAULT webrtc_sctp_transport_debug
30 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
31
32 enum
33 {
34 SIGNAL_0,
35 ON_STREAM_RESET_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 webrtc_sctp_transport_signals[LAST_SIGNAL] = { 0 };
49
50 #define webrtc_sctp_transport_parent_class parent_class
51 G_DEFINE_TYPE_WITH_CODE (WebRTCSCTPTransport, webrtc_sctp_transport,
52 GST_TYPE_WEBRTC_SCTP_TRANSPORT,
53 GST_DEBUG_CATEGORY_INIT (webrtc_sctp_transport_debug,
54 "webrtcsctptransport", 0, "webrtcsctptransport"););
55
56 typedef void (*SCTPTask) (WebRTCSCTPTransport * sctp, gpointer user_data);
57
58 struct task
59 {
60 WebRTCSCTPTransport *sctp;
61 SCTPTask func;
62 gpointer user_data;
63 GDestroyNotify notify;
64 };
65
66 static GstStructure *
_execute_task(GstWebRTCBin * webrtc,struct task * task)67 _execute_task (GstWebRTCBin * webrtc, struct task *task)
68 {
69 if (task->func)
70 task->func (task->sctp, task->user_data);
71 return NULL;
72 }
73
74 static void
_free_task(struct task * task)75 _free_task (struct task *task)
76 {
77 gst_object_unref (task->sctp);
78
79 if (task->notify)
80 task->notify (task->user_data);
81 g_free (task);
82 }
83
84 static void
_sctp_enqueue_task(WebRTCSCTPTransport * sctp,SCTPTask func,gpointer user_data,GDestroyNotify notify)85 _sctp_enqueue_task (WebRTCSCTPTransport * sctp, SCTPTask func,
86 gpointer user_data, GDestroyNotify notify)
87 {
88 struct task *task = g_new0 (struct task, 1);
89
90 task->sctp = gst_object_ref (sctp);
91 task->func = func;
92 task->user_data = user_data;
93 task->notify = notify;
94
95 gst_webrtc_bin_enqueue_task (sctp->webrtcbin,
96 (GstWebRTCBinFunc) _execute_task, task, (GDestroyNotify) _free_task,
97 NULL);
98 }
99
100 static void
_emit_stream_reset(WebRTCSCTPTransport * sctp,gpointer user_data)101 _emit_stream_reset (WebRTCSCTPTransport * sctp, gpointer user_data)
102 {
103 guint stream_id = GPOINTER_TO_UINT (user_data);
104
105 g_signal_emit (sctp,
106 webrtc_sctp_transport_signals[ON_STREAM_RESET_SIGNAL], 0, stream_id);
107 }
108
109 static void
_on_sctp_dec_pad_removed(GstElement * sctpdec,GstPad * pad,WebRTCSCTPTransport * sctp)110 _on_sctp_dec_pad_removed (GstElement * sctpdec, GstPad * pad,
111 WebRTCSCTPTransport * sctp)
112 {
113 guint stream_id;
114
115 if (sscanf (GST_PAD_NAME (pad), "src_%u", &stream_id) != 1)
116 return;
117
118 _sctp_enqueue_task (sctp, (SCTPTask) _emit_stream_reset,
119 GUINT_TO_POINTER (stream_id), NULL);
120 }
121
122 static void
_on_sctp_association_established(GstElement * sctpenc,gboolean established,WebRTCSCTPTransport * sctp)123 _on_sctp_association_established (GstElement * sctpenc, gboolean established,
124 WebRTCSCTPTransport * sctp)
125 {
126 GST_OBJECT_LOCK (sctp);
127 if (established)
128 sctp->state = GST_WEBRTC_SCTP_TRANSPORT_STATE_CONNECTED;
129 else
130 sctp->state = GST_WEBRTC_SCTP_TRANSPORT_STATE_CLOSED;
131 sctp->association_established = established;
132 GST_OBJECT_UNLOCK (sctp);
133
134 g_object_notify (G_OBJECT (sctp), "state");
135 }
136
137 void
webrtc_sctp_transport_set_priority(WebRTCSCTPTransport * sctp,GstWebRTCPriorityType priority)138 webrtc_sctp_transport_set_priority (WebRTCSCTPTransport * sctp,
139 GstWebRTCPriorityType priority)
140 {
141 GstPad *pad;
142
143 pad = gst_element_get_static_pad (sctp->sctpenc, "src");
144 gst_pad_push_event (pad,
145 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM_STICKY,
146 gst_structure_new ("GstWebRtcBinUpdateTos", "sctp-priority",
147 GST_TYPE_WEBRTC_PRIORITY_TYPE, priority, NULL)));
148 gst_object_unref (pad);
149 }
150
151 static void
webrtc_sctp_transport_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)152 webrtc_sctp_transport_get_property (GObject * object, guint prop_id,
153 GValue * value, GParamSpec * pspec)
154 {
155 WebRTCSCTPTransport *sctp = WEBRTC_SCTP_TRANSPORT (object);
156
157 switch (prop_id) {
158 case PROP_TRANSPORT:
159 g_value_set_object (value, sctp->transport);
160 break;
161 case PROP_STATE:
162 g_value_set_enum (value, sctp->state);
163 break;
164 case PROP_MAX_MESSAGE_SIZE:
165 g_value_set_uint64 (value, sctp->max_message_size);
166 break;
167 case PROP_MAX_CHANNELS:
168 g_value_set_uint (value, sctp->max_channels);
169 break;
170 default:
171 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
172 break;
173 }
174 }
175
176 static void
webrtc_sctp_transport_finalize(GObject * object)177 webrtc_sctp_transport_finalize (GObject * object)
178 {
179 WebRTCSCTPTransport *sctp = WEBRTC_SCTP_TRANSPORT (object);
180
181 g_signal_handlers_disconnect_by_data (sctp->sctpdec, sctp);
182 g_signal_handlers_disconnect_by_data (sctp->sctpenc, sctp);
183
184 gst_object_unref (sctp->sctpdec);
185 gst_object_unref (sctp->sctpenc);
186
187 g_clear_object (&sctp->transport);
188
189 G_OBJECT_CLASS (parent_class)->finalize (object);
190 }
191
192 static void
webrtc_sctp_transport_constructed(GObject * object)193 webrtc_sctp_transport_constructed (GObject * object)
194 {
195 WebRTCSCTPTransport *sctp = WEBRTC_SCTP_TRANSPORT (object);
196 guint association_id;
197
198 association_id = g_random_int_range (0, G_MAXUINT16);
199
200 sctp->sctpdec =
201 g_object_ref_sink (gst_element_factory_make ("sctpdec", NULL));
202 g_object_set (sctp->sctpdec, "sctp-association-id", association_id, NULL);
203 sctp->sctpenc =
204 g_object_ref_sink (gst_element_factory_make ("sctpenc", NULL));
205 g_object_set (sctp->sctpenc, "sctp-association-id", association_id, NULL);
206 g_object_set (sctp->sctpenc, "use-sock-stream", TRUE, NULL);
207
208 g_signal_connect (sctp->sctpdec, "pad-removed",
209 G_CALLBACK (_on_sctp_dec_pad_removed), sctp);
210 g_signal_connect (sctp->sctpenc, "sctp-association-established",
211 G_CALLBACK (_on_sctp_association_established), sctp);
212
213 G_OBJECT_CLASS (parent_class)->constructed (object);
214 }
215
216 static void
webrtc_sctp_transport_class_init(WebRTCSCTPTransportClass * klass)217 webrtc_sctp_transport_class_init (WebRTCSCTPTransportClass * klass)
218 {
219 GObjectClass *gobject_class = (GObjectClass *) klass;
220
221 gobject_class->constructed = webrtc_sctp_transport_constructed;
222 gobject_class->get_property = webrtc_sctp_transport_get_property;
223 gobject_class->finalize = webrtc_sctp_transport_finalize;
224
225 g_object_class_override_property (gobject_class, PROP_TRANSPORT, "transport");
226 g_object_class_override_property (gobject_class, PROP_STATE, "state");
227 g_object_class_override_property (gobject_class,
228 PROP_MAX_MESSAGE_SIZE, "max-message-size");
229 g_object_class_override_property (gobject_class,
230 PROP_MAX_CHANNELS, "max-channels");
231
232 /**
233 * WebRTCSCTPTransport::stream-reset:
234 * @object: the #WebRTCSCTPTransport
235 * @stream_id: the SCTP stream that was reset
236 */
237 webrtc_sctp_transport_signals[ON_STREAM_RESET_SIGNAL] =
238 g_signal_new ("stream-reset", G_TYPE_FROM_CLASS (klass),
239 G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_UINT);
240 }
241
242 static void
webrtc_sctp_transport_init(WebRTCSCTPTransport * nice)243 webrtc_sctp_transport_init (WebRTCSCTPTransport * nice)
244 {
245 }
246
247 WebRTCSCTPTransport *
webrtc_sctp_transport_new(void)248 webrtc_sctp_transport_new (void)
249 {
250 return g_object_new (TYPE_WEBRTC_SCTP_TRANSPORT, NULL);
251 }
252