PROP_ICE_AGENT,
PROP_LATENCY,
PROP_SCTP_TRANSPORT,
- PROP_HTTP_PROXY
+ PROP_HTTP_PROXY,
+#ifdef TIZEN_FEATURE_WEBRTC_IMPORT_NETSIM
+ PROP_NETSIM,
+ PROP_DROP_PROBABILITY_SENDER,
+ PROP_DROP_PROBABILITY_RECEIVER
+#endif
};
static guint gst_webrtc_bin_signals[LAST_SIGNAL] = { 0 };
#undef STATE
}
+#ifdef TIZEN_FEATURE_WEBRTC_MODIFICATION
+static void
+_update_and_notify_ice_gathering_state (GstWebRTCBin * webrtc, GstWebRTCICEGatheringState state)
+{
+ GstWebRTCICEGatheringState old_state = webrtc->ice_gathering_state;
+
+ if (state != webrtc->ice_gathering_state) {
+ const gchar *old_s, *new_s;
+
+ old_s = _enum_value_to_string (GST_TYPE_WEBRTC_ICE_GATHERING_STATE,
+ old_state);
+ new_s = _enum_value_to_string (GST_TYPE_WEBRTC_ICE_GATHERING_STATE,
+ state);
+ GST_INFO_OBJECT (webrtc, "ICE gathering state change from %s(%u) to %s(%u)",
+ old_s, old_state, new_s, state);
+
+ webrtc->ice_gathering_state = state;
+ PC_UNLOCK (webrtc);
+ g_object_notify (G_OBJECT (webrtc), "ice-gathering-state");
+ PC_LOCK (webrtc);
+ }
+}
+#endif
+
static GstStructure *
_update_ice_gathering_state_task (GstWebRTCBin * webrtc, gpointer data)
{
+#ifndef TIZEN_FEATURE_WEBRTC_MODIFICATION
GstWebRTCICEGatheringState old_state = webrtc->ice_gathering_state;
+#endif
GstWebRTCICEGatheringState new_state;
new_state = _collate_ice_gathering_states (webrtc);
ICE_LOCK (webrtc);
if (webrtc->priv->pending_local_ice_candidates->len != 0) {
/* ICE candidates queued for emissiong -> we're gathering, not complete */
+#ifdef TIZEN_FEATURE_WEBRTC_MODIFICATION
+ webrtc->pending_ice_gathering_state = GST_WEBRTC_ICE_GATHERING_STATE_COMPLETE;
+ GST_INFO_OBJECT (webrtc, "set pending_ice_gathering_state to (%u)",
+ webrtc->pending_ice_gathering_state);
+ ICE_UNLOCK (webrtc);
+ return NULL;
+ }
+#else
new_state = GST_WEBRTC_ICE_GATHERING_STATE_GATHERING;
}
+#endif
ICE_UNLOCK (webrtc);
}
+#ifdef TIZEN_FEATURE_WEBRTC_MODIFICATION
+ _update_and_notify_ice_gathering_state (webrtc, new_state);
+#else
if (new_state != webrtc->ice_gathering_state) {
const gchar *old_s, *new_s;
PC_LOCK (webrtc);
}
+#endif
return NULL;
}
}
if (caps) {
+#ifndef TIZEN_FEATURE_WEBRTC_MODIFICATION
if (trans)
+#endif
gst_caps_replace (&trans->last_retrieved_caps, caps);
ret = caps;
return trans;
}
+#ifdef TIZEN_FEATURE_WEBRTC_MODIFICATION
+static void
+_remove_webrtc_transceiver (GstWebRTCBin * webrtc,
+ GstWebRTCRTPTransceiver * trans)
+{
+ g_ptr_array_remove (webrtc->priv->transceivers, trans);
+ gst_object_unref (trans);
+}
+#endif
+
static TransportStream *
_create_transport_channel (GstWebRTCBin * webrtc, guint session_id)
{
g_object_get (channel, "ready-state", &ready_state, NULL);
+#ifdef TIZEN_FEATURE_WEBRTC_MODIFICATION
+ GST_TRACE_OBJECT (webrtc,
+ "%" GST_PTR_FORMAT " ready-state %u", channel, ready_state);
+#endif
if (ready_state == GST_WEBRTC_DATA_CHANNEL_STATE_OPEN) {
gboolean found;
}
g_ptr_array_add (webrtc->priv->data_channels, gst_object_ref (channel));
+#ifdef TIZEN_FEATURE_WEBRTC_MODIFICATION
+ webrtc->priv->data_channels_opened++;
+#endif
DC_UNLOCK (webrtc);
gst_webrtc_bin_update_sctp_priority (webrtc);
gboolean found;
DC_LOCK (webrtc);
+#ifdef TIZEN_FEATURE_WEBRTC_MODIFICATION
+ if (channel->parent.prev_ready_state == GST_WEBRTC_DATA_CHANNEL_STATE_OPEN ||
+ channel->parent.prev_ready_state == GST_WEBRTC_DATA_CHANNEL_STATE_CLOSING)
+ webrtc->priv->data_channels_closed++;
+
+#endif
found = g_ptr_array_remove (webrtc->priv->pending_data_channels, channel)
|| g_ptr_array_remove (webrtc->priv->data_channels, channel);
g_value_unset (&red_pt_array);
}
+#ifdef TIZEN_FEATURE_WEBRTC_IMPORT_NETSIM
+static void
+_insert_netsim_element_between (GstWebRTCBin * webrtc, GstElement * srcbin,
+ const gchar * srcpadname, GstElement * sinkbin, const gchar * sinkpadname,
+ guint idx)
+{
+ gboolean send = !g_strcmp0 (sinkpadname, "rtp_sink");
+ gchar *netsim_name = g_strdup_printf ("netsim_%s_%u",
+ send ? "send" : "recv", idx);
+ GstElement *netsim = gst_element_factory_make ("netsim", netsim_name);
+ g_free (netsim_name);
+
+ gst_bin_add (GST_BIN (webrtc), netsim);
+ g_object_set (netsim, "drop-probability",
+ send ? webrtc->priv->drop_probability_sender :
+ webrtc->priv->drop_probability_receiver, NULL);
+ gst_element_sync_state_with_parent (netsim);
+
+ if (!gst_element_link_pads (srcbin, srcpadname, netsim, "sink"))
+ g_warn_if_reached ();
+
+ if (!gst_element_link_pads (netsim, "src", sinkbin, sinkpadname))
+ g_warn_if_reached ();
+}
+#endif
+
static GstPad *
_connect_input_stream (GstWebRTCBin * webrtc, GstWebRTCBinPad * pad)
{
gst_object_unref (rtp_sink);
pad_name = g_strdup_printf ("send_rtp_src_%u", pad->trans->mline);
+#ifdef TIZEN_FEATURE_WEBRTC_IMPORT_NETSIM
+ if (webrtc->priv->netsim) {
+ _insert_netsim_element_between (webrtc, GST_ELEMENT (webrtc->rtpbin), pad_name,
+ GST_ELEMENT (trans->stream->send_bin), "rtp_sink", pad->trans->mline);
+ } else {
+#endif
if (!gst_element_link_pads (GST_ELEMENT (webrtc->rtpbin), pad_name,
GST_ELEMENT (trans->stream->send_bin), "rtp_sink"))
g_warn_if_reached ();
+#ifdef TIZEN_FEATURE_WEBRTC_IMPORT_NETSIM
+ }
+#endif
g_free (pad_name);
} else {
gchar *pad_name = g_strdup_printf ("sink_%u", pad->trans->mline);
session_id, stream);
pad_name = g_strdup_printf ("recv_rtp_sink_%u", session_id);
+#ifdef TIZEN_FEATURE_WEBRTC_IMPORT_NETSIM
+ if (webrtc->priv->netsim) {
+ _insert_netsim_element_between (webrtc, GST_ELEMENT (stream->receive_bin),
+ "rtp_src", GST_ELEMENT (webrtc->rtpbin), pad_name, session_id);
+ } else {
+#endif
if (!gst_element_link_pads (GST_ELEMENT (stream->receive_bin),
"rtp_src", GST_ELEMENT (webrtc->rtpbin), pad_name))
g_warn_if_reached ();
+#ifdef TIZEN_FEATURE_WEBRTC_IMPORT_NETSIM
+ }
+#endif
g_free (pad_name);
gst_element_sync_state_with_parent (GST_ELEMENT (stream->receive_bin));
gst_rtp_header_extension_set_id (stream->rtxreceive_stream_id,
stream->rtphdrext_id_stream_id);
+#ifdef TIZEN_FEATURE_WEBRTC_MODIFICATION
+ GST_DEBUG_OBJECT (stream, "adding rtp header extension %" GST_PTR_FORMAT
+ " with id %u to %" GST_PTR_FORMAT, stream->rtxreceive_stream_id,
+ stream->rtphdrext_id_stream_id, stream->rtxreceive);
+#else
GST_DEBUG_OBJECT (stream, "adding rtp header extension %" GST_PTR_FORMAT
" with id %u to %" GST_PTR_FORMAT, stream->rtxsend_stream_id,
stream->rtphdrext_id_stream_id, stream->rtxreceive);
+#endif
g_signal_emit_by_name (stream->rtxreceive, "add-extension",
stream->rtxreceive_stream_id);
gst_rtp_header_extension_set_id (stream->rtxreceive_repaired_stream_id,
stream->rtphdrext_id_repaired_stream_id);
+#ifdef TIZEN_FEATURE_WEBRTC_MODIFICATION
+ GST_DEBUG_OBJECT (stream, "adding rtp header extension %" GST_PTR_FORMAT
+ " with id %u to %" GST_PTR_FORMAT, stream->rtxreceive_repaired_stream_id,
+ stream->rtphdrext_id_repaired_stream_id, stream->rtxreceive);
+#else
GST_DEBUG_OBJECT (stream, "adding rtp header extension %" GST_PTR_FORMAT
" with id %u to %" GST_PTR_FORMAT, stream->rtxsend_repaired_stream_id,
stream->rtphdrext_id_repaired_stream_id, stream->rtxreceive);
+#endif
g_signal_emit_by_name (stream->rtxreceive, "add-extension",
stream->rtxreceive_repaired_stream_id);
gst_object_unref (rtp_sink);
pad_name = g_strdup_printf ("send_rtp_src_%d", session_id);
+#ifdef TIZEN_FEATURE_WEBRTC_IMPORT_NETSIM
+ if (webrtc->priv->netsim) {
+ _insert_netsim_element_between (webrtc, GST_ELEMENT (webrtc->rtpbin), pad_name,
+ GST_ELEMENT (stream->send_bin), "rtp_sink", session_id);
+ } else {
+#endif
if (!gst_element_link_pads (GST_ELEMENT (webrtc->rtpbin), pad_name,
GST_ELEMENT (stream->send_bin), "rtp_sink"))
g_warn_if_reached ();
+#ifdef TIZEN_FEATURE_WEBRTC_IMPORT_NETSIM
+ }
+#endif
g_free (pad_name);
done:
}
g_array_free (items, TRUE);
+#ifdef TIZEN_FEATURE_WEBRTC_MODIFICATION
+ if (webrtc->pending_ice_gathering_state == GST_WEBRTC_ICE_GATHERING_STATE_COMPLETE) {
+ _update_and_notify_ice_gathering_state (webrtc, GST_WEBRTC_ICE_GATHERING_STATE_COMPLETE);
+ webrtc->pending_ice_gathering_state = GST_WEBRTC_ICE_GATHERING_STATE_NEW;
+ }
+#endif
+
return NULL;
}
g_return_val_if_fail (GST_IS_WEBRTC_BIN (webrtc), NULL);
g_return_val_if_fail (label != NULL, NULL);
g_return_val_if_fail (strlen (label) <= 65535, NULL);
+#ifndef TIZEN_FEATURE_WEBRTC_MODIFICATION
g_return_val_if_fail (webrtc->priv->is_closed != TRUE, NULL);
+#endif
if (!init_params
|| !gst_structure_get_boolean (init_params, "ordered", &ordered))
GST_INFO_OBJECT (webrtc, "session %u ssrc %u validated", session_id, ssrc);
}
+#ifdef TIZEN_FEATURE_WEBRTC_SSRC_TIMEOUT_NOTIFICATION
+static void
+post_ssrc_timeout_error_msg (GstWebRTCBin *webrtc, guint ssrc)
+{
+ GError *err = g_error_new (GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_TOO_LAZY, "RTP session ssrc timeout happened");
+ gchar *debug = g_strdup_printf("timeout on ssrc %u", ssrc);
+ GstMessage *msg = gst_message_new_error (GST_OBJECT_CAST (webrtc), err, debug);
+ g_free (debug);
+ g_error_free (err);
+
+ gst_element_post_message (GST_ELEMENT_CAST (webrtc), msg);
+}
+#endif
+
static void
on_rtpbin_timeout (GstElement * rtpbin, guint session_id, guint ssrc,
GstWebRTCBin * webrtc)
PC_LOCK (webrtc);
remove_ssrc_entry_by_ssrc (webrtc, session_id, ssrc);
+#ifdef TIZEN_FEATURE_WEBRTC_SSRC_TIMEOUT_NOTIFICATION
+ post_ssrc_timeout_error_msg (webrtc, ssrc);
+#endif
PC_UNLOCK (webrtc);
}
GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDONLY, session_id, ssrc);
if (!mid) {
TransportStream *stream = _find_transport_for_session (webrtc, session_id);
+#ifdef TIZEN_FEATURE_WEBRTC_MODIFICATION
+ if (stream)
+#endif
transport_stream_add_ssrc_map_item (stream,
GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDONLY, ssrc, -1);
} else if (mid->mid) {
break;
case GST_STATE_CHANGE_READY_TO_NULL:
_stop_thread (webrtc);
+#ifdef TIZEN_FEATURE_WEBRTC_MODIFICATION
+ webrtc->priv->need_negotiation = FALSE;
+#endif
break;
default:
break;
* a possibly dead transceiver */
PC_LOCK (webrtc);
if (webrtc_pad->trans)
+#ifdef TIZEN_FEATURE_WEBRTC_MODIFICATION
+ _remove_webrtc_transceiver (webrtc, webrtc_pad->trans);
+#else
gst_object_unref (webrtc_pad->trans);
+#endif
webrtc_pad->trans = NULL;
gst_caps_replace (&webrtc_pad->received_caps, NULL);
PC_UNLOCK (webrtc);
}
}
+#ifdef TIZEN_FEATURE_WEBRTC_IMPORT_NETSIM
+static void
+_update_drop_probability (GstWebRTCBin * webrtc, gfloat probability, gboolean sender)
+{
+ GValue value = G_VALUE_INIT;
+ GstElement *element;
+ GstIterator *bin_iterator = gst_bin_iterate_sorted (GST_BIN (webrtc));
+ g_assert (bin_iterator);
+
+ while (gst_iterator_next (bin_iterator, &value) == GST_ITERATOR_OK) {
+ element = GST_ELEMENT (g_value_get_object (&value));
+ if (g_strrstr (GST_ELEMENT_NAME (element), sender ? "netsim_send" : "netsim_recv"))
+ g_object_set (element, "drop-probability", probability, NULL);
+ g_value_reset (&value);
+ }
+
+ g_value_unset (&value);
+ gst_iterator_free (bin_iterator);
+}
+#endif
+
static void
gst_webrtc_bin_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
gst_webrtc_ice_set_http_proxy (webrtc->priv->ice,
g_value_get_string (value));
break;
+#ifdef TIZEN_FEATURE_WEBRTC_IMPORT_NETSIM
+ case PROP_NETSIM:
+ webrtc->priv->netsim = g_value_get_boolean (value);
+ _update_drop_probability (webrtc, webrtc->priv->netsim ?
+ webrtc->priv->drop_probability_sender : 0.0, TRUE);
+ _update_drop_probability (webrtc, webrtc->priv->netsim ?
+ webrtc->priv->drop_probability_receiver : 0.0, FALSE);
+ break;
+ case PROP_DROP_PROBABILITY_SENDER:
+ webrtc->priv->drop_probability_sender = g_value_get_float (value);
+ _update_drop_probability (webrtc, webrtc->priv->drop_probability_sender, TRUE);
+ break;
+ case PROP_DROP_PROBABILITY_RECEIVER:
+ webrtc->priv->drop_probability_receiver = g_value_get_float (value);
+ _update_drop_probability (webrtc, webrtc->priv->drop_probability_receiver, FALSE);
+ break;
+#endif
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
g_value_take_string (value,
gst_webrtc_ice_get_http_proxy (webrtc->priv->ice));
break;
+#ifdef TIZEN_FEATURE_WEBRTC_IMPORT_NETSIM
+ case PROP_NETSIM:
+ g_value_set_boolean (value, webrtc->priv->netsim);
+ break;
+ case PROP_DROP_PROBABILITY_SENDER:
+ g_value_set_float (value, webrtc->priv->drop_probability_sender);
+ break;
+ case PROP_DROP_PROBABILITY_RECEIVER:
+ g_value_set_float (value, webrtc->priv->drop_probability_receiver);
+ break;
+#endif
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
GST_TYPE_WEBRTC_SCTP_TRANSPORT,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+#ifdef TIZEN_FEATURE_WEBRTC_IMPORT_NETSIM
+ g_object_class_install_property (gobject_class,
+ PROP_NETSIM,
+ g_param_spec_boolean ("netsim", "Use network simulator",
+ "Use network simulator for packet loss",
+ FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (gobject_class,
+ PROP_DROP_PROBABILITY_SENDER,
+ g_param_spec_float ("drop-probability-sender", "Drop Probability for sender",
+ "The Probability a sending RTP buffer is dropped",
+ 0.0, 1.0, 0.0,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (gobject_class,
+ PROP_DROP_PROBABILITY_RECEIVER,
+ g_param_spec_float ("drop-probability-receiver", "Drop Probability for receiver",
+ "The Probability a received RTP buffer is dropped",
+ 0.0, 1.0, 0.0,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+
+#endif
+
/**
* GstWebRTCBin::create-offer:
* @object: the #webrtcbin
* "local-candidate-id" G_TYPE_STRING unique identifier that is associated to the object that was inspected to produce the RTCIceCandidateStats for the local candidate associated with this candidate pair.
* "remote-candidate-id" G_TYPE_STRING unique identifier that is associated to the object that was inspected to produce the RTCIceCandidateStats for the remote candidate associated with this candidate pair.
*/
+#ifdef TIZEN_FEATURE_WEBRTC_MODIFICATION
+ /**
+ * RTCPeerConnectionStats supported fields (https://w3c.github.io/webrtc-stats/#pcstats-dict*)
+ *
+ * "data-channels-opened" G_TYPE_UINT number of unique data channels that have entered the 'open' state
+ * "data-channels-closed" G_TYPE_UINT number of unique data channels that have left the 'open' state
+ *
+ */
+#endif
gst_webrtc_bin_signals[GET_STATS_SIGNAL] =
g_signal_new_class_handler ("get-stats",
G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,