webrtc: Add GstWebRTCDataChannel to the library API
authorSebastian Dröge <sebastian@centricular.com>
Mon, 1 Jun 2020 11:46:03 +0000 (14:46 +0300)
committerGStreamer Merge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Tue, 2 Jun 2020 21:04:37 +0000 (21:04 +0000)
This makes it more discoverable for bindings and allows bindings to
generate static API for the signals and functions.

Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/issues/1168

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1313>

ext/webrtc/gstwebrtcbin.c
ext/webrtc/webrtcdatachannel.c
ext/webrtc/webrtcdatachannel.h
gst-libs/gst/webrtc/datachannel.c [new file with mode: 0644]
gst-libs/gst/webrtc/datachannel.h [new file with mode: 0644]
gst-libs/gst/webrtc/meson.build
gst-libs/gst/webrtc/webrtc.h
gst-libs/gst/webrtc/webrtc_fwd.h

index b505b75..7920b19 100644 (file)
@@ -545,17 +545,17 @@ _find_pad (GstWebRTCBin * webrtc, gconstpointer data, FindPadFunc func)
   return NULL;
 }
 
-typedef gboolean (*FindDataChannelFunc) (GstWebRTCDataChannel * p1,
+typedef gboolean (*FindDataChannelFunc) (WebRTCDataChannel * p1,
     gconstpointer data);
 
-static GstWebRTCDataChannel *
+static WebRTCDataChannel *
 _find_data_channel (GstWebRTCBin * webrtc, gconstpointer data,
     FindDataChannelFunc func)
 {
   int i;
 
   for (i = 0; i < webrtc->priv->data_channels->len; i++) {
-    GstWebRTCDataChannel *channel =
+    WebRTCDataChannel *channel =
         g_ptr_array_index (webrtc->priv->data_channels, i);
 
     if (func (channel, data))
@@ -566,15 +566,15 @@ _find_data_channel (GstWebRTCBin * webrtc, gconstpointer data,
 }
 
 static gboolean
-data_channel_match_for_id (GstWebRTCDataChannel * channel, gint * id)
+data_channel_match_for_id (WebRTCDataChannel * channel, gint * id)
 {
-  return channel->id == *id;
+  return channel->parent.id == *id;
 }
 
-static GstWebRTCDataChannel *
+static WebRTCDataChannel *
 _find_data_channel_for_id (GstWebRTCBin * webrtc, gint id)
 {
-  GstWebRTCDataChannel *channel;
+  WebRTCDataChannel *channel;
 
   channel = _find_data_channel (webrtc, &id,
       (FindDataChannelFunc) data_channel_match_for_id);
@@ -1737,7 +1737,7 @@ _get_or_create_rtp_transport_channel (GstWebRTCBin * webrtc, guint session_id)
 
 /* this is called from the webrtc thread with the pc lock held */
 static void
-_on_data_channel_ready_state (GstWebRTCDataChannel * channel,
+_on_data_channel_ready_state (WebRTCDataChannel * channel,
     GParamSpec * pspec, GstWebRTCBin * webrtc)
 {
   GstWebRTCDataChannelState ready_state;
@@ -1749,7 +1749,7 @@ _on_data_channel_ready_state (GstWebRTCDataChannel * channel,
     gboolean found = FALSE;
 
     for (i = 0; i < webrtc->priv->pending_data_channels->len; i++) {
-      GstWebRTCDataChannel *c;
+      WebRTCDataChannel *c;
 
       c = g_ptr_array_index (webrtc->priv->pending_data_channels, i);
       if (c == channel) {
@@ -1774,7 +1774,7 @@ static void
 _on_sctpdec_pad_added (GstElement * sctpdec, GstPad * pad,
     GstWebRTCBin * webrtc)
 {
-  GstWebRTCDataChannel *channel;
+  WebRTCDataChannel *channel;
   guint stream_id;
   GstPad *sink_pad;
 
@@ -1784,8 +1784,8 @@ _on_sctpdec_pad_added (GstElement * sctpdec, GstPad * pad,
   PC_LOCK (webrtc);
   channel = _find_data_channel_for_id (webrtc, stream_id);
   if (!channel) {
-    channel = g_object_new (GST_TYPE_WEBRTC_DATA_CHANNEL, NULL);
-    channel->id = stream_id;
+    channel = g_object_new (WEBRTC_TYPE_DATA_CHANNEL, NULL);
+    channel->parent.id = stream_id;
     channel->webrtcbin = webrtc;
 
     gst_bin_add (GST_BIN (webrtc), channel->appsrc);
@@ -1794,8 +1794,7 @@ _on_sctpdec_pad_added (GstElement * sctpdec, GstPad * pad,
     gst_element_sync_state_with_parent (channel->appsrc);
     gst_element_sync_state_with_parent (channel->appsink);
 
-    gst_webrtc_data_channel_link_to_sctp (channel,
-        webrtc->priv->sctp_transport);
+    webrtc_data_channel_link_to_sctp (channel, webrtc->priv->sctp_transport);
 
     g_ptr_array_add (webrtc->priv->pending_data_channels, channel);
   }
@@ -1826,15 +1825,14 @@ _on_sctp_state_notify (GstWebRTCSCTPTransport * sctp, GParamSpec * pspec,
     GST_DEBUG_OBJECT (webrtc, "SCTP association established");
 
     for (i = 0; i < webrtc->priv->data_channels->len; i++) {
-      GstWebRTCDataChannel *channel;
+      WebRTCDataChannel *channel;
 
       channel = g_ptr_array_index (webrtc->priv->data_channels, i);
 
-      gst_webrtc_data_channel_link_to_sctp (channel,
-          webrtc->priv->sctp_transport);
+      webrtc_data_channel_link_to_sctp (channel, webrtc->priv->sctp_transport);
 
-      if (!channel->negotiated && !channel->opened)
-        gst_webrtc_data_channel_start_negotiation (channel);
+      if (!channel->parent.negotiated && !channel->opened)
+        webrtc_data_channel_start_negotiation (channel);
     }
     PC_UNLOCK (webrtc);
   }
@@ -1993,12 +1991,11 @@ _get_or_create_data_channel_transports (GstWebRTCBin * webrtc, guint session_id)
       g_warn_if_reached ();
 
     for (i = 0; i < webrtc->priv->data_channels->len; i++) {
-      GstWebRTCDataChannel *channel;
+      WebRTCDataChannel *channel;
 
       channel = g_ptr_array_index (webrtc->priv->data_channels, i);
 
-      gst_webrtc_data_channel_link_to_sctp (channel,
-          webrtc->priv->sctp_transport);
+      webrtc_data_channel_link_to_sctp (channel, webrtc->priv->sctp_transport);
     }
 
     gst_element_sync_state_with_parent (GST_ELEMENT (stream->send_bin));
@@ -4001,7 +3998,7 @@ _generate_data_channel_id (GstWebRTCBin * webrtc)
 
   /* TODO: a better search algorithm */
   do {
-    GstWebRTCDataChannel *channel;
+    WebRTCDataChannel *channel;
 
     new_id++;
 
@@ -4087,21 +4084,20 @@ _update_data_channel_from_sdp_media (GstWebRTCBin * webrtc,
   }
 
   for (i = 0; i < webrtc->priv->data_channels->len; i++) {
-    GstWebRTCDataChannel *channel;
+    WebRTCDataChannel *channel;
 
     channel = g_ptr_array_index (webrtc->priv->data_channels, i);
 
-    if (channel->id == -1)
-      channel->id = _generate_data_channel_id (webrtc);
-    if (channel->id == -1)
+    if (channel->parent.id == -1)
+      channel->parent.id = _generate_data_channel_id (webrtc);
+    if (channel->parent.id == -1)
       GST_ELEMENT_WARNING (webrtc, RESOURCE, NOT_FOUND,
           ("%s", "Failed to generate an identifier for a data channel"), NULL);
 
     if (webrtc->priv->sctp_transport->association_established
-        && !channel->negotiated && !channel->opened) {
-      gst_webrtc_data_channel_link_to_sctp (channel,
-          webrtc->priv->sctp_transport);
-      gst_webrtc_data_channel_start_negotiation (channel);
+        && !channel->parent.negotiated && !channel->opened) {
+      webrtc_data_channel_link_to_sctp (channel, webrtc->priv->sctp_transport);
+      webrtc_data_channel_start_negotiation (channel);
     }
   }
 
@@ -5049,7 +5045,7 @@ copy_sticky_events (GstPad * pad, GstEvent ** event, gpointer user_data)
   return TRUE;
 }
 
-static GstWebRTCDataChannel *
+static WebRTCDataChannel *
 gst_webrtc_bin_create_data_channel (GstWebRTCBin * webrtc, const gchar * label,
     GstStructure * init_params)
 {
@@ -5060,7 +5056,7 @@ gst_webrtc_bin_create_data_channel (GstWebRTCBin * webrtc, const gchar * label,
   gboolean negotiated;
   gint id;
   GstWebRTCPriorityType priority;
-  GstWebRTCDataChannel *ret;
+  WebRTCDataChannel *ret;
   gint max_channels = 65534;
 
   g_return_val_if_fail (GST_IS_WEBRTC_BIN (webrtc), NULL);
@@ -5125,7 +5121,7 @@ gst_webrtc_bin_create_data_channel (GstWebRTCBin * webrtc, const gchar * label,
   PC_LOCK (webrtc);
   /* check if the id has been used already */
   if (id != -1) {
-    GstWebRTCDataChannel *channel = _find_data_channel_for_id (webrtc, id);
+    WebRTCDataChannel *channel = _find_data_channel_for_id (webrtc, id);
     if (channel) {
       GST_ELEMENT_WARNING (webrtc, LIBRARY, SETTINGS,
           ("Attempting to add a data channel with a duplicate ID: %i", id),
@@ -5147,7 +5143,7 @@ gst_webrtc_bin_create_data_channel (GstWebRTCBin * webrtc, const gchar * label,
     }
   }
 
-  ret = g_object_new (GST_TYPE_WEBRTC_DATA_CHANNEL, "label", label,
+  ret = g_object_new (WEBRTC_TYPE_DATA_CHANNEL, "label", label,
       "ordered", ordered, "max-packet-lifetime", max_packet_lifetime,
       "max-retransmits", max_retransmits, "protocol", protocol,
       "negotiated", negotiated, "id", id, "priority", priority, NULL);
@@ -5162,11 +5158,11 @@ gst_webrtc_bin_create_data_channel (GstWebRTCBin * webrtc, const gchar * label,
     ret = gst_object_ref (ret);
     ret->webrtcbin = webrtc;
     g_ptr_array_add (webrtc->priv->data_channels, ret);
-    gst_webrtc_data_channel_link_to_sctp (ret, webrtc->priv->sctp_transport);
+    webrtc_data_channel_link_to_sctp (ret, webrtc->priv->sctp_transport);
     if (webrtc->priv->sctp_transport &&
         webrtc->priv->sctp_transport->association_established
-        && !ret->negotiated) {
-      gst_webrtc_data_channel_start_negotiation (ret);
+        && !ret->parent.negotiated) {
+      webrtc_data_channel_start_negotiation (ret);
     } else {
       _update_need_negotiation (webrtc);
     }
index 0eb9f85..eccb0db 100644 (file)
 #include "gstwebrtcbin.h"
 #include "utils.h"
 
-#define GST_CAT_DEFAULT gst_webrtc_data_channel_debug
+#define GST_CAT_DEFAULT webrtc_data_channel_debug
 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
 
-#define gst_webrtc_data_channel_parent_class parent_class
-G_DEFINE_TYPE_WITH_CODE (GstWebRTCDataChannel, gst_webrtc_data_channel,
-    G_TYPE_OBJECT, GST_DEBUG_CATEGORY_INIT (gst_webrtc_data_channel_debug,
-        "webrtcdatachannel", 0, "webrtcdatachannel"););
-
-#define CHANNEL_LOCK(channel) g_mutex_lock(&channel->lock)
-#define CHANNEL_UNLOCK(channel) g_mutex_unlock(&channel->lock)
-
-enum
-{
-  SIGNAL_0,
-  SIGNAL_ON_OPEN,
-  SIGNAL_ON_CLOSE,
-  SIGNAL_ON_ERROR,
-  SIGNAL_ON_MESSAGE_DATA,
-  SIGNAL_ON_MESSAGE_STRING,
-  SIGNAL_ON_BUFFERED_AMOUNT_LOW,
-  SIGNAL_SEND_DATA,
-  SIGNAL_SEND_STRING,
-  SIGNAL_CLOSE,
-  LAST_SIGNAL,
-};
-
-enum
-{
-  PROP_0,
-  PROP_LABEL,
-  PROP_ORDERED,
-  PROP_MAX_PACKET_LIFETIME,
-  PROP_MAX_RETRANSMITS,
-  PROP_PROTOCOL,
-  PROP_NEGOTIATED,
-  PROP_ID,
-  PROP_PRIORITY,
-  PROP_READY_STATE,
-  PROP_BUFFERED_AMOUNT,
-  PROP_BUFFERED_AMOUNT_LOW_THRESHOLD,
-};
-
-static guint gst_webrtc_data_channel_signals[LAST_SIGNAL] = { 0 };
+#define webrtc_data_channel_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (WebRTCDataChannel, webrtc_data_channel,
+    GST_TYPE_WEBRTC_DATA_CHANNEL,
+    GST_DEBUG_CATEGORY_INIT (webrtc_data_channel_debug, "webrtcdatachannel", 0,
+        "webrtcdatachannel"););
 
 typedef enum
 {
@@ -142,11 +107,11 @@ priority_uint_to_type (guint16 val)
 }
 
 static GstBuffer *
-construct_open_packet (GstWebRTCDataChannel * channel)
+construct_open_packet (WebRTCDataChannel * channel)
 {
   GstByteWriter w;
-  gsize label_len = strlen (channel->label);
-  gsize proto_len = strlen (channel->protocol);
+  gsize label_len = strlen (channel->parent.label);
+  gsize proto_len = strlen (channel->parent.protocol);
   gsize size = 12 + label_len + proto_len;
   DataChannelReliabilityType reliability = 0;
   guint32 reliability_param = 0;
@@ -178,18 +143,18 @@ construct_open_packet (GstWebRTCDataChannel * channel)
   if (!gst_byte_writer_put_uint8 (&w, (guint8) CHANNEL_MESSAGE_OPEN))
     g_return_val_if_reached (NULL);
 
-  if (!channel->ordered)
+  if (!channel->parent.ordered)
     reliability |= 0x80;
-  if (channel->max_retransmits != -1) {
+  if (channel->parent.max_retransmits != -1) {
     reliability |= 0x01;
-    reliability_param = channel->max_retransmits;
+    reliability_param = channel->parent.max_retransmits;
   }
-  if (channel->max_packet_lifetime != -1) {
+  if (channel->parent.max_packet_lifetime != -1) {
     reliability |= 0x02;
-    reliability_param = channel->max_packet_lifetime;
+    reliability_param = channel->parent.max_packet_lifetime;
   }
 
-  priority = priority_type_to_uint (channel->priority);
+  priority = priority_type_to_uint (channel->parent.priority);
 
   if (!gst_byte_writer_put_uint8 (&w, (guint8) reliability))
     g_return_val_if_reached (NULL);
@@ -201,9 +166,11 @@ construct_open_packet (GstWebRTCDataChannel * channel)
     g_return_val_if_reached (NULL);
   if (!gst_byte_writer_put_uint16_be (&w, (guint16) proto_len))
     g_return_val_if_reached (NULL);
-  if (!gst_byte_writer_put_data (&w, (guint8 *) channel->label, label_len))
+  if (!gst_byte_writer_put_data (&w, (guint8 *) channel->parent.label,
+          label_len))
     g_return_val_if_reached (NULL);
-  if (!gst_byte_writer_put_data (&w, (guint8 *) channel->protocol, proto_len))
+  if (!gst_byte_writer_put_data (&w, (guint8 *) channel->parent.protocol,
+          proto_len))
     g_return_val_if_reached (NULL);
 
   buf = gst_byte_writer_reset_and_get_buffer (&w);
@@ -216,7 +183,7 @@ construct_open_packet (GstWebRTCDataChannel * channel)
 }
 
 static GstBuffer *
-construct_ack_packet (GstWebRTCDataChannel * channel)
+construct_ack_packet (WebRTCDataChannel * channel)
 {
   GstByteWriter w;
   GstBuffer *buf;
@@ -272,7 +239,7 @@ _free_task (struct task *task)
 }
 
 static void
-_channel_enqueue_task (GstWebRTCDataChannel * channel, ChannelTask func,
+_channel_enqueue_task (WebRTCDataChannel * channel, ChannelTask func,
     gpointer user_data, GDestroyNotify notify)
 {
   struct task *task = g_new0 (struct task, 1);
@@ -288,9 +255,9 @@ _channel_enqueue_task (GstWebRTCDataChannel * channel, ChannelTask func,
 }
 
 static void
-_channel_store_error (GstWebRTCDataChannel * channel, GError * error)
+_channel_store_error (WebRTCDataChannel * channel, GError * error)
 {
-  CHANNEL_LOCK (channel);
+  GST_WEBRTC_DATA_CHANNEL_LOCK (channel);
   if (error) {
     GST_WARNING_OBJECT (channel, "Error: %s",
         error ? error->message : "Unknown");
@@ -299,76 +266,32 @@ _channel_store_error (GstWebRTCDataChannel * channel, GError * error)
     else
       g_clear_error (&error);
   }
-  CHANNEL_UNLOCK (channel);
-}
-
-static void
-_maybe_emit_on_error (GstWebRTCDataChannel * channel, GError * error)
-{
-  if (error) {
-    GST_WARNING_OBJECT (channel, "error thrown");
-    g_signal_emit (channel, gst_webrtc_data_channel_signals[SIGNAL_ON_ERROR], 0,
-        error);
-  }
+  GST_WEBRTC_DATA_CHANNEL_UNLOCK (channel);
 }
 
 static void
-_emit_on_open (GstWebRTCDataChannel * channel, gpointer user_data)
+_emit_on_open (WebRTCDataChannel * channel, gpointer user_data)
 {
-  CHANNEL_LOCK (channel);
-  if (channel->ready_state == GST_WEBRTC_DATA_CHANNEL_STATE_CLOSING ||
-      channel->ready_state == GST_WEBRTC_DATA_CHANNEL_STATE_CLOSED) {
-    CHANNEL_UNLOCK (channel);
-    return;
-  }
-
-  if (channel->ready_state != GST_WEBRTC_DATA_CHANNEL_STATE_OPEN) {
-    channel->ready_state = GST_WEBRTC_DATA_CHANNEL_STATE_OPEN;
-    CHANNEL_UNLOCK (channel);
-    g_object_notify (G_OBJECT (channel), "ready-state");
-
-    GST_INFO_OBJECT (channel, "We are open and ready for data!");
-    g_signal_emit (channel, gst_webrtc_data_channel_signals[SIGNAL_ON_OPEN], 0,
-        NULL);
-  } else {
-    CHANNEL_UNLOCK (channel);
-  }
+  gst_webrtc_data_channel_on_open (GST_WEBRTC_DATA_CHANNEL (channel));
 }
 
 static void
-_transport_closed_unlocked (GstWebRTCDataChannel * channel)
+_transport_closed (WebRTCDataChannel * channel)
 {
   GError *error;
 
-  if (channel->ready_state == GST_WEBRTC_DATA_CHANNEL_STATE_CLOSED)
-    return;
-
-  channel->ready_state = GST_WEBRTC_DATA_CHANNEL_STATE_CLOSED;
-
+  GST_WEBRTC_DATA_CHANNEL_LOCK (channel);
   error = channel->stored_error;
   channel->stored_error = NULL;
-  CHANNEL_UNLOCK (channel);
-
-  g_object_notify (G_OBJECT (channel), "ready-state");
-  GST_INFO_OBJECT (channel, "We are closed for data");
-
-  _maybe_emit_on_error (channel, error);
-
-  g_signal_emit (channel, gst_webrtc_data_channel_signals[SIGNAL_ON_CLOSE], 0,
-      NULL);
-  CHANNEL_LOCK (channel);
-}
+  GST_WEBRTC_DATA_CHANNEL_UNLOCK (channel);
 
-static void
-_transport_closed (GstWebRTCDataChannel * channel, gpointer user_data)
-{
-  CHANNEL_LOCK (channel);
-  _transport_closed_unlocked (channel);
-  CHANNEL_UNLOCK (channel);
+  if (error)
+    gst_webrtc_data_channel_on_error (GST_WEBRTC_DATA_CHANNEL (channel), error);
+  gst_webrtc_data_channel_on_close (GST_WEBRTC_DATA_CHANNEL (channel));
 }
 
 static void
-_close_sctp_stream (GstWebRTCDataChannel * channel, gpointer user_data)
+_close_sctp_stream (WebRTCDataChannel * channel, gpointer user_data)
 {
   GstPad *pad, *peer;
 
@@ -386,49 +309,49 @@ _close_sctp_stream (GstWebRTCDataChannel * channel, gpointer user_data)
     gst_object_unref (peer);
   }
 
-  _transport_closed (channel, NULL);
+  _transport_closed (channel);
 }
 
 static void
-_close_procedure (GstWebRTCDataChannel * channel, gpointer user_data)
+_close_procedure (WebRTCDataChannel * channel, gpointer user_data)
 {
   /* https://www.w3.org/TR/webrtc/#data-transport-closing-procedure */
-  CHANNEL_LOCK (channel);
-  if (channel->ready_state == GST_WEBRTC_DATA_CHANNEL_STATE_CLOSED
-      || channel->ready_state == GST_WEBRTC_DATA_CHANNEL_STATE_CLOSING) {
-    CHANNEL_UNLOCK (channel);
+  GST_WEBRTC_DATA_CHANNEL_LOCK (channel);
+  if (channel->parent.ready_state == GST_WEBRTC_DATA_CHANNEL_STATE_CLOSED
+      || channel->parent.ready_state == GST_WEBRTC_DATA_CHANNEL_STATE_CLOSING) {
+    GST_WEBRTC_DATA_CHANNEL_UNLOCK (channel);
     return;
   }
-  channel->ready_state = GST_WEBRTC_DATA_CHANNEL_STATE_CLOSING;
-  CHANNEL_UNLOCK (channel);
+  channel->parent.ready_state = GST_WEBRTC_DATA_CHANNEL_STATE_CLOSING;
+  GST_WEBRTC_DATA_CHANNEL_UNLOCK (channel);
   g_object_notify (G_OBJECT (channel), "ready-state");
 
-  CHANNEL_LOCK (channel);
-  if (channel->buffered_amount <= 0) {
+  GST_WEBRTC_DATA_CHANNEL_LOCK (channel);
+  if (channel->parent.buffered_amount <= 0) {
     _channel_enqueue_task (channel, (ChannelTask) _close_sctp_stream,
         NULL, NULL);
   }
 
-  CHANNEL_UNLOCK (channel);
+  GST_WEBRTC_DATA_CHANNEL_UNLOCK (channel);
 }
 
 static void
 _on_sctp_reset_stream (GstWebRTCSCTPTransport * sctp, guint stream_id,
-    GstWebRTCDataChannel * channel)
+    WebRTCDataChannel * channel)
 {
-  if (channel->id == stream_id)
+  if (channel->parent.id == stream_id)
     _channel_enqueue_task (channel, (ChannelTask) _transport_closed,
         GUINT_TO_POINTER (stream_id), NULL);
 }
 
 static void
-gst_webrtc_data_channel_close (GstWebRTCDataChannel * channel)
+webrtc_data_channel_close (GstWebRTCDataChannel * channel)
 {
-  _close_procedure (channel, NULL);
+  _close_procedure (WEBRTC_DATA_CHANNEL (channel), NULL);
 }
 
 static GstFlowReturn
-_parse_control_packet (GstWebRTCDataChannel * channel, guint8 * data,
+_parse_control_packet (WebRTCDataChannel * channel, guint8 * data,
     gsize size, GError ** error)
 {
   GstByteReader r;
@@ -460,7 +383,7 @@ _parse_control_packet (GstWebRTCDataChannel * channel, guint8 * data,
 
     GST_INFO_OBJECT (channel, "Received channel open");
 
-    if (channel->negotiated) {
+    if (channel->parent.negotiated) {
       g_set_error (error, GST_WEBRTC_BIN_ERROR,
           GST_WEBRTC_BIN_ERROR_DATA_CHANNEL_FAILURE,
           "Data channel was signalled as negotiated already");
@@ -493,34 +416,35 @@ _parse_control_packet (GstWebRTCDataChannel * channel, guint8 * data,
     memcpy (proto, src, proto_len);
     proto[proto_len] = '\0';
 
-    channel->label = label;
-    channel->protocol = proto;
-    channel->priority = priority_uint_to_type (priority);
-    channel->ordered = !(reliability & 0x80);
+    channel->parent.label = label;
+    channel->parent.protocol = proto;
+    channel->parent.priority = priority_uint_to_type (priority);
+    channel->parent.ordered = !(reliability & 0x80);
     if (reliability & 0x01) {
-      channel->max_retransmits = reliability_param;
-      channel->max_packet_lifetime = -1;
+      channel->parent.max_retransmits = reliability_param;
+      channel->parent.max_packet_lifetime = -1;
     } else if (reliability & 0x02) {
-      channel->max_retransmits = -1;
-      channel->max_packet_lifetime = reliability_param;
+      channel->parent.max_retransmits = -1;
+      channel->parent.max_packet_lifetime = reliability_param;
     } else {
-      channel->max_retransmits = -1;
-      channel->max_packet_lifetime = -1;
+      channel->parent.max_retransmits = -1;
+      channel->parent.max_packet_lifetime = -1;
     }
     channel->opened = TRUE;
 
     GST_INFO_OBJECT (channel, "Received channel open for SCTP stream %i "
-        "label %s protocol %s ordered %s", channel->id, channel->label,
-        channel->protocol, channel->ordered ? "true" : "false");
+        "label %s protocol %s ordered %s", channel->parent.id,
+        channel->parent.label, channel->parent.protocol,
+        channel->parent.ordered ? "true" : "false");
 
     _channel_enqueue_task (channel, (ChannelTask) _emit_on_open, NULL, NULL);
 
     GST_INFO_OBJECT (channel, "Sending channel ack");
     buffer = construct_ack_packet (channel);
 
-    CHANNEL_LOCK (channel);
-    channel->buffered_amount += gst_buffer_get_size (buffer);
-    CHANNEL_UNLOCK (channel);
+    GST_WEBRTC_DATA_CHANNEL_LOCK (channel);
+    channel->parent.buffered_amount += gst_buffer_get_size (buffer);
+    GST_WEBRTC_DATA_CHANNEL_UNLOCK (channel);
 
     ret = gst_app_src_push_buffer (GST_APP_SRC (channel->appsrc), buffer);
     if (ret != GST_FLOW_OK) {
@@ -568,23 +492,21 @@ buffer_unmap_and_unref (struct map_info *info)
 }
 
 static void
-_emit_have_data (GstWebRTCDataChannel * channel, GBytes * data)
+_emit_have_data (WebRTCDataChannel * channel, GBytes * data)
 {
-  GST_LOG_OBJECT (channel, "Have data %p", data);
-  g_signal_emit (channel,
-      gst_webrtc_data_channel_signals[SIGNAL_ON_MESSAGE_DATA], 0, data);
+  gst_webrtc_data_channel_on_message_data (GST_WEBRTC_DATA_CHANNEL (channel),
+      data);
 }
 
 static void
 _emit_have_string (GstWebRTCDataChannel * channel, gchar * str)
 {
-  GST_LOG_OBJECT (channel, "Have string %p", str);
-  g_signal_emit (channel,
-      gst_webrtc_data_channel_signals[SIGNAL_ON_MESSAGE_STRING], 0, str);
+  gst_webrtc_data_channel_on_message_string (GST_WEBRTC_DATA_CHANNEL (channel),
+      str);
 }
 
 static GstFlowReturn
-_data_channel_have_sample (GstWebRTCDataChannel * channel, GstSample * sample,
+_data_channel_have_sample (WebRTCDataChannel * channel, GstSample * sample,
     GError ** error)
 {
   GstSctpReceiveMeta *receive;
@@ -678,7 +600,7 @@ _data_channel_have_sample (GstWebRTCDataChannel * channel, GstSample * sample,
 static GstFlowReturn
 on_sink_preroll (GstAppSink * sink, gpointer user_data)
 {
-  GstWebRTCDataChannel *channel = user_data;
+  WebRTCDataChannel *channel = user_data;
   GstSample *sample = gst_app_sink_pull_preroll (sink);
   GstFlowReturn ret;
 
@@ -703,7 +625,7 @@ on_sink_preroll (GstAppSink * sink, gpointer user_data)
 static GstFlowReturn
 on_sink_sample (GstAppSink * sink, gpointer user_data)
 {
-  GstWebRTCDataChannel *channel = user_data;
+  WebRTCDataChannel *channel = user_data;
   GstSample *sample = gst_app_sink_pull_sample (sink);
   GstFlowReturn ret;
   GError *error = NULL;
@@ -734,23 +656,24 @@ static GstAppSinkCallbacks sink_callbacks = {
 };
 
 void
-gst_webrtc_data_channel_start_negotiation (GstWebRTCDataChannel * channel)
+webrtc_data_channel_start_negotiation (WebRTCDataChannel * channel)
 {
   GstBuffer *buffer;
 
-  g_return_if_fail (!channel->negotiated);
-  g_return_if_fail (channel->id != -1);
+  g_return_if_fail (!channel->parent.negotiated);
+  g_return_if_fail (channel->parent.id != -1);
   g_return_if_fail (channel->sctp_transport != NULL);
 
   buffer = construct_open_packet (channel);
 
   GST_INFO_OBJECT (channel, "Sending channel open for SCTP stream %i "
-      "label %s protocol %s ordered %s", channel->id, channel->label,
-      channel->protocol, channel->ordered ? "true" : "false");
+      "label %s protocol %s ordered %s", channel->parent.id,
+      channel->parent.label, channel->parent.protocol,
+      channel->parent.ordered ? "true" : "false");
 
-  CHANNEL_LOCK (channel);
-  channel->buffered_amount += gst_buffer_get_size (buffer);
-  CHANNEL_UNLOCK (channel);
+  GST_WEBRTC_DATA_CHANNEL_LOCK (channel);
+  channel->parent.buffered_amount += gst_buffer_get_size (buffer);
+  GST_WEBRTC_DATA_CHANNEL_UNLOCK (channel);
 
   if (gst_app_src_push_buffer (GST_APP_SRC (channel->appsrc),
           buffer) == GST_FLOW_OK) {
@@ -767,15 +690,15 @@ gst_webrtc_data_channel_start_negotiation (GstWebRTCDataChannel * channel)
 }
 
 static void
-_get_sctp_reliability (GstWebRTCDataChannel * channel,
+_get_sctp_reliability (WebRTCDataChannel * channel,
     GstSctpSendMetaPartiallyReliability * reliability, guint * rel_param)
 {
-  if (channel->max_retransmits != -1) {
+  if (channel->parent.max_retransmits != -1) {
     *reliability = GST_SCTP_SEND_META_PARTIAL_RELIABILITY_RTX;
-    *rel_param = channel->max_retransmits;
-  } else if (channel->max_packet_lifetime != -1) {
+    *rel_param = channel->parent.max_retransmits;
+  } else if (channel->parent.max_packet_lifetime != -1) {
     *reliability = GST_SCTP_SEND_META_PARTIAL_RELIABILITY_TTL;
-    *rel_param = channel->max_packet_lifetime;
+    *rel_param = channel->parent.max_packet_lifetime;
   } else {
     *reliability = GST_SCTP_SEND_META_PARTIAL_RELIABILITY_NONE;
     *rel_param = 0;
@@ -783,15 +706,16 @@ _get_sctp_reliability (GstWebRTCDataChannel * channel,
 }
 
 static gboolean
-_is_within_max_message_size (GstWebRTCDataChannel * channel, gsize size)
+_is_within_max_message_size (WebRTCDataChannel * channel, gsize size)
 {
   return size <= channel->sctp_transport->max_message_size;
 }
 
 static void
-gst_webrtc_data_channel_send_data (GstWebRTCDataChannel * channel,
+webrtc_data_channel_send_data (GstWebRTCDataChannel * base_channel,
     GBytes * bytes)
 {
+  WebRTCDataChannel *channel = WEBRTC_DATA_CHANNEL (base_channel);
   GstSctpSendMetaPartiallyReliability reliability;
   guint rel_param;
   guint32 ppid;
@@ -824,15 +748,15 @@ gst_webrtc_data_channel_send_data (GstWebRTCDataChannel * channel,
   }
 
   _get_sctp_reliability (channel, &reliability, &rel_param);
-  gst_sctp_buffer_add_send_meta (buffer, ppid, channel->ordered, reliability,
-      rel_param);
+  gst_sctp_buffer_add_send_meta (buffer, ppid, channel->parent.ordered,
+      reliability, rel_param);
 
   GST_LOG_OBJECT (channel, "Sending data using buffer %" GST_PTR_FORMAT,
       buffer);
 
-  CHANNEL_LOCK (channel);
-  channel->buffered_amount += gst_buffer_get_size (buffer);
-  CHANNEL_UNLOCK (channel);
+  GST_WEBRTC_DATA_CHANNEL_LOCK (channel);
+  channel->parent.buffered_amount += gst_buffer_get_size (buffer);
+  GST_WEBRTC_DATA_CHANNEL_UNLOCK (channel);
 
   ret = gst_app_src_push_buffer (GST_APP_SRC (channel->appsrc), buffer);
 
@@ -846,16 +770,17 @@ gst_webrtc_data_channel_send_data (GstWebRTCDataChannel * channel,
 }
 
 static void
-gst_webrtc_data_channel_send_string (GstWebRTCDataChannel * channel,
-    gchar * str)
+webrtc_data_channel_send_string (GstWebRTCDataChannel * base_channel,
+    const gchar * str)
 {
+  WebRTCDataChannel *channel = WEBRTC_DATA_CHANNEL (base_channel);
   GstSctpSendMetaPartiallyReliability reliability;
   guint rel_param;
   guint32 ppid;
   GstBuffer *buffer;
   GstFlowReturn ret;
 
-  if (!channel->negotiated)
+  if (!channel->parent.negotiated)
     g_return_if_fail (channel->opened);
   g_return_if_fail (channel->sctp_transport != NULL);
 
@@ -884,15 +809,15 @@ gst_webrtc_data_channel_send_string (GstWebRTCDataChannel * channel,
   }
 
   _get_sctp_reliability (channel, &reliability, &rel_param);
-  gst_sctp_buffer_add_send_meta (buffer, ppid, channel->ordered, reliability,
-      rel_param);
+  gst_sctp_buffer_add_send_meta (buffer, ppid, channel->parent.ordered,
+      reliability, rel_param);
 
   GST_TRACE_OBJECT (channel, "Sending string using buffer %" GST_PTR_FORMAT,
       buffer);
 
-  CHANNEL_LOCK (channel);
-  channel->buffered_amount += gst_buffer_get_size (buffer);
-  CHANNEL_UNLOCK (channel);
+  GST_WEBRTC_DATA_CHANNEL_LOCK (channel);
+  channel->parent.buffered_amount += gst_buffer_get_size (buffer);
+  GST_WEBRTC_DATA_CHANNEL_UNLOCK (channel);
 
   ret = gst_app_src_push_buffer (GST_APP_SRC (channel->appsrc), buffer);
 
@@ -907,128 +832,37 @@ gst_webrtc_data_channel_send_string (GstWebRTCDataChannel * channel,
 
 static void
 _on_sctp_notify_state_unlocked (GObject * sctp_transport,
-    GstWebRTCDataChannel * channel)
+    WebRTCDataChannel * channel)
 {
   GstWebRTCSCTPTransportState state;
 
   g_object_get (sctp_transport, "state", &state, NULL);
   if (state == GST_WEBRTC_SCTP_TRANSPORT_STATE_CONNECTED) {
-    if (channel->negotiated)
+    if (channel->parent.negotiated)
       _channel_enqueue_task (channel, (ChannelTask) _emit_on_open, NULL, NULL);
   }
 }
 
 static void
 _on_sctp_notify_state (GObject * sctp_transport, GParamSpec * pspec,
-    GstWebRTCDataChannel * channel)
+    WebRTCDataChannel * channel)
 {
-  CHANNEL_LOCK (channel);
+  GST_WEBRTC_DATA_CHANNEL_LOCK (channel);
   _on_sctp_notify_state_unlocked (sctp_transport, channel);
-  CHANNEL_UNLOCK (channel);
-}
-
-static void
-gst_webrtc_data_channel_set_property (GObject * object, guint prop_id,
-    const GValue * value, GParamSpec * pspec)
-{
-  GstWebRTCDataChannel *channel = GST_WEBRTC_DATA_CHANNEL (object);
-
-  CHANNEL_LOCK (channel);
-  switch (prop_id) {
-    case PROP_LABEL:
-      channel->label = g_value_dup_string (value);
-      break;
-    case PROP_ORDERED:
-      channel->ordered = g_value_get_boolean (value);
-      break;
-    case PROP_MAX_PACKET_LIFETIME:
-      channel->max_packet_lifetime = g_value_get_int (value);
-      break;
-    case PROP_MAX_RETRANSMITS:
-      channel->max_retransmits = g_value_get_int (value);
-      break;
-    case PROP_PROTOCOL:
-      channel->protocol = g_value_dup_string (value);
-      break;
-    case PROP_NEGOTIATED:
-      channel->negotiated = g_value_get_boolean (value);
-      break;
-    case PROP_ID:
-      channel->id = g_value_get_int (value);
-      break;
-    case PROP_PRIORITY:
-      channel->priority = g_value_get_enum (value);
-      break;
-    case PROP_BUFFERED_AMOUNT_LOW_THRESHOLD:
-      channel->buffered_amount_low_threshold = g_value_get_uint64 (value);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-  }
-  CHANNEL_UNLOCK (channel);
-}
-
-static void
-gst_webrtc_data_channel_get_property (GObject * object, guint prop_id,
-    GValue * value, GParamSpec * pspec)
-{
-  GstWebRTCDataChannel *channel = GST_WEBRTC_DATA_CHANNEL (object);
-
-  CHANNEL_LOCK (channel);
-  switch (prop_id) {
-    case PROP_LABEL:
-      g_value_set_string (value, channel->label);
-      break;
-    case PROP_ORDERED:
-      g_value_set_boolean (value, channel->ordered);
-      break;
-    case PROP_MAX_PACKET_LIFETIME:
-      g_value_set_int (value, channel->max_packet_lifetime);
-      break;
-    case PROP_MAX_RETRANSMITS:
-      g_value_set_int (value, channel->max_retransmits);
-      break;
-    case PROP_PROTOCOL:
-      g_value_set_string (value, channel->protocol);
-      break;
-    case PROP_NEGOTIATED:
-      g_value_set_boolean (value, channel->negotiated);
-      break;
-    case PROP_ID:
-      g_value_set_int (value, channel->id);
-      break;
-    case PROP_PRIORITY:
-      g_value_set_enum (value, channel->priority);
-      break;
-    case PROP_READY_STATE:
-      g_value_set_enum (value, channel->ready_state);
-      break;
-    case PROP_BUFFERED_AMOUNT:
-      g_value_set_uint64 (value, channel->buffered_amount);
-      break;
-    case PROP_BUFFERED_AMOUNT_LOW_THRESHOLD:
-      g_value_set_uint64 (value, channel->buffered_amount_low_threshold);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-  }
-  CHANNEL_UNLOCK (channel);
+  GST_WEBRTC_DATA_CHANNEL_UNLOCK (channel);
 }
 
 static void
-_emit_low_threshold (GstWebRTCDataChannel * channel, gpointer user_data)
+_emit_low_threshold (WebRTCDataChannel * channel, gpointer user_data)
 {
-  GST_LOG_OBJECT (channel, "Low threshold reached");
-  g_signal_emit (channel,
-      gst_webrtc_data_channel_signals[SIGNAL_ON_BUFFERED_AMOUNT_LOW], 0);
+  gst_webrtc_data_channel_on_buffered_amount_low (GST_WEBRTC_DATA_CHANNEL
+      (channel));
 }
 
 static GstPadProbeReturn
 on_appsrc_data (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
 {
-  GstWebRTCDataChannel *channel = user_data;
+  WebRTCDataChannel *channel = user_data;
   guint64 prev_amount;
   guint64 size = 0;
 
@@ -1041,25 +875,27 @@ on_appsrc_data (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
   }
 
   if (size > 0) {
-    CHANNEL_LOCK (channel);
-    prev_amount = channel->buffered_amount;
-    channel->buffered_amount -= size;
+    GST_WEBRTC_DATA_CHANNEL_LOCK (channel);
+    prev_amount = channel->parent.buffered_amount;
+    channel->parent.buffered_amount -= size;
     GST_TRACE_OBJECT (channel, "checking low-threshold: prev %"
         G_GUINT64_FORMAT " low-threshold %" G_GUINT64_FORMAT " buffered %"
-        G_GUINT64_FORMAT, prev_amount, channel->buffered_amount_low_threshold,
-        channel->buffered_amount);
-    if (prev_amount >= channel->buffered_amount_low_threshold &&
-        channel->buffered_amount < channel->buffered_amount_low_threshold) {
-      _channel_enqueue_task (channel, (ChannelTask) _emit_low_threshold,
-          NULL, NULL);
+        G_GUINT64_FORMAT, prev_amount,
+        channel->parent.buffered_amount_low_threshold,
+        channel->parent.buffered_amount);
+    if (prev_amount >= channel->parent.buffered_amount_low_threshold
+        && channel->parent.buffered_amount <
+        channel->parent.buffered_amount_low_threshold) {
+      _channel_enqueue_task (channel, (ChannelTask) _emit_low_threshold, NULL,
+          NULL);
     }
 
-    if (channel->ready_state == GST_WEBRTC_DATA_CHANNEL_STATE_CLOSING
-        && channel->buffered_amount <= 0) {
+    if (channel->parent.ready_state == GST_WEBRTC_DATA_CHANNEL_STATE_CLOSING
+        && channel->parent.buffered_amount <= 0) {
       _channel_enqueue_task (channel, (ChannelTask) _close_sctp_stream, NULL,
           NULL);
     }
-    CHANNEL_UNLOCK (channel);
+    GST_WEBRTC_DATA_CHANNEL_UNLOCK (channel);
   }
 
   return GST_PAD_PROBE_OK;
@@ -1068,7 +904,7 @@ on_appsrc_data (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
 static void
 gst_webrtc_data_channel_constructed (GObject * object)
 {
-  GstWebRTCDataChannel *channel = GST_WEBRTC_DATA_CHANNEL (object);
+  WebRTCDataChannel *channel = WEBRTC_DATA_CHANNEL (object);
   GstPad *pad;
   GstCaps *caps;
 
@@ -1095,7 +931,7 @@ gst_webrtc_data_channel_constructed (GObject * object)
 static void
 gst_webrtc_data_channel_finalize (GObject * object)
 {
-  GstWebRTCDataChannel *channel = GST_WEBRTC_DATA_CHANNEL (object);
+  WebRTCDataChannel *channel = WEBRTC_DATA_CHANNEL (object);
 
   if (channel->src_probe) {
     GstPad *pad = gst_element_get_static_pad (channel->appsrc, "src");
@@ -1104,12 +940,6 @@ gst_webrtc_data_channel_finalize (GObject * object)
     channel->src_probe = 0;
   }
 
-  g_free (channel->label);
-  channel->label = NULL;
-
-  g_free (channel->protocol);
-  channel->protocol = NULL;
-
   if (channel->sctp_transport)
     g_signal_handlers_disconnect_by_data (channel->sctp_transport, channel);
   g_clear_object (&channel->sctp_transport);
@@ -1117,207 +947,37 @@ gst_webrtc_data_channel_finalize (GObject * object)
   g_clear_object (&channel->appsrc);
   g_clear_object (&channel->appsink);
 
-  g_mutex_clear (&channel->lock);
-
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
 static void
-gst_webrtc_data_channel_class_init (GstWebRTCDataChannelClass * klass)
+webrtc_data_channel_class_init (WebRTCDataChannelClass * klass)
 {
   GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstWebRTCDataChannelClass *channel_class =
+      (GstWebRTCDataChannelClass *) klass;
 
   gobject_class->constructed = gst_webrtc_data_channel_constructed;
-  gobject_class->get_property = gst_webrtc_data_channel_get_property;
-  gobject_class->set_property = gst_webrtc_data_channel_set_property;
   gobject_class->finalize = gst_webrtc_data_channel_finalize;
 
-  g_object_class_install_property (gobject_class,
-      PROP_LABEL,
-      g_param_spec_string ("label",
-          "Label", "Data channel label",
-          NULL,
-          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
-
-  g_object_class_install_property (gobject_class,
-      PROP_ORDERED,
-      g_param_spec_boolean ("ordered",
-          "Ordered", "Using ordered transmission mode",
-          FALSE,
-          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
-
-  g_object_class_install_property (gobject_class,
-      PROP_MAX_PACKET_LIFETIME,
-      g_param_spec_int ("max-packet-lifetime",
-          "Maximum Packet Lifetime",
-          "Maximum number of milliseconds that transmissions and "
-          "retransmissions may occur in unreliable mode (-1 = unset)",
-          -1, G_MAXUINT16, -1,
-          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
-
-  g_object_class_install_property (gobject_class,
-      PROP_MAX_RETRANSMITS,
-      g_param_spec_int ("max-retransmits",
-          "Maximum Retransmits",
-          "Maximum number of retransmissions attempted in unreliable mode",
-          -1, G_MAXUINT16, 0,
-          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
-
-  g_object_class_install_property (gobject_class,
-      PROP_PROTOCOL,
-      g_param_spec_string ("protocol",
-          "Protocol", "Data channel protocol",
-          "",
-          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
-
-  g_object_class_install_property (gobject_class,
-      PROP_NEGOTIATED,
-      g_param_spec_boolean ("negotiated",
-          "Negotiated",
-          "Whether this data channel was negotiated by the application", FALSE,
-          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
-
-  g_object_class_install_property (gobject_class,
-      PROP_ID,
-      g_param_spec_int ("id",
-          "ID",
-          "ID negotiated by this data channel (-1 = unset)",
-          -1, G_MAXUINT16, -1,
-          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
-
-  g_object_class_install_property (gobject_class,
-      PROP_PRIORITY,
-      g_param_spec_enum ("priority",
-          "Priority",
-          "The priority of data sent using this data channel",
-          GST_TYPE_WEBRTC_PRIORITY_TYPE,
-          GST_WEBRTC_PRIORITY_TYPE_LOW,
-          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
-
-  g_object_class_install_property (gobject_class,
-      PROP_READY_STATE,
-      g_param_spec_enum ("ready-state",
-          "Ready State",
-          "The Ready state of this data channel",
-          GST_TYPE_WEBRTC_DATA_CHANNEL_STATE,
-          GST_WEBRTC_DATA_CHANNEL_STATE_NEW,
-          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-
-  g_object_class_install_property (gobject_class,
-      PROP_BUFFERED_AMOUNT,
-      g_param_spec_uint64 ("buffered-amount",
-          "Buffered Amount",
-          "The amount of data in bytes currently buffered",
-          0, G_MAXUINT64, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-
-  g_object_class_install_property (gobject_class,
-      PROP_BUFFERED_AMOUNT_LOW_THRESHOLD,
-      g_param_spec_uint64 ("buffered-amount-low-threshold",
-          "Buffered Amount Low Threshold",
-          "The threshold at which the buffered amount is considered low and "
-          "the buffered-amount-low signal is emitted",
-          0, G_MAXUINT64, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
-  /**
-   * GstWebRTCDataChannel::on-open:
-   * @object: the #GstWebRTCDataChannel
-   */
-  gst_webrtc_data_channel_signals[SIGNAL_ON_OPEN] =
-      g_signal_new ("on-open", G_TYPE_FROM_CLASS (klass),
-      G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
-
-  /**
-   * GstWebRTCDataChannel::on-close:
-   * @object: the #GstWebRTCDataChannel
-   */
-  gst_webrtc_data_channel_signals[SIGNAL_ON_CLOSE] =
-      g_signal_new ("on-close", G_TYPE_FROM_CLASS (klass),
-      G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
-
-  /**
-   * GstWebRTCDataChannel::on-error:
-   * @object: the #GstWebRTCDataChannel
-   * @error: the #GError thrown
-   */
-  gst_webrtc_data_channel_signals[SIGNAL_ON_ERROR] =
-      g_signal_new ("on-error", G_TYPE_FROM_CLASS (klass),
-      G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_ERROR);
-
-  /**
-   * GstWebRTCDataChannel::on-message-data:
-   * @object: the #GstWebRTCDataChannel
-   * @data: (nullable): a #GBytes of the data received
-   */
-  gst_webrtc_data_channel_signals[SIGNAL_ON_MESSAGE_DATA] =
-      g_signal_new ("on-message-data", G_TYPE_FROM_CLASS (klass),
-      G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_BYTES);
-
-  /**
-   * GstWebRTCDataChannel::on-message-string:
-   * @object: the #GstWebRTCDataChannel
-   * @data: (nullable): the data received as a string
-   */
-  gst_webrtc_data_channel_signals[SIGNAL_ON_MESSAGE_STRING] =
-      g_signal_new ("on-message-string", G_TYPE_FROM_CLASS (klass),
-      G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_STRING);
-
-  /**
-   * GstWebRTCDataChannel::on-buffered-amount-low:
-   * @object: the #GstWebRTCDataChannel
-   */
-  gst_webrtc_data_channel_signals[SIGNAL_ON_BUFFERED_AMOUNT_LOW] =
-      g_signal_new ("on-buffered-amount-low", G_TYPE_FROM_CLASS (klass),
-      G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
-
-  /**
-   * GstWebRTCDataChannel::send-data:
-   * @object: the #GstWebRTCDataChannel
-   * @data: (nullable): a #GBytes with the data
-   */
-  gst_webrtc_data_channel_signals[SIGNAL_SEND_DATA] =
-      g_signal_new_class_handler ("send-data", G_TYPE_FROM_CLASS (klass),
-      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
-      G_CALLBACK (gst_webrtc_data_channel_send_data), NULL, NULL, NULL,
-      G_TYPE_NONE, 1, G_TYPE_BYTES);
-
-  /**
-   * GstWebRTCDataChannel::send-string:
-   * @object: the #GstWebRTCDataChannel
-   * @data: (nullable): the data to send as a string
-   */
-  gst_webrtc_data_channel_signals[SIGNAL_SEND_STRING] =
-      g_signal_new_class_handler ("send-string", G_TYPE_FROM_CLASS (klass),
-      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
-      G_CALLBACK (gst_webrtc_data_channel_send_string), NULL, NULL, NULL,
-      G_TYPE_NONE, 1, G_TYPE_STRING);
-
-  /**
-   * GstWebRTCDataChannel::close:
-   * @object: the #GstWebRTCDataChannel
-   *
-   * Close the data channel
-   */
-  gst_webrtc_data_channel_signals[SIGNAL_CLOSE] =
-      g_signal_new_class_handler ("close", G_TYPE_FROM_CLASS (klass),
-      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
-      G_CALLBACK (gst_webrtc_data_channel_close), NULL, NULL, NULL,
-      G_TYPE_NONE, 0);
+  channel_class->send_data = webrtc_data_channel_send_data;
+  channel_class->send_string = webrtc_data_channel_send_string;
+  channel_class->close = webrtc_data_channel_close;
 }
 
 static void
-gst_webrtc_data_channel_init (GstWebRTCDataChannel * channel)
+webrtc_data_channel_init (WebRTCDataChannel * channel)
 {
-  g_mutex_init (&channel->lock);
 }
 
 static void
-_data_channel_set_sctp_transport (GstWebRTCDataChannel * channel,
+_data_channel_set_sctp_transport (WebRTCDataChannel * channel,
     GstWebRTCSCTPTransport * sctp)
 {
   g_return_if_fail (GST_IS_WEBRTC_DATA_CHANNEL (channel));
   g_return_if_fail (GST_IS_WEBRTC_SCTP_TRANSPORT (sctp));
 
-  CHANNEL_LOCK (channel);
+  GST_WEBRTC_DATA_CHANNEL_LOCK (channel);
   if (channel->sctp_transport)
     g_signal_handlers_disconnect_by_data (channel->sctp_transport, channel);
 
@@ -1331,11 +991,11 @@ _data_channel_set_sctp_transport (GstWebRTCDataChannel * channel,
         channel);
     _on_sctp_notify_state_unlocked (G_OBJECT (sctp), channel);
   }
-  CHANNEL_UNLOCK (channel);
+  GST_WEBRTC_DATA_CHANNEL_UNLOCK (channel);
 }
 
 void
-gst_webrtc_data_channel_link_to_sctp (GstWebRTCDataChannel * channel,
+webrtc_data_channel_link_to_sctp (WebRTCDataChannel * channel,
     GstWebRTCSCTPTransport * sctp_transport)
 {
   if (sctp_transport && !channel->sctp_transport) {
index 6fd1536..7ca3c0d 100644 (file)
  * Boston, MA 02110-1301, USA.
  */
 
-#ifndef __GST_WEBRTC_DATA_CHANNEL_H__
-#define __GST_WEBRTC_DATA_CHANNEL_H__
+#ifndef __WEBRTC_DATA_CHANNEL_H__
+#define __WEBRTC_DATA_CHANNEL_H__
 
 #include <gst/gst.h>
 #include <gst/webrtc/webrtc_fwd.h>
 #include <gst/webrtc/dtlstransport.h>
+#include <gst/webrtc/datachannel.h>
 #include "sctptransport.h"
 
 G_BEGIN_DECLS
 
-GType gst_webrtc_data_channel_get_type(void);
-#define GST_TYPE_WEBRTC_DATA_CHANNEL            (gst_webrtc_data_channel_get_type())
-#define GST_WEBRTC_DATA_CHANNEL(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_WEBRTC_DATA_CHANNEL,GstWebRTCDataChannel))
-#define GST_IS_WEBRTC_DATA_CHANNEL(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_WEBRTC_DATA_CHANNEL))
-#define GST_WEBRTC_DATA_CHANNEL_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_WEBRTC_DATA_CHANNEL,GstWebRTCDataChannelClass))
-#define GST_IS_WEBRTC_DATA_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_WEBRTC_DATA_CHANNEL))
-#define GST_WEBRTC_DATA_CHANNEL_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_WEBRTC_DATA_CHANNEL,GstWebRTCDataChannelClass))
+GType webrtc_data_channel_get_type(void);
+#define WEBRTC_TYPE_DATA_CHANNEL            (webrtc_data_channel_get_type())
+#define WEBRTC_DATA_CHANNEL(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),WEBRTC_TYPE_DATA_CHANNEL,WebRTCDataChannel))
+#define WEBRTC_IS_DATA_CHANNEL(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),WEBRTC_TYPE_DATA_CHANNEL))
+#define WEBRTC_DATA_CHANNEL_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass) ,WEBRTC_TYPE_DATA_CHANNEL,WebRTCDataChannelClass))
+#define WEBRTC_IS_DATA_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,WEBRTC_TYPE_DATA_CHANNEL))
+#define WEBRTC_DATA_CHANNEL_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj) ,WEBRTC_TYPE_DATA_CHANNEL,WebRTCDataChannelClass))
 
-typedef struct _GstWebRTCDataChannel GstWebRTCDataChannel;
-typedef struct _GstWebRTCDataChannelClass GstWebRTCDataChannelClass;
+typedef struct _WebRTCDataChannel WebRTCDataChannel;
+typedef struct _WebRTCDataChannelClass WebRTCDataChannelClass;
 
-struct _GstWebRTCDataChannel
+struct _WebRTCDataChannel
 {
-  GObject                         parent;
+  GstWebRTCDataChannel              parent;
 
   GstWebRTCSCTPTransport           *sctp_transport;
   GstElement                       *appsrc;
   GstElement                       *appsink;
 
-  gchar                            *label;
-  gboolean                          ordered;
-  guint                             max_packet_lifetime;
-  guint                             max_retransmits;
-  gchar                            *protocol;
-  gboolean                          negotiated;
-  gint                              id;
-  GstWebRTCPriorityType             priority;
-  GstWebRTCDataChannelState         ready_state;
-  guint64                           buffered_amount;
-  guint64                           buffered_amount_low_threshold;
-
   GstWebRTCBin                     *webrtcbin;
   gboolean                          opened;
   gulong                            src_probe;
   GError                           *stored_error;
-  GMutex                            lock;
 
   gpointer                          _padding[GST_PADDING];
 };
 
-struct _GstWebRTCDataChannelClass
+struct _WebRTCDataChannelClass
 {
-  GObjectClass            parent_class;
+  GstWebRTCDataChannelClass  parent_class;
 
   gpointer                  _padding[GST_PADDING];
 };
 
-void    gst_webrtc_data_channel_start_negotiation   (GstWebRTCDataChannel       *channel);
+void    webrtc_data_channel_start_negotiation   (WebRTCDataChannel       *channel);
 G_GNUC_INTERNAL
-void    gst_webrtc_data_channel_link_to_sctp (GstWebRTCDataChannel              *channel,
-                                              GstWebRTCSCTPTransport            *sctp_transport);
+void    webrtc_data_channel_link_to_sctp (WebRTCDataChannel                 *channel,
+                                          GstWebRTCSCTPTransport            *sctp_transport);
 
 G_END_DECLS
 
-#endif /* __GST_WEBRTC_DATA_CHANNEL_H__ */
+#endif /* __WEBRTC_DATA_CHANNEL_H__ */
diff --git a/gst-libs/gst/webrtc/datachannel.c b/gst-libs/gst/webrtc/datachannel.c
new file mode 100644 (file)
index 0000000..99cc4f4
--- /dev/null
@@ -0,0 +1,555 @@
+/* GStreamer
+ * Copyright (C) 2017 Matthew Waters <matthew@centricular.com>
+ * Copyright (C) 2020 Sebastian Dröge <sebastian@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:gstwebrtc-datachannel
+ * @short_description: RTCDataChannel object
+ * @title: GstWebRTCDataChannel
+ *
+ * <https://www.w3.org/TR/webrtc/#rtcdatachannel>
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "datachannel.h"
+
+#define GST_CAT_DEFAULT gst_webrtc_data_channel_debug
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+
+#define gst_webrtc_data_channel_parent_class parent_class
+G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstWebRTCDataChannel, gst_webrtc_data_channel,
+    G_TYPE_OBJECT, GST_DEBUG_CATEGORY_INIT (gst_webrtc_data_channel_debug,
+        "webrtcdatachannel", 0, "webrtcdatachannel"););
+
+enum
+{
+  SIGNAL_0,
+  SIGNAL_ON_OPEN,
+  SIGNAL_ON_CLOSE,
+  SIGNAL_ON_ERROR,
+  SIGNAL_ON_MESSAGE_DATA,
+  SIGNAL_ON_MESSAGE_STRING,
+  SIGNAL_ON_BUFFERED_AMOUNT_LOW,
+  SIGNAL_SEND_DATA,
+  SIGNAL_SEND_STRING,
+  SIGNAL_CLOSE,
+  LAST_SIGNAL,
+};
+
+enum
+{
+  PROP_0,
+  PROP_LABEL,
+  PROP_ORDERED,
+  PROP_MAX_PACKET_LIFETIME,
+  PROP_MAX_RETRANSMITS,
+  PROP_PROTOCOL,
+  PROP_NEGOTIATED,
+  PROP_ID,
+  PROP_PRIORITY,
+  PROP_READY_STATE,
+  PROP_BUFFERED_AMOUNT,
+  PROP_BUFFERED_AMOUNT_LOW_THRESHOLD,
+};
+
+static guint gst_webrtc_data_channel_signals[LAST_SIGNAL] = { 0 };
+
+static void
+gst_webrtc_data_channel_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstWebRTCDataChannel *channel = GST_WEBRTC_DATA_CHANNEL (object);
+
+  GST_WEBRTC_DATA_CHANNEL_LOCK (channel);
+  switch (prop_id) {
+    case PROP_LABEL:
+      channel->label = g_value_dup_string (value);
+      break;
+    case PROP_ORDERED:
+      channel->ordered = g_value_get_boolean (value);
+      break;
+    case PROP_MAX_PACKET_LIFETIME:
+      channel->max_packet_lifetime = g_value_get_int (value);
+      break;
+    case PROP_MAX_RETRANSMITS:
+      channel->max_retransmits = g_value_get_int (value);
+      break;
+    case PROP_PROTOCOL:
+      channel->protocol = g_value_dup_string (value);
+      break;
+    case PROP_NEGOTIATED:
+      channel->negotiated = g_value_get_boolean (value);
+      break;
+    case PROP_ID:
+      channel->id = g_value_get_int (value);
+      break;
+    case PROP_PRIORITY:
+      channel->priority = g_value_get_enum (value);
+      break;
+    case PROP_BUFFERED_AMOUNT_LOW_THRESHOLD:
+      channel->buffered_amount_low_threshold = g_value_get_uint64 (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+  GST_WEBRTC_DATA_CHANNEL_UNLOCK (channel);
+}
+
+static void
+gst_webrtc_data_channel_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstWebRTCDataChannel *channel = GST_WEBRTC_DATA_CHANNEL (object);
+
+  GST_WEBRTC_DATA_CHANNEL_LOCK (channel);
+  switch (prop_id) {
+    case PROP_LABEL:
+      g_value_set_string (value, channel->label);
+      break;
+    case PROP_ORDERED:
+      g_value_set_boolean (value, channel->ordered);
+      break;
+    case PROP_MAX_PACKET_LIFETIME:
+      g_value_set_int (value, channel->max_packet_lifetime);
+      break;
+    case PROP_MAX_RETRANSMITS:
+      g_value_set_int (value, channel->max_retransmits);
+      break;
+    case PROP_PROTOCOL:
+      g_value_set_string (value, channel->protocol);
+      break;
+    case PROP_NEGOTIATED:
+      g_value_set_boolean (value, channel->negotiated);
+      break;
+    case PROP_ID:
+      g_value_set_int (value, channel->id);
+      break;
+    case PROP_PRIORITY:
+      g_value_set_enum (value, channel->priority);
+      break;
+    case PROP_READY_STATE:
+      g_value_set_enum (value, channel->ready_state);
+      break;
+    case PROP_BUFFERED_AMOUNT:
+      g_value_set_uint64 (value, channel->buffered_amount);
+      break;
+    case PROP_BUFFERED_AMOUNT_LOW_THRESHOLD:
+      g_value_set_uint64 (value, channel->buffered_amount_low_threshold);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+  GST_WEBRTC_DATA_CHANNEL_UNLOCK (channel);
+}
+
+static void
+gst_webrtc_data_channel_finalize (GObject * object)
+{
+  GstWebRTCDataChannel *channel = GST_WEBRTC_DATA_CHANNEL (object);
+
+  g_free (channel->label);
+  channel->label = NULL;
+
+  g_free (channel->protocol);
+  channel->protocol = NULL;
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_webrtc_data_channel_class_init (GstWebRTCDataChannelClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+
+  gobject_class->get_property = gst_webrtc_data_channel_get_property;
+  gobject_class->set_property = gst_webrtc_data_channel_set_property;
+  gobject_class->finalize = gst_webrtc_data_channel_finalize;
+
+  g_object_class_install_property (gobject_class,
+      PROP_LABEL,
+      g_param_spec_string ("label",
+          "Label", "Data channel label",
+          NULL,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class,
+      PROP_ORDERED,
+      g_param_spec_boolean ("ordered",
+          "Ordered", "Using ordered transmission mode",
+          FALSE,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class,
+      PROP_MAX_PACKET_LIFETIME,
+      g_param_spec_int ("max-packet-lifetime",
+          "Maximum Packet Lifetime",
+          "Maximum number of milliseconds that transmissions and "
+          "retransmissions may occur in unreliable mode (-1 = unset)",
+          -1, G_MAXUINT16, -1,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class,
+      PROP_MAX_RETRANSMITS,
+      g_param_spec_int ("max-retransmits",
+          "Maximum Retransmits",
+          "Maximum number of retransmissions attempted in unreliable mode",
+          -1, G_MAXUINT16, 0,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class,
+      PROP_PROTOCOL,
+      g_param_spec_string ("protocol",
+          "Protocol", "Data channel protocol",
+          "",
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class,
+      PROP_NEGOTIATED,
+      g_param_spec_boolean ("negotiated",
+          "Negotiated",
+          "Whether this data channel was negotiated by the application", FALSE,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class,
+      PROP_ID,
+      g_param_spec_int ("id",
+          "ID",
+          "ID negotiated by this data channel (-1 = unset)",
+          -1, G_MAXUINT16, -1,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class,
+      PROP_PRIORITY,
+      g_param_spec_enum ("priority",
+          "Priority",
+          "The priority of data sent using this data channel",
+          GST_TYPE_WEBRTC_PRIORITY_TYPE,
+          GST_WEBRTC_PRIORITY_TYPE_LOW,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class,
+      PROP_READY_STATE,
+      g_param_spec_enum ("ready-state",
+          "Ready State",
+          "The Ready state of this data channel",
+          GST_TYPE_WEBRTC_DATA_CHANNEL_STATE,
+          GST_WEBRTC_DATA_CHANNEL_STATE_NEW,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class,
+      PROP_BUFFERED_AMOUNT,
+      g_param_spec_uint64 ("buffered-amount",
+          "Buffered Amount",
+          "The amount of data in bytes currently buffered",
+          0, G_MAXUINT64, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class,
+      PROP_BUFFERED_AMOUNT_LOW_THRESHOLD,
+      g_param_spec_uint64 ("buffered-amount-low-threshold",
+          "Buffered Amount Low Threshold",
+          "The threshold at which the buffered amount is considered low and "
+          "the buffered-amount-low signal is emitted",
+          0, G_MAXUINT64, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstWebRTCDataChannel::on-open:
+   * @object: the #GstWebRTCDataChannel
+   */
+  gst_webrtc_data_channel_signals[SIGNAL_ON_OPEN] =
+      g_signal_new ("on-open", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
+
+  /**
+   * GstWebRTCDataChannel::on-close:
+   * @object: the #GstWebRTCDataChannel
+   */
+  gst_webrtc_data_channel_signals[SIGNAL_ON_CLOSE] =
+      g_signal_new ("on-close", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
+
+  /**
+   * GstWebRTCDataChannel::on-error:
+   * @object: the #GstWebRTCDataChannel
+   * @error: the #GError thrown
+   */
+  gst_webrtc_data_channel_signals[SIGNAL_ON_ERROR] =
+      g_signal_new ("on-error", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_ERROR);
+
+  /**
+   * GstWebRTCDataChannel::on-message-data:
+   * @object: the #GstWebRTCDataChannel
+   * @data: (nullable): a #GBytes of the data received
+   */
+  gst_webrtc_data_channel_signals[SIGNAL_ON_MESSAGE_DATA] =
+      g_signal_new ("on-message-data", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_BYTES);
+
+  /**
+   * GstWebRTCDataChannel::on-message-string:
+   * @object: the #GstWebRTCDataChannel
+   * @data: (nullable): the data received as a string
+   */
+  gst_webrtc_data_channel_signals[SIGNAL_ON_MESSAGE_STRING] =
+      g_signal_new ("on-message-string", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_STRING);
+
+  /**
+   * GstWebRTCDataChannel::on-buffered-amount-low:
+   * @object: the #GstWebRTCDataChannel
+   */
+  gst_webrtc_data_channel_signals[SIGNAL_ON_BUFFERED_AMOUNT_LOW] =
+      g_signal_new ("on-buffered-amount-low", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
+
+  /**
+   * GstWebRTCDataChannel::send-data:
+   * @object: the #GstWebRTCDataChannel
+   * @data: (nullable): a #GBytes with the data
+   */
+  gst_webrtc_data_channel_signals[SIGNAL_SEND_DATA] =
+      g_signal_new_class_handler ("send-data", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+      G_CALLBACK (gst_webrtc_data_channel_send_data), NULL, NULL, NULL,
+      G_TYPE_NONE, 1, G_TYPE_BYTES);
+
+  /**
+   * GstWebRTCDataChannel::send-string:
+   * @object: the #GstWebRTCDataChannel
+   * @data: (nullable): the data to send as a string
+   */
+  gst_webrtc_data_channel_signals[SIGNAL_SEND_STRING] =
+      g_signal_new_class_handler ("send-string", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+      G_CALLBACK (gst_webrtc_data_channel_send_string), NULL, NULL, NULL,
+      G_TYPE_NONE, 1, G_TYPE_STRING);
+
+  /**
+   * GstWebRTCDataChannel::close:
+   * @object: the #GstWebRTCDataChannel
+   *
+   * Close the data channel
+   */
+  gst_webrtc_data_channel_signals[SIGNAL_CLOSE] =
+      g_signal_new_class_handler ("close", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+      G_CALLBACK (gst_webrtc_data_channel_close), NULL, NULL, NULL,
+      G_TYPE_NONE, 0);
+}
+
+static void
+gst_webrtc_data_channel_init (GstWebRTCDataChannel * channel)
+{
+  g_mutex_init (&channel->lock);
+}
+
+/**
+ * gst_webrtc_data_channel_on_open:
+ * @channel: a #GstWebRTCDataChannel
+ *
+ * Signal that the data channel was opened. Should only be used by subclasses.
+ */
+void
+gst_webrtc_data_channel_on_open (GstWebRTCDataChannel * channel)
+{
+  g_return_if_fail (GST_IS_WEBRTC_DATA_CHANNEL (channel));
+
+  GST_WEBRTC_DATA_CHANNEL_LOCK (channel);
+  if (channel->ready_state == GST_WEBRTC_DATA_CHANNEL_STATE_CLOSING ||
+      channel->ready_state == GST_WEBRTC_DATA_CHANNEL_STATE_CLOSED) {
+    GST_WEBRTC_DATA_CHANNEL_UNLOCK (channel);
+    return;
+  }
+
+  if (channel->ready_state != GST_WEBRTC_DATA_CHANNEL_STATE_OPEN) {
+    channel->ready_state = GST_WEBRTC_DATA_CHANNEL_STATE_OPEN;
+    GST_WEBRTC_DATA_CHANNEL_UNLOCK (channel);
+    g_object_notify (G_OBJECT (channel), "ready-state");
+
+    GST_INFO_OBJECT (channel, "We are open and ready for data!");
+  } else {
+    GST_WEBRTC_DATA_CHANNEL_UNLOCK (channel);
+  }
+
+  GST_INFO_OBJECT (channel, "Opened");
+
+  g_signal_emit (channel, gst_webrtc_data_channel_signals[SIGNAL_ON_OPEN], 0,
+      NULL);
+}
+
+/**
+ * gst_webrtc_data_channel_on_close:
+ * @channel: a #GstWebRTCDataChannel
+ *
+ * Signal that the data channel was closed. Should only be used by subclasses.
+ */
+void
+gst_webrtc_data_channel_on_close (GstWebRTCDataChannel * channel)
+{
+  g_return_if_fail (GST_IS_WEBRTC_DATA_CHANNEL (channel));
+
+  GST_INFO_OBJECT (channel, "Closed");
+
+  GST_WEBRTC_DATA_CHANNEL_LOCK (channel);
+  if (channel->ready_state == GST_WEBRTC_DATA_CHANNEL_STATE_CLOSED) {
+    GST_WEBRTC_DATA_CHANNEL_UNLOCK (channel);
+    return;
+  }
+
+  channel->ready_state = GST_WEBRTC_DATA_CHANNEL_STATE_CLOSED;
+  GST_WEBRTC_DATA_CHANNEL_UNLOCK (channel);
+
+  g_object_notify (G_OBJECT (channel), "ready-state");
+  GST_INFO_OBJECT (channel, "We are closed for data");
+
+  g_signal_emit (channel, gst_webrtc_data_channel_signals[SIGNAL_ON_CLOSE], 0,
+      NULL);
+}
+
+/**
+ * gst_webrtc_data_channel_on_error:
+ * @channel: a #GstWebRTCDataChannel
+ * @error: (transfer full): a #GError
+ *
+ * Signal that the data channel had an error. Should only be used by subclasses.
+ */
+void
+gst_webrtc_data_channel_on_error (GstWebRTCDataChannel * channel,
+    GError * error)
+{
+  g_return_if_fail (GST_IS_WEBRTC_DATA_CHANNEL (channel));
+  g_return_if_fail (error != NULL);
+
+  GST_WARNING_OBJECT (channel, "Error: %s", GST_STR_NULL (error->message));
+
+  g_signal_emit (channel, gst_webrtc_data_channel_signals[SIGNAL_ON_ERROR], 0,
+      error);
+}
+
+/**
+ * gst_webrtc_data_channel_on_message_data:
+ * @channel: a #GstWebRTCDataChannel
+ * @data: (nullable): a #GBytes or %NULL
+ *
+ * Signal that the data channel received a data message. Should only be used by subclasses.
+ */
+void
+gst_webrtc_data_channel_on_message_data (GstWebRTCDataChannel * channel,
+    GBytes * data)
+{
+  g_return_if_fail (GST_IS_WEBRTC_DATA_CHANNEL (channel));
+
+  GST_LOG_OBJECT (channel, "Have data %p", data);
+  g_signal_emit (channel,
+      gst_webrtc_data_channel_signals[SIGNAL_ON_MESSAGE_DATA], 0, data);
+}
+
+/**
+ * gst_webrtc_data_channel_on_message_string:
+ * @channel: a #GstWebRTCDataChannel
+ * @str: (nullable): a string or %NULL
+ *
+ * Signal that the data channel received a string message. Should only be used by subclasses.
+ */
+void
+gst_webrtc_data_channel_on_message_string (GstWebRTCDataChannel * channel,
+    const gchar * str)
+{
+  g_return_if_fail (GST_IS_WEBRTC_DATA_CHANNEL (channel));
+
+  GST_LOG_OBJECT (channel, "Have string %p", str);
+  g_signal_emit (channel,
+      gst_webrtc_data_channel_signals[SIGNAL_ON_MESSAGE_STRING], 0, str);
+}
+
+/**
+ * gst_webrtc_data_channel_on_buffered_amount_low:
+ * @channel: a #GstWebRTCDataChannel
+ *
+ * Signal that the data channel reached a low buffered amount. Should only be used by subclasses.
+ */
+void
+gst_webrtc_data_channel_on_buffered_amount_low (GstWebRTCDataChannel * channel)
+{
+  g_return_if_fail (GST_IS_WEBRTC_DATA_CHANNEL (channel));
+
+  GST_LOG_OBJECT (channel, "Low threshold reached");
+  g_signal_emit (channel,
+      gst_webrtc_data_channel_signals[SIGNAL_ON_BUFFERED_AMOUNT_LOW], 0);
+}
+
+/**
+ * gst_webrtc_data_channel_send_data:
+ * @channel: a #GstWebRTCDataChannel
+ * @data: (nullable): a #GBytes or %NULL
+ *
+ * Send @data as a data message over @channel.
+ */
+void
+gst_webrtc_data_channel_send_data (GstWebRTCDataChannel * channel,
+    GBytes * data)
+{
+  GstWebRTCDataChannelClass *klass;
+
+  g_return_if_fail (GST_IS_WEBRTC_DATA_CHANNEL (channel));
+
+  klass = GST_WEBRTC_DATA_CHANNEL_GET_CLASS (channel);
+  klass->send_data (channel, data);
+}
+
+/**
+ * gst_webrtc_data_channel_send_string:
+ * @channel: a #GstWebRTCDataChannel
+ * @str: (nullable): a string or %NULL
+ *
+ * Send @str as a string message over @channel.
+ */
+void
+gst_webrtc_data_channel_send_string (GstWebRTCDataChannel * channel,
+    const gchar * str)
+{
+  GstWebRTCDataChannelClass *klass;
+
+  g_return_if_fail (GST_IS_WEBRTC_DATA_CHANNEL (channel));
+
+  klass = GST_WEBRTC_DATA_CHANNEL_GET_CLASS (channel);
+  klass->send_string (channel, str);
+}
+
+/**
+ * gst_webrtc_data_channel_close:
+ * @channel: a #GstWebRTCDataChannel
+ *
+ * Close the @channel.
+ */
+void
+gst_webrtc_data_channel_close (GstWebRTCDataChannel * channel)
+{
+  GstWebRTCDataChannelClass *klass;
+
+  g_return_if_fail (GST_IS_WEBRTC_DATA_CHANNEL (channel));
+
+  klass = GST_WEBRTC_DATA_CHANNEL_GET_CLASS (channel);
+  klass->close (channel);
+}
diff --git a/gst-libs/gst/webrtc/datachannel.h b/gst-libs/gst/webrtc/datachannel.h
new file mode 100644 (file)
index 0000000..be2379c
--- /dev/null
@@ -0,0 +1,108 @@
+/* GStreamer
+ * Copyright (C) 2018 Matthew Waters <matthew@centricular.com>
+ * Copyright (C) 2020 Sebastian Dröge <sebastian@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_WEBRTC_DATA_CHANNEL_H__
+#define __GST_WEBRTC_DATA_CHANNEL_H__
+
+#include <gst/gst.h>
+#include <gst/webrtc/webrtc_fwd.h>
+
+G_BEGIN_DECLS
+
+GST_WEBRTC_API
+GType gst_webrtc_data_channel_get_type(void);
+
+#define GST_TYPE_WEBRTC_DATA_CHANNEL            (gst_webrtc_data_channel_get_type())
+#define GST_WEBRTC_DATA_CHANNEL(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_WEBRTC_DATA_CHANNEL,GstWebRTCDataChannel))
+#define GST_IS_WEBRTC_DATA_CHANNEL(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_WEBRTC_DATA_CHANNEL))
+#define GST_WEBRTC_DATA_CHANNEL_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_WEBRTC_DATA_CHANNEL,GstWebRTCDataChannelClass))
+#define GST_IS_WEBRTC_DATA_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_WEBRTC_DATA_CHANNEL))
+#define GST_WEBRTC_DATA_CHANNEL_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_WEBRTC_DATA_CHANNEL,GstWebRTCDataChannelClass))
+
+#define GST_WEBRTC_DATA_CHANNEL_LOCK(channel) g_mutex_lock(&((GstWebRTCDataChannel *)(channel))->lock)
+#define GST_WEBRTC_DATA_CHANNEL_UNLOCK(channel) g_mutex_unlock(&((GstWebRTCDataChannel *)(channel))->lock)
+
+/**
+ * GstWebRTCDataChannel:
+ */
+struct _GstWebRTCDataChannel
+{
+  GObject                           parent;
+
+  GMutex                            lock;
+
+  gchar                            *label;
+  gboolean                          ordered;
+  guint                             max_packet_lifetime;
+  guint                             max_retransmits;
+  gchar                            *protocol;
+  gboolean                          negotiated;
+  gint                              id;
+  GstWebRTCPriorityType             priority;
+  GstWebRTCDataChannelState         ready_state;
+  guint64                           buffered_amount;
+  guint64                           buffered_amount_low_threshold;
+
+  gpointer                         _padding[GST_PADDING];
+};
+
+struct _GstWebRTCDataChannelClass
+{
+  GObjectClass        parent_class;
+
+  void              (*send_data)   (GstWebRTCDataChannel * channel, GBytes *data);
+  void              (*send_string) (GstWebRTCDataChannel * channel, const gchar *str);
+  void              (*close)       (GstWebRTCDataChannel * channel);
+
+  gpointer           _padding[GST_PADDING];
+};
+
+GST_WEBRTC_API
+void gst_webrtc_data_channel_on_open (GstWebRTCDataChannel * channel);
+
+GST_WEBRTC_API
+void gst_webrtc_data_channel_on_close (GstWebRTCDataChannel * channel);
+
+GST_WEBRTC_API
+void gst_webrtc_data_channel_on_error (GstWebRTCDataChannel * channel, GError * error);
+
+GST_WEBRTC_API
+void gst_webrtc_data_channel_on_message_data (GstWebRTCDataChannel * channel, GBytes * data);
+
+GST_WEBRTC_API
+void gst_webrtc_data_channel_on_message_string (GstWebRTCDataChannel * channel, const gchar * str);
+
+GST_WEBRTC_API
+void gst_webrtc_data_channel_on_buffered_amount_low (GstWebRTCDataChannel * channel);
+
+GST_WEBRTC_API
+void gst_webrtc_data_channel_send_data (GstWebRTCDataChannel * channel, GBytes * data);
+
+GST_WEBRTC_API
+void gst_webrtc_data_channel_send_string (GstWebRTCDataChannel * channel, const gchar * str);
+
+GST_WEBRTC_API
+void gst_webrtc_data_channel_close (GstWebRTCDataChannel * channel);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstWebRTCDataChannel, g_object_unref)
+
+G_END_DECLS
+
+#endif /* __GST_WEBRTC_DATA_CHANNEL_H__ */
index a9f11dc..981083c 100644 (file)
@@ -5,6 +5,7 @@ webrtc_sources = [
   'rtpreceiver.c',
   'rtpsender.c',
   'rtptransceiver.c',
+  'datachannel.c',
 ]
 
 webrtc_headers = [
@@ -14,6 +15,7 @@ webrtc_headers = [
   'rtpreceiver.h',
   'rtpsender.h',
   'rtptransceiver.h',
+  'datachannel.h',
   'webrtc_fwd.h',
   'webrtc.h',
 ]
index 354c15c..e68a9db 100644 (file)
@@ -29,5 +29,6 @@
 #include <gst/webrtc/rtpreceiver.h>
 #include <gst/webrtc/rtpsender.h>
 #include <gst/webrtc/rtptransceiver.h>
+#include <gst/webrtc/datachannel.h>
 
 #endif /* __GST_WEBRTC_WEBRTC_H__ */
index 61c1aca..5c727d2 100644 (file)
@@ -59,6 +59,9 @@ typedef struct _GstWebRTCSessionDescription GstWebRTCSessionDescription;
 typedef struct _GstWebRTCRTPTransceiver GstWebRTCRTPTransceiver;
 typedef struct _GstWebRTCRTPTransceiverClass GstWebRTCRTPTransceiverClass;
 
+typedef struct _GstWebRTCDataChannel GstWebRTCDataChannel;
+typedef struct _GstWebRTCDataChannelClass GstWebRTCDataChannelClass;
+
 /**
  * GstWebRTCDTLSTransportState:
  * @GST_WEBRTC_DTLS_TRANSPORT_STATE_NEW: new