Merge branch 'upstream/1.22.7' into tizen_gst_1.22.7
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / ext / webrtc / gstwebrtcbin.c
index f554ec2..55a7d71 100644 (file)
@@ -673,7 +673,12 @@ enum
   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 };
@@ -1560,10 +1565,36 @@ _collate_peer_connection_states (GstWebRTCBin * webrtc)
 #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);
@@ -1576,11 +1607,23 @@ _update_ice_gathering_state_task (GstWebRTCBin * webrtc, gpointer data)
     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;
 
@@ -1597,6 +1640,7 @@ _update_ice_gathering_state_task (GstWebRTCBin * webrtc, gpointer data)
     PC_LOCK (webrtc);
   }
 
+#endif
   return NULL;
 }
 
@@ -2044,7 +2088,9 @@ _find_codec_preferences (GstWebRTCBin * webrtc,
     }
 
     if (caps) {
+#ifndef TIZEN_FEATURE_WEBRTC_MODIFICATION
       if (trans)
+#endif
         gst_caps_replace (&trans->last_retrieved_caps, caps);
 
       ret = caps;
@@ -2427,6 +2473,16 @@ _create_webrtc_transceiver (GstWebRTCBin * webrtc,
   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)
 {
@@ -2495,6 +2551,10 @@ _on_data_channel_ready_state (WebRTCDataChannel * channel,
 
   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;
 
@@ -2507,6 +2567,9 @@ _on_data_channel_ready_state (WebRTCDataChannel * channel,
     }
 
     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);
@@ -2517,6 +2580,12 @@ _on_data_channel_ready_state (WebRTCDataChannel * channel,
     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);
 
@@ -5142,6 +5211,32 @@ _set_internal_rtpbin_element_props_from_stream (GstWebRTCBin * webrtc,
   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)
 {
@@ -5231,9 +5326,18 @@ _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);
@@ -5285,9 +5389,18 @@ _connect_output_stream (GstWebRTCBin * webrtc,
       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));
@@ -5480,9 +5593,15 @@ ensure_rtx_hdr_ext (TransportStream * stream)
       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);
@@ -5498,9 +5617,15 @@ ensure_rtx_hdr_ext (TransportStream * stream)
       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);
@@ -6002,9 +6127,18 @@ _connect_rtpfunnel (GstWebRTCBin * webrtc, guint session_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:
@@ -6862,6 +6996,13 @@ _on_local_ice_candidate_task (GstWebRTCBin * webrtc)
   }
   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;
 }
 
@@ -7061,7 +7202,9 @@ gst_webrtc_bin_create_data_channel (GstWebRTCBin * webrtc, const gchar * label,
   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))
@@ -7632,6 +7775,20 @@ on_rtpbin_ssrc_validated (GstElement * rtpbin, guint session_id, guint ssrc,
   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)
@@ -7640,6 +7797,9 @@ on_rtpbin_timeout (GstElement * rtpbin, guint session_id, guint ssrc,
 
   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);
 }
 
@@ -7657,6 +7817,9 @@ on_rtpbin_new_sender_ssrc (GstElement * rtpbin, guint session_id, guint ssrc,
       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) {
@@ -7887,6 +8050,9 @@ gst_webrtc_bin_change_state (GstElement * element, GstStateChange transition)
       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;
@@ -8183,7 +8349,11 @@ gst_webrtc_bin_release_pad (GstElement * element, GstPad * pad)
    * 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);
@@ -8223,6 +8393,27 @@ _update_rtpstorage_latency (GstWebRTCBin * 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)
@@ -8263,6 +8454,23 @@ gst_webrtc_bin_set_property (GObject * object, guint prop_id,
       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;
@@ -8344,6 +8552,17 @@ gst_webrtc_bin_get_property (GObject * object, guint prop_id,
       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;
@@ -8658,6 +8877,29 @@ gst_webrtc_bin_class_init (GstWebRTCBinClass * klass)
           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
@@ -8813,6 +9055,15 @@ gst_webrtc_bin_class_init (GstWebRTCBinClass * klass)
    *  "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,