• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer
2  * Copyright (C) 2017 Matthew Waters <matthew@centricular.com>
3  * Copyright (C) 2020 Sebastian Dröge <sebastian@centricular.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 /**
22  * SECTION:gstwebrtc-datachannel
23  * @short_description: RTCDataChannel object
24  * @title: GstWebRTCDataChannel
25  *
26  * <https://www.w3.org/TR/webrtc/#rtcdatachannel>
27  *
28  * Since: 1.18
29  */
30 
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
34 
35 #include "datachannel.h"
36 #include "webrtc-priv.h"
37 
38 #define GST_CAT_DEFAULT gst_webrtc_data_channel_debug
39 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
40 
41 #define gst_webrtc_data_channel_parent_class parent_class
42 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstWebRTCDataChannel, gst_webrtc_data_channel,
43     G_TYPE_OBJECT, GST_DEBUG_CATEGORY_INIT (gst_webrtc_data_channel_debug,
44         "webrtcdatachannel", 0, "webrtcdatachannel"););
45 
46 enum
47 {
48   SIGNAL_0,
49   SIGNAL_ON_OPEN,
50   SIGNAL_ON_CLOSE,
51   SIGNAL_ON_ERROR,
52   SIGNAL_ON_MESSAGE_DATA,
53   SIGNAL_ON_MESSAGE_STRING,
54   SIGNAL_ON_BUFFERED_AMOUNT_LOW,
55   SIGNAL_SEND_DATA,
56   SIGNAL_SEND_STRING,
57   SIGNAL_CLOSE,
58   LAST_SIGNAL,
59 };
60 
61 enum
62 {
63   PROP_0,
64   PROP_LABEL,
65   PROP_ORDERED,
66   PROP_MAX_PACKET_LIFETIME,
67   PROP_MAX_RETRANSMITS,
68   PROP_PROTOCOL,
69   PROP_NEGOTIATED,
70   PROP_ID,
71   PROP_PRIORITY,
72   PROP_READY_STATE,
73   PROP_BUFFERED_AMOUNT,
74   PROP_BUFFERED_AMOUNT_LOW_THRESHOLD,
75 };
76 
77 static guint gst_webrtc_data_channel_signals[LAST_SIGNAL] = { 0 };
78 
79 static void
gst_webrtc_data_channel_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)80 gst_webrtc_data_channel_set_property (GObject * object, guint prop_id,
81     const GValue * value, GParamSpec * pspec)
82 {
83   GstWebRTCDataChannel *channel = GST_WEBRTC_DATA_CHANNEL (object);
84 
85   GST_WEBRTC_DATA_CHANNEL_LOCK (channel);
86   switch (prop_id) {
87     case PROP_LABEL:
88       g_free (channel->label);
89       channel->label = g_value_dup_string (value);
90       break;
91     case PROP_ORDERED:
92       channel->ordered = g_value_get_boolean (value);
93       break;
94     case PROP_MAX_PACKET_LIFETIME:
95       channel->max_packet_lifetime = g_value_get_int (value);
96       break;
97     case PROP_MAX_RETRANSMITS:
98       channel->max_retransmits = g_value_get_int (value);
99       break;
100     case PROP_PROTOCOL:
101       g_free (channel->protocol);
102       channel->protocol = g_value_dup_string (value);
103       break;
104     case PROP_NEGOTIATED:
105       channel->negotiated = g_value_get_boolean (value);
106       break;
107     case PROP_ID:
108       channel->id = g_value_get_int (value);
109       break;
110     case PROP_PRIORITY:
111       channel->priority = g_value_get_enum (value);
112       break;
113     case PROP_BUFFERED_AMOUNT_LOW_THRESHOLD:
114       channel->buffered_amount_low_threshold = g_value_get_uint64 (value);
115       break;
116     default:
117       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
118       break;
119   }
120   GST_WEBRTC_DATA_CHANNEL_UNLOCK (channel);
121 }
122 
123 static void
gst_webrtc_data_channel_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)124 gst_webrtc_data_channel_get_property (GObject * object, guint prop_id,
125     GValue * value, GParamSpec * pspec)
126 {
127   GstWebRTCDataChannel *channel = GST_WEBRTC_DATA_CHANNEL (object);
128 
129   GST_WEBRTC_DATA_CHANNEL_LOCK (channel);
130   switch (prop_id) {
131     case PROP_LABEL:
132       g_value_set_string (value, channel->label);
133       break;
134     case PROP_ORDERED:
135       g_value_set_boolean (value, channel->ordered);
136       break;
137     case PROP_MAX_PACKET_LIFETIME:
138       g_value_set_int (value, channel->max_packet_lifetime);
139       break;
140     case PROP_MAX_RETRANSMITS:
141       g_value_set_int (value, channel->max_retransmits);
142       break;
143     case PROP_PROTOCOL:
144       g_value_set_string (value, channel->protocol);
145       break;
146     case PROP_NEGOTIATED:
147       g_value_set_boolean (value, channel->negotiated);
148       break;
149     case PROP_ID:
150       g_value_set_int (value, channel->id);
151       break;
152     case PROP_PRIORITY:
153       g_value_set_enum (value, channel->priority);
154       break;
155     case PROP_READY_STATE:
156       g_value_set_enum (value, channel->ready_state);
157       break;
158     case PROP_BUFFERED_AMOUNT:
159       g_value_set_uint64 (value, channel->buffered_amount);
160       break;
161     case PROP_BUFFERED_AMOUNT_LOW_THRESHOLD:
162       g_value_set_uint64 (value, channel->buffered_amount_low_threshold);
163       break;
164     default:
165       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
166       break;
167   }
168   GST_WEBRTC_DATA_CHANNEL_UNLOCK (channel);
169 }
170 
171 static void
gst_webrtc_data_channel_finalize(GObject * object)172 gst_webrtc_data_channel_finalize (GObject * object)
173 {
174   GstWebRTCDataChannel *channel = GST_WEBRTC_DATA_CHANNEL (object);
175 
176   g_free (channel->label);
177   channel->label = NULL;
178 
179   g_free (channel->protocol);
180   channel->protocol = NULL;
181 
182   G_OBJECT_CLASS (parent_class)->finalize (object);
183 }
184 
185 static void
gst_webrtc_data_channel_class_init(GstWebRTCDataChannelClass * klass)186 gst_webrtc_data_channel_class_init (GstWebRTCDataChannelClass * klass)
187 {
188   GObjectClass *gobject_class = (GObjectClass *) klass;
189 
190   gobject_class->get_property = gst_webrtc_data_channel_get_property;
191   gobject_class->set_property = gst_webrtc_data_channel_set_property;
192   gobject_class->finalize = gst_webrtc_data_channel_finalize;
193 
194   g_object_class_install_property (gobject_class,
195       PROP_LABEL,
196       g_param_spec_string ("label",
197           "Label", "Data channel label",
198           NULL,
199           G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
200 
201   g_object_class_install_property (gobject_class,
202       PROP_ORDERED,
203       g_param_spec_boolean ("ordered",
204           "Ordered", "Using ordered transmission mode",
205           FALSE,
206           G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
207 
208   g_object_class_install_property (gobject_class,
209       PROP_MAX_PACKET_LIFETIME,
210       g_param_spec_int ("max-packet-lifetime",
211           "Maximum Packet Lifetime",
212           "Maximum number of milliseconds that transmissions and "
213           "retransmissions may occur in unreliable mode (-1 = unset)",
214           -1, G_MAXUINT16, -1,
215           G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
216 
217   g_object_class_install_property (gobject_class,
218       PROP_MAX_RETRANSMITS,
219       g_param_spec_int ("max-retransmits",
220           "Maximum Retransmits",
221           "Maximum number of retransmissions attempted in unreliable mode",
222           -1, G_MAXUINT16, 0,
223           G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
224 
225   g_object_class_install_property (gobject_class,
226       PROP_PROTOCOL,
227       g_param_spec_string ("protocol",
228           "Protocol", "Data channel protocol",
229           "",
230           G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
231 
232   g_object_class_install_property (gobject_class,
233       PROP_NEGOTIATED,
234       g_param_spec_boolean ("negotiated",
235           "Negotiated",
236           "Whether this data channel was negotiated by the application", FALSE,
237           G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
238 
239   g_object_class_install_property (gobject_class,
240       PROP_ID,
241       g_param_spec_int ("id",
242           "ID",
243           "ID negotiated by this data channel (-1 = unset)",
244           -1, G_MAXUINT16, -1,
245           G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
246 
247   g_object_class_install_property (gobject_class,
248       PROP_PRIORITY,
249       g_param_spec_enum ("priority",
250           "Priority",
251           "The priority of data sent using this data channel",
252           GST_TYPE_WEBRTC_PRIORITY_TYPE,
253           GST_WEBRTC_PRIORITY_TYPE_LOW,
254           G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
255 
256   g_object_class_install_property (gobject_class,
257       PROP_READY_STATE,
258       g_param_spec_enum ("ready-state",
259           "Ready State",
260           "The Ready state of this data channel",
261           GST_TYPE_WEBRTC_DATA_CHANNEL_STATE,
262           GST_WEBRTC_DATA_CHANNEL_STATE_NEW,
263           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
264 
265   g_object_class_install_property (gobject_class,
266       PROP_BUFFERED_AMOUNT,
267       g_param_spec_uint64 ("buffered-amount",
268           "Buffered Amount",
269           "The amount of data in bytes currently buffered",
270           0, G_MAXUINT64, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
271 
272   g_object_class_install_property (gobject_class,
273       PROP_BUFFERED_AMOUNT_LOW_THRESHOLD,
274       g_param_spec_uint64 ("buffered-amount-low-threshold",
275           "Buffered Amount Low Threshold",
276           "The threshold at which the buffered amount is considered low and "
277           "the buffered-amount-low signal is emitted",
278           0, G_MAXUINT64, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
279 
280   /**
281    * GstWebRTCDataChannel::on-open:
282    * @object: the #GstWebRTCDataChannel
283    */
284   gst_webrtc_data_channel_signals[SIGNAL_ON_OPEN] =
285       g_signal_new ("on-open", G_TYPE_FROM_CLASS (klass),
286       G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
287 
288   /**
289    * GstWebRTCDataChannel::on-close:
290    * @object: the #GstWebRTCDataChannel
291    */
292   gst_webrtc_data_channel_signals[SIGNAL_ON_CLOSE] =
293       g_signal_new ("on-close", G_TYPE_FROM_CLASS (klass),
294       G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
295 
296   /**
297    * GstWebRTCDataChannel::on-error:
298    * @object: the #GstWebRTCDataChannel
299    * @error: the #GError thrown
300    */
301   gst_webrtc_data_channel_signals[SIGNAL_ON_ERROR] =
302       g_signal_new ("on-error", G_TYPE_FROM_CLASS (klass),
303       G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_ERROR);
304 
305   /**
306    * GstWebRTCDataChannel::on-message-data:
307    * @object: the #GstWebRTCDataChannel
308    * @data: (nullable): a #GBytes of the data received
309    */
310   gst_webrtc_data_channel_signals[SIGNAL_ON_MESSAGE_DATA] =
311       g_signal_new ("on-message-data", G_TYPE_FROM_CLASS (klass),
312       G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_BYTES);
313 
314   /**
315    * GstWebRTCDataChannel::on-message-string:
316    * @object: the #GstWebRTCDataChannel
317    * @data: (nullable): the data received as a string
318    */
319   gst_webrtc_data_channel_signals[SIGNAL_ON_MESSAGE_STRING] =
320       g_signal_new ("on-message-string", G_TYPE_FROM_CLASS (klass),
321       G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_STRING);
322 
323   /**
324    * GstWebRTCDataChannel::on-buffered-amount-low:
325    * @object: the #GstWebRTCDataChannel
326    */
327   gst_webrtc_data_channel_signals[SIGNAL_ON_BUFFERED_AMOUNT_LOW] =
328       g_signal_new ("on-buffered-amount-low", G_TYPE_FROM_CLASS (klass),
329       G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
330 
331   /**
332    * GstWebRTCDataChannel::send-data:
333    * @object: the #GstWebRTCDataChannel
334    * @data: (nullable): a #GBytes with the data
335    */
336   gst_webrtc_data_channel_signals[SIGNAL_SEND_DATA] =
337       g_signal_new_class_handler ("send-data", G_TYPE_FROM_CLASS (klass),
338       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
339       G_CALLBACK (gst_webrtc_data_channel_send_data), NULL, NULL, NULL,
340       G_TYPE_NONE, 1, G_TYPE_BYTES);
341 
342   /**
343    * GstWebRTCDataChannel::send-string:
344    * @object: the #GstWebRTCDataChannel
345    * @data: (nullable): the data to send as a string
346    */
347   gst_webrtc_data_channel_signals[SIGNAL_SEND_STRING] =
348       g_signal_new_class_handler ("send-string", G_TYPE_FROM_CLASS (klass),
349       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
350       G_CALLBACK (gst_webrtc_data_channel_send_string), NULL, NULL, NULL,
351       G_TYPE_NONE, 1, G_TYPE_STRING);
352 
353   /**
354    * GstWebRTCDataChannel::close:
355    * @object: the #GstWebRTCDataChannel
356    *
357    * Close the data channel
358    */
359   gst_webrtc_data_channel_signals[SIGNAL_CLOSE] =
360       g_signal_new_class_handler ("close", G_TYPE_FROM_CLASS (klass),
361       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
362       G_CALLBACK (gst_webrtc_data_channel_close), NULL, NULL, NULL,
363       G_TYPE_NONE, 0);
364 }
365 
366 static void
gst_webrtc_data_channel_init(GstWebRTCDataChannel * channel)367 gst_webrtc_data_channel_init (GstWebRTCDataChannel * channel)
368 {
369   g_mutex_init (&channel->lock);
370 }
371 
372 /**
373  * gst_webrtc_data_channel_on_open:
374  * @channel: a #GstWebRTCDataChannel
375  *
376  * Signal that the data channel was opened. Should only be used by subclasses.
377  */
378 void
gst_webrtc_data_channel_on_open(GstWebRTCDataChannel * channel)379 gst_webrtc_data_channel_on_open (GstWebRTCDataChannel * channel)
380 {
381   g_return_if_fail (GST_IS_WEBRTC_DATA_CHANNEL (channel));
382 
383   GST_WEBRTC_DATA_CHANNEL_LOCK (channel);
384   if (channel->ready_state == GST_WEBRTC_DATA_CHANNEL_STATE_CLOSING ||
385       channel->ready_state == GST_WEBRTC_DATA_CHANNEL_STATE_CLOSED) {
386     GST_WEBRTC_DATA_CHANNEL_UNLOCK (channel);
387     return;
388   }
389 
390   if (channel->ready_state != GST_WEBRTC_DATA_CHANNEL_STATE_OPEN) {
391     channel->ready_state = GST_WEBRTC_DATA_CHANNEL_STATE_OPEN;
392     GST_WEBRTC_DATA_CHANNEL_UNLOCK (channel);
393     g_object_notify (G_OBJECT (channel), "ready-state");
394 
395     GST_INFO_OBJECT (channel, "We are open and ready for data!");
396   } else {
397     GST_WEBRTC_DATA_CHANNEL_UNLOCK (channel);
398   }
399 
400   GST_INFO_OBJECT (channel, "Opened");
401 
402   g_signal_emit (channel, gst_webrtc_data_channel_signals[SIGNAL_ON_OPEN], 0,
403       NULL);
404 }
405 
406 /**
407  * gst_webrtc_data_channel_on_close:
408  * @channel: a #GstWebRTCDataChannel
409  *
410  * Signal that the data channel was closed. Should only be used by subclasses.
411  */
412 void
gst_webrtc_data_channel_on_close(GstWebRTCDataChannel * channel)413 gst_webrtc_data_channel_on_close (GstWebRTCDataChannel * channel)
414 {
415   g_return_if_fail (GST_IS_WEBRTC_DATA_CHANNEL (channel));
416 
417   GST_INFO_OBJECT (channel, "Closed");
418 
419   GST_WEBRTC_DATA_CHANNEL_LOCK (channel);
420   if (channel->ready_state == GST_WEBRTC_DATA_CHANNEL_STATE_CLOSED) {
421     GST_WEBRTC_DATA_CHANNEL_UNLOCK (channel);
422     return;
423   }
424 
425   channel->ready_state = GST_WEBRTC_DATA_CHANNEL_STATE_CLOSED;
426   GST_WEBRTC_DATA_CHANNEL_UNLOCK (channel);
427 
428   g_object_notify (G_OBJECT (channel), "ready-state");
429   GST_INFO_OBJECT (channel, "We are closed for data");
430 
431   g_signal_emit (channel, gst_webrtc_data_channel_signals[SIGNAL_ON_CLOSE], 0,
432       NULL);
433 }
434 
435 /**
436  * gst_webrtc_data_channel_on_error:
437  * @channel: a #GstWebRTCDataChannel
438  * @error: (transfer full): a #GError
439  *
440  * Signal that the data channel had an error. Should only be used by subclasses.
441  */
442 void
gst_webrtc_data_channel_on_error(GstWebRTCDataChannel * channel,GError * error)443 gst_webrtc_data_channel_on_error (GstWebRTCDataChannel * channel,
444     GError * error)
445 {
446   g_return_if_fail (GST_IS_WEBRTC_DATA_CHANNEL (channel));
447   g_return_if_fail (error != NULL);
448 
449   GST_WARNING_OBJECT (channel, "Error: %s", GST_STR_NULL (error->message));
450 
451   g_signal_emit (channel, gst_webrtc_data_channel_signals[SIGNAL_ON_ERROR], 0,
452       error);
453 }
454 
455 /**
456  * gst_webrtc_data_channel_on_message_data:
457  * @channel: a #GstWebRTCDataChannel
458  * @data: (nullable): a #GBytes or %NULL
459  *
460  * Signal that the data channel received a data message. Should only be used by subclasses.
461  */
462 void
gst_webrtc_data_channel_on_message_data(GstWebRTCDataChannel * channel,GBytes * data)463 gst_webrtc_data_channel_on_message_data (GstWebRTCDataChannel * channel,
464     GBytes * data)
465 {
466   g_return_if_fail (GST_IS_WEBRTC_DATA_CHANNEL (channel));
467 
468   GST_LOG_OBJECT (channel, "Have data %p", data);
469   g_signal_emit (channel,
470       gst_webrtc_data_channel_signals[SIGNAL_ON_MESSAGE_DATA], 0, data);
471 }
472 
473 /**
474  * gst_webrtc_data_channel_on_message_string:
475  * @channel: a #GstWebRTCDataChannel
476  * @str: (nullable): a string or %NULL
477  *
478  * Signal that the data channel received a string message. Should only be used by subclasses.
479  */
480 void
gst_webrtc_data_channel_on_message_string(GstWebRTCDataChannel * channel,const gchar * str)481 gst_webrtc_data_channel_on_message_string (GstWebRTCDataChannel * channel,
482     const gchar * str)
483 {
484   g_return_if_fail (GST_IS_WEBRTC_DATA_CHANNEL (channel));
485 
486   GST_LOG_OBJECT (channel, "Have string %p", str);
487   g_signal_emit (channel,
488       gst_webrtc_data_channel_signals[SIGNAL_ON_MESSAGE_STRING], 0, str);
489 }
490 
491 /**
492  * gst_webrtc_data_channel_on_buffered_amount_low:
493  * @channel: a #GstWebRTCDataChannel
494  *
495  * Signal that the data channel reached a low buffered amount. Should only be used by subclasses.
496  */
497 void
gst_webrtc_data_channel_on_buffered_amount_low(GstWebRTCDataChannel * channel)498 gst_webrtc_data_channel_on_buffered_amount_low (GstWebRTCDataChannel * channel)
499 {
500   g_return_if_fail (GST_IS_WEBRTC_DATA_CHANNEL (channel));
501 
502   GST_LOG_OBJECT (channel, "Low threshold reached");
503   g_signal_emit (channel,
504       gst_webrtc_data_channel_signals[SIGNAL_ON_BUFFERED_AMOUNT_LOW], 0);
505 }
506 
507 /**
508  * gst_webrtc_data_channel_send_data:
509  * @channel: a #GstWebRTCDataChannel
510  * @data: (nullable): a #GBytes or %NULL
511  *
512  * Send @data as a data message over @channel.
513  */
514 void
gst_webrtc_data_channel_send_data(GstWebRTCDataChannel * channel,GBytes * data)515 gst_webrtc_data_channel_send_data (GstWebRTCDataChannel * channel,
516     GBytes * data)
517 {
518   GstWebRTCDataChannelClass *klass;
519 
520   g_return_if_fail (GST_IS_WEBRTC_DATA_CHANNEL (channel));
521 
522   klass = GST_WEBRTC_DATA_CHANNEL_GET_CLASS (channel);
523   klass->send_data (channel, data);
524 }
525 
526 /**
527  * gst_webrtc_data_channel_send_string:
528  * @channel: a #GstWebRTCDataChannel
529  * @str: (nullable): a string or %NULL
530  *
531  * Send @str as a string message over @channel.
532  */
533 void
gst_webrtc_data_channel_send_string(GstWebRTCDataChannel * channel,const gchar * str)534 gst_webrtc_data_channel_send_string (GstWebRTCDataChannel * channel,
535     const gchar * str)
536 {
537   GstWebRTCDataChannelClass *klass;
538 
539   g_return_if_fail (GST_IS_WEBRTC_DATA_CHANNEL (channel));
540 
541   klass = GST_WEBRTC_DATA_CHANNEL_GET_CLASS (channel);
542   klass->send_string (channel, str);
543 }
544 
545 /**
546  * gst_webrtc_data_channel_close:
547  * @channel: a #GstWebRTCDataChannel
548  *
549  * Close the @channel.
550  */
551 void
gst_webrtc_data_channel_close(GstWebRTCDataChannel * channel)552 gst_webrtc_data_channel_close (GstWebRTCDataChannel * channel)
553 {
554   GstWebRTCDataChannelClass *klass;
555 
556   g_return_if_fail (GST_IS_WEBRTC_DATA_CHANNEL (channel));
557 
558   klass = GST_WEBRTC_DATA_CHANNEL_GET_CLASS (channel);
559   klass->close (channel);
560 }
561