static void
kms_webrtc_rtcp_mux_connection_get_property (GObject * object,
    guint prop_id, GValue * value, GParamSpec * pspec)
{
  KmsWebRtcRtcpMuxConnection *self = KMS_WEBRTC_RTCP_MUX_CONNECTION (object);

  switch (prop_id) {
    case PROP_ADDED:
      g_value_set_boolean (value, self->priv->added);
      break;
    case PROP_CONNECTED:
      g_value_set_boolean (value, self->priv->connected);
      break;
    case PROP_IS_CLIENT:{
      gboolean is_client;

      g_object_get (G_OBJECT (self->priv->tr->sink->dtlssrtpenc), "is-client",
          &is_client, NULL);
      g_value_set_boolean (value, is_client);
      break;
    }
    case PROP_MIN_PORT:
      g_value_set_uint (value, self->parent.min_port);
      break;
    case PROP_MAX_PORT:
      g_value_set_uint (value, self->parent.max_port);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}
static GstPad *
kms_webrtc_rtcp_mux_connection_request_rtcp_src (KmsIRtpConnection *
    base_rtp_conn)
{
  KmsWebRtcRtcpMuxConnection *self =
      KMS_WEBRTC_RTCP_MUX_CONNECTION (base_rtp_conn);

  return gst_element_get_static_pad (self->priv->tr->dtlssrtpdec, "rtcp_src");
}
static void
kms_webrtc_rtcp_mux_connection_src_sync_state_with_parent (KmsIRtpConnection *
    base_rtp_conn)
{
  KmsWebRtcRtcpMuxConnection *self =
      KMS_WEBRTC_RTCP_MUX_CONNECTION (base_rtp_conn);
  GstElement *element = GST_ELEMENT (self->priv->tr->src);

  gst_element_sync_state_with_parent_target_state (element);
}
static gchar *
kms_webrtc_rtcp_mux_connection_get_certificate_pem_file (KmsWebRtcBaseConnection
    * base_conn)
{
  KmsWebRtcRtcpMuxConnection *self = KMS_WEBRTC_RTCP_MUX_CONNECTION (base_conn);
  gchar *pem;

  g_object_get (G_OBJECT (self->priv->tr->dtlssrtpdec), "pem", &pem, NULL);

  return pem;
}
static void
kms_webrtc_rtcp_mux_connection_sink_sync_state_with_parent (KmsIRtpConnection *
    base_rtp_conn)
{
  KmsWebRtcRtcpMuxConnection *self =
      KMS_WEBRTC_RTCP_MUX_CONNECTION (base_rtp_conn);
  KmsWebRtcTransport *tr = self->priv->tr;

  gst_element_sync_state_with_parent_target_state (tr->nicesink);
  gst_element_sync_state_with_parent_target_state (tr->dtlssrtpenc);
}
static void
kms_webrtc_rtcp_mux_connection_finalize (GObject * object)
{
  KmsWebRtcRtcpMuxConnection *self = KMS_WEBRTC_RTCP_MUX_CONNECTION (object);
  KmsWebRtcRtcpMuxConnectionPrivate *priv = self->priv;

  GST_DEBUG_OBJECT (self, "finalize");

  kms_webrtc_transport_destroy (priv->tr);

  /* chain up */
  G_OBJECT_CLASS (kms_webrtc_rtcp_mux_connection_parent_class)->finalize
      (object);
}
static void
kms_webrtc_rtcp_mux_connection_add (KmsIRtpConnection * base_rtp_conn,
    GstBin * bin, gboolean active)
{
  KmsWebRtcRtcpMuxConnection *self =
      KMS_WEBRTC_RTCP_MUX_CONNECTION (base_rtp_conn);
  KmsWebRtcRtcpMuxConnectionPrivate *priv = self->priv;
  KmsWebRtcTransport *tr = priv->tr;

  /* srcs */
  g_object_set (G_OBJECT (tr->sink->dtlssrtpenc), "is-client", active, NULL);

  gst_bin_add (bin, g_object_ref (tr->src));
  gst_bin_add (bin, g_object_ref (tr->sink));
}
static GstPad *
kms_webrtc_rtcp_mux_connection_request_rtp_sink (KmsIRtpConnection *
    base_rtp_conn)
{
  KmsWebRtcRtcpMuxConnection *self =
      KMS_WEBRTC_RTCP_MUX_CONNECTION (base_rtp_conn);
  GstPad *pad;
  gchar *str;

  str = g_strdup_printf ("rtp_sink_%d",
      g_atomic_int_add (&self->priv->tr->rtp_id, 1));

  pad = gst_element_get_request_pad (self->priv->tr->dtlssrtpenc, str);
  g_free (str);

  return pad;
}
static void
kms_webrtc_rtcp_mux_connection_get_property (GObject * object,
    guint prop_id, GValue * value, GParamSpec * pspec)
{
  KmsWebRtcRtcpMuxConnection *self = KMS_WEBRTC_RTCP_MUX_CONNECTION (object);

  switch (prop_id) {
    case PROP_ADDED:
      g_value_set_boolean (value, self->priv->added);
      break;
    case PROP_CONNECTED:
      g_value_set_boolean (value, self->priv->connected);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}
static void
kms_webrtc_rtcp_mux_connection_collect_latency_stats (KmsIRtpConnection * obj,
    gboolean enable)
{
  KmsWebRtcRtcpMuxConnection *self = KMS_WEBRTC_RTCP_MUX_CONNECTION (obj);
  KmsWebRtcBaseConnection *base = KMS_WEBRTC_BASE_CONNECTION (obj);

  KMS_WEBRTC_BASE_CONNECTION_LOCK (base);

  if (enable) {
    kms_webrtc_transport_enable_latency_notification (self->priv->tr,
        base->cb, base->user_data, NULL);
  } else {
    kms_webrtc_transport_disable_latency_notification (self->priv->tr);
  }

  kms_webrtc_base_connection_collect_latency_stats (obj, enable);

  KMS_WEBRTC_BASE_CONNECTION_UNLOCK (base);
}
KmsWebRtcRtcpMuxConnection *
kms_webrtc_rtcp_mux_connection_new (NiceAgent * agent, GMainContext * context,
    const gchar * name)
{
  GObject *obj;
  KmsWebRtcBaseConnection *base_conn;
  KmsWebRtcRtcpMuxConnection *conn;
  KmsWebRtcRtcpMuxConnectionPrivate *priv;

  obj = g_object_new (KMS_TYPE_WEBRTC_RTCP_MUX_CONNECTION, NULL);
  base_conn = KMS_WEBRTC_BASE_CONNECTION (obj);
  conn = KMS_WEBRTC_RTCP_MUX_CONNECTION (obj);
  priv = conn->priv;

  if (!kms_webrtc_base_connection_configure (base_conn, agent, name)) {
    g_object_unref (obj);
    return NULL;
  }

  priv->tr =
      kms_webrtc_transport_create (agent, base_conn->stream_id,
      NICE_COMPONENT_TYPE_RTP);

  if (priv->tr == NULL) {
    GST_ERROR_OBJECT (conn, "Cannot create connection");
    g_object_unref (obj);
    return NULL;
  }

  g_signal_connect (priv->tr->dtlssrtpenc, "on-key-set",
      G_CALLBACK (connected_cb), conn);

  nice_agent_attach_recv (agent, base_conn->stream_id,
      NICE_COMPONENT_TYPE_RTP, context, kms_webrtc_transport_nice_agent_recv_cb,
      NULL);

  return conn;
}