• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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