static gboolean
kms_sdp_rtp_media_handler_add_answer_attributes (KmsSdpMediaHandler * handler,
    const GstSDPMedia * offer, GstSDPMedia * answer, GError ** error)
{
  KmsSdpRtpMediaHandler *self = KMS_SDP_RTP_MEDIA_HANDLER (handler);

  if (!KMS_SDP_MEDIA_HANDLER_CLASS (parent_class)->add_answer_attributes
      (handler, offer, answer, error)) {
    return FALSE;
  }

  if (self->priv->rtcp_entry) {
    gchar *val, *addr, *addr_type;

    g_object_get (self, "addr", &addr, "addr_type", &addr_type, NULL);

    if (addr != NULL) {
      val = g_strdup_printf ("%d IN %s %s", DEFAULT_RTCP_ENTRY_PORT, addr_type,
          addr);
    } else {
      val = g_strdup_printf ("%d", DEFAULT_RTCP_ENTRY_PORT);
    }

    gst_sdp_media_add_attribute (answer, "rtcp", val);

    g_free (addr_type);
    g_free (addr);
    g_free (val);
  }

  return TRUE;
}
static GstSDPMedia *
kms_sdp_rtp_avpf_media_handler_create_offer (KmsSdpMediaHandler * handler,
    const gchar * media, GError ** error)
{
  GstSDPMedia *m;

  if (gst_sdp_media_new (&m) != GST_SDP_OK) {
    g_set_error (error, KMS_SDP_AGENT_ERROR, SDP_AGENT_UNEXPECTED_ERROR,
        "Can not create '%s' media", media);
    goto error;
  }

  /* Create m-line */
  if (!KMS_SDP_MEDIA_HANDLER_CLASS (parent_class)->init_offer (handler, media,
          m, error)) {
    goto error;
  }

  /* Add attributes to m-line */
  if (!KMS_SDP_MEDIA_HANDLER_GET_CLASS (handler)->add_offer_attributes (handler,
          m, error)) {
    goto error;
  }

  return m;

error:
  if (m != NULL) {
    gst_sdp_media_free (m);
  }

  return NULL;
}
static gboolean
kms_sdp_rtp_avpf_media_handler_add_answer_attributes_impl (KmsSdpMediaHandler *
    handler, const GstSDPMedia * offer, GstSDPMedia * answer, GError ** error)
{
  if (!KMS_SDP_MEDIA_HANDLER_CLASS (parent_class)->add_answer_attributes
      (handler, offer, answer, error)) {
    return FALSE;
  }

  return kms_sdp_rtp_avpf_media_handler_filter_rtcp_fb_attrs (handler, offer,
      answer, error);
}
static gboolean
kms_sdp_rtp_avpf_media_handler_add_offer_attributes (KmsSdpMediaHandler *
    handler, GstSDPMedia * offer, GError ** error)
{
  /* We depend of payloads supported by parent class */
  if (!KMS_SDP_MEDIA_HANDLER_CLASS (parent_class)->add_offer_attributes
      (handler, offer, error)) {
    return FALSE;
  }

  return kms_sdp_rtp_avpf_media_handler_add_rtcp_fb_attrs (handler, offer,
      error);
}
static void
kms_sdp_rtp_savp_media_handler_class_init (KmsSdpRtpSavpMediaHandlerClass *
    klass)
{
  GObjectClass *gobject_class;
  KmsSdpMediaHandlerClass *handler_class;

  gobject_class = G_OBJECT_CLASS (klass);

  gobject_class->constructor = kms_sdp_rtp_savp_media_handler_constructor;

  handler_class = KMS_SDP_MEDIA_HANDLER_CLASS (klass);

  handler_class->manage_protocol =
      kms_sdp_rtp_savp_media_handler_manage_protocol;
}
static void
kms_sdp_reject_media_handler_class_init (KmsSdpRejectMediaHandlerClass * klass)
{
    GObjectClass *gobject_class;
    KmsSdpMediaHandlerClass *handler_class;

    gobject_class = G_OBJECT_CLASS (klass);

    gobject_class->constructor = kms_sdp_reject_media_handler_constructor;

    handler_class = KMS_SDP_MEDIA_HANDLER_CLASS (klass);

    handler_class->create_offer = kms_sdp_reject_media_handler_create_offer;
    handler_class->create_answer = kms_sdp_reject_media_handler_create_answer;
    handler_class->init_answer = kms_sdp_reject_media_handler_init_answer;
}
static gboolean
kms_sdp_rtp_avpf_media_handler_add_answer_attributes_impl (KmsSdpMediaHandler *
    handler, const GstSDPMedia * offer, GstSDPMedia * answer, GError ** error)
{
  if (!KMS_SDP_MEDIA_HANDLER_CLASS (parent_class)->add_answer_attributes
      (handler, offer, answer, error)) {
    return FALSE;
  }

  if (g_strcmp0 (gst_sdp_media_get_proto (offer), SDP_MEDIA_RTP_AVP_PROTO) == 0) {
    /* Do not add specific feedback parameters in response */
    return TRUE;
  }

  return kms_sdp_rtp_avpf_media_handler_filter_rtcp_fb_attrs (handler, offer,
      answer, error);
}
static gboolean
kms_sdp_rtp_avpf_media_handler_can_insert_attribute (KmsSdpMediaHandler *
    handler, const GstSDPMedia * offer, const GstSDPAttribute * attr,
    GstSDPMedia * answer, SdpMessageContext * ctx)
{
  if (g_strcmp0 (attr->key, SDP_MEDIA_RTCP_FB) == 0) {
    /* ignore */
    return FALSE;
  }

  if (!KMS_SDP_MEDIA_HANDLER_CLASS (parent_class)->can_insert_attribute
      (handler, offer, attr, answer, ctx)) {
    return FALSE;
  }

  return TRUE;
}
static void
kms_sdp_rtp_avpf_media_handler_class_init (KmsSdpRtpAvpfMediaHandlerClass *
    klass)
{
  GObjectClass *gobject_class;
  KmsSdpMediaHandlerClass *handler_class;

  gobject_class = G_OBJECT_CLASS (klass);

  gobject_class->constructor = kms_sdp_rtp_avpf_media_handler_constructor;
  gobject_class->get_property = kms_sdp_rtp_avpf_media_handler_get_property;
  gobject_class->set_property = kms_sdp_rtp_avpf_media_handler_set_property;

  handler_class = KMS_SDP_MEDIA_HANDLER_CLASS (klass);

  handler_class->create_offer = kms_sdp_rtp_avpf_media_handler_create_offer;
  handler_class->create_answer = kms_sdp_rtp_avpf_media_handler_create_answer;
  handler_class->manage_protocol =
      kms_sdp_rtp_avpf_media_handler_manage_protocol;

  handler_class->can_insert_attribute =
      kms_sdp_rtp_avpf_media_handler_can_insert_attribute;
  handler_class->intersect_sdp_medias =
      kms_sdp_rtp_avpf_media_handler_intersect_sdp_medias;
  handler_class->add_offer_attributes =
      kms_sdp_rtp_avpf_media_handler_add_offer_attributes;
  handler_class->add_answer_attributes =
      kms_sdp_rtp_avpf_media_handler_add_answer_attributes_impl;

  g_object_class_install_property (gobject_class, PROP_NACK,
      g_param_spec_boolean ("nack", "Nack",
          "Wheter rtcp-fb-nack-param if supproted or not",
          DEFAULT_SDP_MEDIA_RTP_AVPF_NACK,
          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));

  g_object_class_install_property (gobject_class, PROP_GOOG_REMB,
      g_param_spec_boolean ("goog-remb", "goog-remb",
          "Wheter receiver estimated maximum bitrate is supported",
          DEFAULT_SDP_MEDIA_RTP_GOOG_REMB,
          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));

  g_type_class_add_private (klass, sizeof (KmsSdpRtpAvpfMediaHandlerPrivate));
}
static gboolean
kms_sdp_rtp_media_handler_can_insert_attribute (KmsSdpMediaHandler *
    handler, const GstSDPMedia * offer, const GstSDPAttribute * attr,
    GstSDPMedia * answer, SdpMessageContext * ctx)
{
  KmsSdpRtpMediaHandler *self = KMS_SDP_RTP_MEDIA_HANDLER (handler);

  if (g_strcmp0 (attr->key, "rtcp-mux") != 0) {
    return KMS_SDP_MEDIA_HANDLER_CLASS (parent_class)->can_insert_attribute
        (handler, offer, attr, answer, ctx);
  }

  if (!self->priv->rtcp_mux) {
    return FALSE;
  }

  if (!self->priv->rtcp_entry) {
    return FALSE;
  }

  return !sdp_utils_is_attribute_in_media (answer, attr);
}
GstSDPMedia *
kms_sdp_rtp_avpf_media_handler_create_answer (KmsSdpMediaHandler * handler,
    SdpMessageContext * ctx, const GstSDPMedia * offer, GError ** error)
{
  GstSDPMedia *m;

  if (gst_sdp_media_new (&m) != GST_SDP_OK) {
    g_set_error (error, KMS_SDP_AGENT_ERROR, SDP_AGENT_UNEXPECTED_ERROR,
        "Can not create '%s' media answer", gst_sdp_media_get_media (offer));
    goto error;
  }

  /* Create m-line */
  if (!KMS_SDP_MEDIA_HANDLER_CLASS (parent_class)->init_answer (handler, offer,
          m, error)) {
    goto error;
  }

  /* Add attributes to m-line */
  if (!KMS_SDP_MEDIA_HANDLER_GET_CLASS (handler)->add_answer_attributes
      (handler, offer, m, error)) {
    goto error;
  }

  if (!KMS_SDP_MEDIA_HANDLER_GET_CLASS (handler)->intersect_sdp_medias (handler,
          offer, m, ctx, error)) {
    goto error;
  }

  return m;

error:
  if (m != NULL) {
    gst_sdp_media_free (m);
  }

  return NULL;
}
static void
kms_sdp_rtp_media_handler_class_init (KmsSdpRtpMediaHandlerClass * klass)
{
  GObjectClass *gobject_class;
  KmsSdpMediaHandlerClass *handler_class;

  gobject_class = G_OBJECT_CLASS (klass);

  gobject_class->get_property = kms_sdp_rtp_media_handler_get_property;
  gobject_class->set_property = kms_sdp_rtp_media_handler_set_property;

  handler_class = KMS_SDP_MEDIA_HANDLER_CLASS (klass);

  handler_class->can_insert_attribute =
      kms_sdp_rtp_media_handler_can_insert_attribute;
  handler_class->intersect_sdp_medias =
      kms_sdp_rtp_media_handler_intersect_sdp_medias;
  handler_class->add_offer_attributes =
      kms_sdp_rtp_media_handler_add_offer_attributes;
  handler_class->add_answer_attributes =
      kms_sdp_rtp_media_handler_add_answer_attributes;

  g_object_class_install_property (gobject_class, PROP_RTCP_MUX,
      g_param_spec_boolean ("rtcp-mux", "rtcp-mux",
          "Wheter multiplexing RTP data and control packets on a single port is supported",
          DEFAULT_SDP_MEDIA_RTP_RTCP_MUX,
          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));

  g_object_class_install_property (gobject_class, PROP_RTCP_ENTRY,
      g_param_spec_boolean ("rtcp-entry", "rtcp-entry",
          "When TRUE an rtcp entry [rfc3605] will be added",
          DEFAULT_SDP_MEDIA_RTP_RTCP_ENTRY,
          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));

  g_type_class_add_private (klass, sizeof (KmsSdpRtpMediaHandlerPrivate));
}