diff --git a/ext/webrtc/gstwebrtcbin.c b/ext/webrtc/gstwebrtcbin.c index b505b7511c..7920b19fdd 100644 --- a/ext/webrtc/gstwebrtcbin.c +++ b/ext/webrtc/gstwebrtcbin.c @@ -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); } diff --git a/ext/webrtc/webrtcdatachannel.c b/ext/webrtc/webrtcdatachannel.c index 0eb9f852a8..eccb0db16a 100644 --- a/ext/webrtc/webrtcdatachannel.c +++ b/ext/webrtc/webrtcdatachannel.c @@ -41,49 +41,14 @@ #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); + GST_WEBRTC_DATA_CHANNEL_UNLOCK (channel); } static void -_maybe_emit_on_error (GstWebRTCDataChannel * channel, GError * error) +_emit_on_open (WebRTCDataChannel * channel, gpointer user_data) { - 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_on_open (GST_WEBRTC_DATA_CHANNEL (channel)); } static void -_emit_on_open (GstWebRTCDataChannel * 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); - } -} - -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); + GST_WEBRTC_DATA_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); + 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 -_transport_closed (GstWebRTCDataChannel * channel, gpointer user_data) -{ - CHANNEL_LOCK (channel); - _transport_closed_unlocked (channel); - CHANNEL_UNLOCK (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); + GST_WEBRTC_DATA_CHANNEL_UNLOCK (channel); } static void -gst_webrtc_data_channel_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) +_emit_low_threshold (WebRTCDataChannel * channel, gpointer user_data) { - 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); -} - -static void -_emit_low_threshold (GstWebRTCDataChannel * 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) { diff --git a/ext/webrtc/webrtcdatachannel.h b/ext/webrtc/webrtcdatachannel.h index 6fd1536b98..7ca3c0d179 100644 --- a/ext/webrtc/webrtcdatachannel.h +++ b/ext/webrtc/webrtcdatachannel.h @@ -17,68 +17,56 @@ * 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 #include #include +#include #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 index 0000000000..99cc4f4ae1 --- /dev/null +++ b/gst-libs/gst/webrtc/datachannel.c @@ -0,0 +1,555 @@ +/* GStreamer + * Copyright (C) 2017 Matthew Waters + * Copyright (C) 2020 Sebastian Dröge + * + * 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 + * + * + */ + +#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 index 0000000000..be2379c936 --- /dev/null +++ b/gst-libs/gst/webrtc/datachannel.h @@ -0,0 +1,108 @@ +/* GStreamer + * Copyright (C) 2018 Matthew Waters + * Copyright (C) 2020 Sebastian Dröge + * + * 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 +#include + +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__ */ diff --git a/gst-libs/gst/webrtc/meson.build b/gst-libs/gst/webrtc/meson.build index a9f11dc593..981083c2e6 100644 --- a/gst-libs/gst/webrtc/meson.build +++ b/gst-libs/gst/webrtc/meson.build @@ -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', ] diff --git a/gst-libs/gst/webrtc/webrtc.h b/gst-libs/gst/webrtc/webrtc.h index 354c15c196..e68a9dba82 100644 --- a/gst-libs/gst/webrtc/webrtc.h +++ b/gst-libs/gst/webrtc/webrtc.h @@ -29,5 +29,6 @@ #include #include #include +#include #endif /* __GST_WEBRTC_WEBRTC_H__ */ diff --git a/gst-libs/gst/webrtc/webrtc_fwd.h b/gst-libs/gst/webrtc/webrtc_fwd.h index 61c1aca9e5..5c727d2344 100644 --- a/gst-libs/gst/webrtc/webrtc_fwd.h +++ b/gst-libs/gst/webrtc/webrtc_fwd.h @@ -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