static CodecBlueprint *
_find_matching_blueprint (FsCodec *codec, GList *blueprints)
{
  GList *item = NULL;
  GstCaps *caps = NULL;

  caps = fs_codec_to_gst_caps (codec);

  if (!caps)
  {
    gchar *tmp = fs_codec_to_string (codec);
    GST_WARNING ("Could not transform codec into caps: %s", tmp);
    g_free (tmp);
    return NULL;
  }

  for (item = g_list_first (blueprints); item; item = g_list_next (item))
  {
    CodecBlueprint *bp = item->data;

    if (gst_caps_can_intersect (caps, bp->rtp_caps))
      break;
  }

  gst_caps_unref (caps);

  if (item)
    return item->data;
  else
    return NULL;
}
Esempio n. 2
0
static void
_src_pad_added (FsStream *stream, GstPad *pad, FsCodec *codec,
    gpointer user_data)
{
  struct SimpleTestStream *st = user_data;
  GstElement *fakesink = gst_element_factory_make ("fakesink", NULL);
  GstPad *fakesink_pad = NULL;
  GstPadLinkReturn ret;
  FsCodec *codeccopy = fs_codec_copy (codec);
  gchar *str = NULL;

  g_assert (fakesink);

  g_object_set (fakesink,
      "signal-handoffs", TRUE,
      "sync", TRUE,
      "async", TRUE,
      NULL);

  ts_fail_if (codec->encoding_name == NULL,
      "Got invalid codec without an encoding_name with id %u"
      " and clock_rate %u", codec->id, codec->clock_rate);

  g_object_set_data (G_OBJECT (fakesink), "codec", codeccopy);
  g_object_weak_ref (G_OBJECT (fakesink),
      (GWeakNotify) fs_codec_destroy, codeccopy);

  g_signal_connect (fakesink, "handoff", st->handoff_handler, st);

  gst_bin_add (GST_BIN (st->dat->pipeline), fakesink);

  fakesink_pad = gst_element_get_static_pad (fakesink, "sink");
  ret = gst_pad_link (pad, fakesink_pad);
  gst_object_unref (fakesink_pad);

  ts_fail_if (GST_PAD_LINK_FAILED(ret), "Could not link fakesink");

  ts_fail_if (gst_element_set_state (fakesink, GST_STATE_PLAYING) ==
      GST_STATE_CHANGE_FAILURE, "Could not set the fakesink to playing");

  str = fs_codec_to_string (codec);
  GST_DEBUG ("%d:%d: Added Fakesink for codec %s", st->dat->id, st->target->id,
           str);
  g_free (str);

  if (max_src_pads > 1)
    ts_fail_unless (count_stream_pads (stream) <= max_src_pads);
  else
    ts_fail_unless (count_stream_pads (stream) == 1);
}
Esempio n. 3
0
static void
_current_send_codec_changed (FsSession *session, FsCodec *codec)
{
  struct SimpleTestConference *dat = NULL;
  FsConference *conf = NULL;
  gchar *str = NULL;

  g_object_get (session, "conference", &conf, NULL);
  dat = g_object_get_data (G_OBJECT (conf), "dat");
  gst_object_unref (conf);

  str = fs_codec_to_string (codec);
  g_debug ("%d: New send codec: %s", dat->id, str);
  g_free (str);
}
Esempio n. 4
0
static gboolean
async_bus_cb (GstBus *bus, GstMessage *message, gpointer user_data)
{
  switch (GST_MESSAGE_TYPE(message))
  {
    case GST_MESSAGE_ERROR:
      {
        GError *error = NULL;
        gchar *debug_str = NULL;

        gst_message_parse_error (message, &error, &debug_str);
        g_print ("Got gst message: %s %s", error->message, debug_str);
      }
      break;
    case GST_MESSAGE_WARNING:
      {
        GError *error = NULL;
        gchar *debug_str = NULL;

        gst_message_parse_warning (message, &error, &debug_str);
        g_warning ("Got gst message: %s %s", error->message, debug_str);
      }
      break;
    case GST_MESSAGE_ELEMENT:
      {
        const GstStructure *s = gst_message_get_structure (message);

        if (gst_structure_has_name (s, "farstream-error"))
        {
          gint error;
          const gchar *error_msg = gst_structure_get_string (s, "error-msg");

          g_assert (gst_structure_get_enum (s, "error-no", FS_TYPE_ERROR,
                  &error));

          if (FS_ERROR_IS_FATAL (error))
            g_error ("Farstream fatal error: %d %s", error, error_msg);
          else
            g_warning ("Farstream non-fatal error: %d %s", error, error_msg);
        }
        else if (gst_structure_has_name (s, "farstream-new-local-candidate"))
        {
          const GValue *val = gst_structure_get_value (s, "candidate");
          FsCandidate *cand = NULL;

          g_assert (val);
          cand = g_value_get_boxed (val);

          g_print ("New candidate: socket %s\n", cand->ip);
          g_print ("You can press ENTER on the other side\n");
        }
        else if (gst_structure_has_name (s,
                "farstream-local-candidates-prepared"))
        {
          g_print ("Local candidates prepared\n");
        }
        else if (gst_structure_has_name (s, "farstream-recv-codecs-changed"))
        {
          const GValue *val = gst_structure_get_value (s, "codecs");
          GList *codecs = NULL;

          g_assert (val);
          codecs = g_value_get_boxed (val);

          g_print ("Recv codecs changed:\n");
          for (; codecs; codecs = g_list_next (codecs))
          {
            FsCodec *codec = codecs->data;
            gchar *tmp = fs_codec_to_string (codec);
            g_print ("%s\n", tmp);
            g_free (tmp);
          }
        }
        else if (gst_structure_has_name (s, "farstream-send-codec-changed"))
        {
          const GValue *val = gst_structure_get_value (s, "codec");
          FsCodec *codec = NULL;
          gchar *tmp;
          g_assert (val);
          codec = g_value_get_boxed (val);
          tmp = fs_codec_to_string (codec);

          g_print ("Send codec changed: %s\n", tmp);
          g_free (tmp);
        }
      }
      break;
    default:
      break;
  }

  return TRUE;
}
static void
mex_telepathy_channel_on_src_pad_added (TfContent *content,
                                        TpHandle   handle,
                                        FsStream  *stream,
                                        GstPad    *pad,
                                        FsCodec   *codec,
                                        gpointer   user_data)
{
  MexTelepathyChannel *self = MEX_TELEPATHY_CHANNEL (user_data);
  MexTelepathyChannelPrivate *priv = self->priv;

  gchar *cstr = fs_codec_to_string (codec);
  FsMediaType mtype;
  GstPad *sinkpad;
  GstElement *element;
  GstStateChangeReturn ret;

  /* Upon pad added, clear the "in progress" box+padding */
  clutter_actor_hide (CLUTTER_ACTOR (priv->busy_box));
  clutter_actor_show (CLUTTER_ACTOR (priv->full_frame) );

  MEX_DEBUG ("New src pad: %s", cstr);
  g_object_get (content, "media-type", &mtype, NULL);

  switch (mtype)
    {
    case FS_MEDIA_TYPE_AUDIO:
      element = gst_parse_bin_from_description (
        "audioconvert ! audioresample ! audioconvert ! autoaudiosink",
        TRUE, NULL);
      break;
    case FS_MEDIA_TYPE_VIDEO:
      element = priv->incoming_sink;
      break;
    default:
      MEX_WARNING ("Unknown media type");
      return;
    }

  if (!gst_bin_add (GST_BIN (priv->pipeline), element))
    {
      MEX_WARNING ("Failed to add sink element to pipeline");
    }
  sinkpad = gst_element_get_pad (element, "sink");
  ret = gst_element_set_state (element, GST_STATE_PLAYING);
  if (ret == GST_STATE_CHANGE_FAILURE)
    {
      tp_channel_close_async (TP_CHANNEL (priv->channel), NULL, NULL);
      MEX_WARNING ("Failed to start tee sink pipeline !?");
      return;
    }

  if (GST_PAD_LINK_FAILED (gst_pad_link (pad, sinkpad)))
    {
      tp_channel_close_async (TP_CHANNEL (priv->channel), NULL, NULL);
      MEX_WARNING ("Couldn't link sink pipeline !?");
      return;
    }

  g_object_unref (sinkpad);

  /* Start in FULL mode */
  mex_telepathy_channel_set_tool_mode (self, TOOL_MODE_FULL, 100);
}
Esempio n. 6
0
static void
_handoff_handler (GstElement *element, GstBuffer *buffer, GstPad *pad,
  gpointer user_data)
{
  struct SimpleTestStream *st = user_data;
  int i;
  gboolean stop = TRUE;
  GList *codecs = NULL;

  g_object_get (st->dat->session,
      "codecs", &codecs,
      NULL);

  ts_fail_if (codecs == NULL, "Could not get codecs");

  if (st->flags & WAITING_ON_LAST_CODEC)
  {
    if (fs_codec_are_equal (
        g_list_last (codecs)->data,
        g_object_get_data (G_OBJECT (element), "codec")))
    {
      st->flags &= ~WAITING_ON_LAST_CODEC;
      st->flags |= SHOULD_BE_LAST_CODEC;
      max_buffer_count += st->buffer_count;
      g_debug ("We HAVE last codec");
    }
    else
    {
      gchar *str = fs_codec_to_string (
          g_object_get_data (G_OBJECT (element), "codec"));
      gchar *str2 = fs_codec_to_string (g_list_last (codecs)->data);
      g_debug ("not yet the last codec, skipping (we have %s, we want %s)",
          str, str2);
      g_free (str);
      g_free (str2);
      fs_codec_list_destroy (codecs);
      return;
    }
  }


  if (select_last_codec || st->flags & SHOULD_BE_LAST_CODEC)
    ts_fail_unless (
        fs_codec_are_equal (
            g_list_last (codecs)->data,
            g_object_get_data (G_OBJECT (element), "codec")),
        "The handoff handler got a buffer from the wrong codec (last)");
  else
    ts_fail_unless (
        fs_codec_are_equal (
            g_list_first (codecs)->data,
            g_object_get_data (G_OBJECT (element), "codec")),
        "The handoff handler got a buffer from the wrong codec");

  fs_codec_list_destroy (codecs);


  st->buffer_count++;

  if (st->buffer_count % 10 == 0)
    g_debug ("%d:%d: Buffer %d", st->dat->id, st->target->id, st->buffer_count);

  /*
  ts_fail_if (dat->buffer_count > max_buffer_count,
    "Too many buffers %d > max_buffer_count", dat->buffer_count);
  */

  for (i = 0; i < count && !stop ; i++)
  {
    GList *item;


    for (item = g_list_first (dats[i]->streams);
         item;
         item = g_list_next (item))
    {
      struct SimpleTestStream *st2 = item->data;

      if (st2->buffer_count < max_buffer_count)
      {
        stop = FALSE;
        break;
      }
    }
  }

  if (stop)
  {
    if (reset_to_last_codec && !(st->flags & HAS_BEEN_RESET)) {
      GError *error = NULL;
      GList *nego_codecs = NULL;
      gchar *str = NULL;

      g_object_get (st->target->session,
          "codecs", &nego_codecs,
          NULL);

      ts_fail_if (nego_codecs == NULL, "No codecs");
      ts_fail_if (g_list_length (nego_codecs) < 2, "Only one negotiated codec");

      str = fs_codec_to_string (g_list_last (nego_codecs)->data);
      g_debug ("Setting codec to: %s", str);
      g_free (str);

      ts_fail_unless (fs_session_set_send_codec (st->target->session,
              g_list_last (nego_codecs)->data, &error),
          "Could not set the send codec: %s",
          error ? error->message : "NO GError!!!");
      g_clear_error (&error);

      fs_codec_list_destroy (nego_codecs);

      st->flags |= HAS_BEEN_RESET | WAITING_ON_LAST_CODEC;

      g_debug ("RESET TO LAST CODEC");

    } else {
      g_main_loop_quit (loop);
    }
  }
}
GList *
negotiate_stream_codecs (
    const GList *remote_codecs,
    GList *current_codec_associations,
    gboolean multi_stream)
{
  GList *new_codec_associations = NULL;
  const GList *rcodec_e = NULL;
  GList *item = NULL;

  GST_DEBUG ("Negotiating stream codecs (for %s)",
      multi_stream ? "a single stream" : "multiple streams");

  for (rcodec_e = remote_codecs;
       rcodec_e;
       rcodec_e = g_list_next (rcodec_e)) {
    FsCodec *remote_codec = rcodec_e->data;
    FsCodec *nego_codec = NULL;
    FsCodec *nego_send_codec = NULL;
    CodecAssociation *old_ca = NULL;

    gchar *tmp = fs_codec_to_string (remote_codec);
    GST_DEBUG ("Remote codec %s", tmp);
    g_free (tmp);

    /* First lets try the codec that is in the same PT */

    old_ca = lookup_codec_association_by_pt_list (current_codec_associations,
        remote_codec->id, FALSE);

    if (old_ca) {
      GST_DEBUG ("Have local codec in the same PT, lets try it first");
      negotiate_stream_codec (old_ca, remote_codec, multi_stream,
          &nego_codec, &nego_send_codec);
    }

    if (!nego_codec) {

      for (item = current_codec_associations;
           item;
           item = g_list_next (item))
      {
        old_ca = item->data;

        if (old_ca->disable || old_ca->reserved)
          continue;

        negotiate_stream_codec (old_ca, remote_codec, multi_stream,
            &nego_codec, &nego_send_codec);

        if (nego_codec)
        {
          /* If we have multiple streams with codecs,
           * then priorize the local IDs */
          if (multi_stream)
            nego_send_codec->id = nego_codec->id = old_ca->codec->id;

          break;
        }
      }
    }

    if (nego_codec) {
      CodecAssociation *new_ca = g_slice_new0 (CodecAssociation);
      gchar *tmp;

      new_ca->need_config = old_ca->need_config;
      new_ca->codec = nego_codec;
      new_ca->send_codec = nego_send_codec;
      new_ca->blueprint = old_ca->blueprint;
      new_ca->send_profile = g_strdup (old_ca->send_profile);
      new_ca->recv_profile = g_strdup (old_ca->recv_profile);

      tmp = fs_codec_to_string (nego_codec);
      GST_DEBUG ("Negotiated codec %s", tmp);
      g_free (tmp);

      new_codec_associations = g_list_append (new_codec_associations,
          new_ca);
    } else {
      gchar *tmp = fs_codec_to_string (remote_codec);
      CodecAssociation *new_ca = g_slice_new0 (CodecAssociation);
      GST_DEBUG ("Could not find a valid intersection... for codec %s",
          tmp);
      g_free (tmp);

      new_ca->codec = fs_codec_copy (remote_codec);
      new_ca->disable = TRUE;

      new_codec_associations = g_list_append (new_codec_associations, new_ca);
    }
  }

  /*
   * Check if there is a non-disabled codec left that we can use
   * for sending
   */
  for (item = new_codec_associations;
       item;
       item = g_list_next (item))
  {
    CodecAssociation *ca = item->data;

    if (codec_association_is_valid_for_sending (ca, TRUE))
      return new_codec_associations;
  }

  /* Else we destroy when and return NULL.. ie .. an error */
  codec_association_list_destroy (new_codec_associations);

  return NULL;
}
GList *
create_local_codec_associations (
    GList *blueprints,
    GList *codec_prefs,
    GList *current_codec_associations)
{
  GList *codec_associations = NULL;
  GList *bp_e = NULL;
  GList *codec_pref_e = NULL;
  GList *lca_e = NULL;
  gboolean has_valid_codec = FALSE;
  CodecAssociation *oldca = NULL;

  if (blueprints == NULL)
    return NULL;

  GST_DEBUG ("Creating local codec associations");

  /* First, lets create the original table by looking at our preferred codecs */
  for (codec_pref_e = codec_prefs;
       codec_pref_e;
       codec_pref_e = g_list_next (codec_pref_e))
  {
    FsCodec *codec_pref = codec_pref_e->data;
    CodecBlueprint *bp = _find_matching_blueprint (codec_pref, blueprints);
    CodecAssociation *ca = NULL;
    GList *bp_param_e = NULL;

    /* If its a negative pref, ignore it in this stage */
    if (codec_pref->id == FS_CODEC_ID_DISABLE)
      continue;

    /* If we want to disable a codec ID, we just insert a reserved codec assoc
     * in the list
     */
    if (codec_pref->id >= 0 && codec_pref->id < 128 &&
        codec_pref->encoding_name &&
        !g_ascii_strcasecmp (codec_pref->encoding_name, "reserve-pt"))
    {
      CodecAssociation *ca = g_slice_new0 (CodecAssociation);
      ca->codec = fs_codec_copy (codec_pref);
      ca->reserved = TRUE;
      codec_associations = g_list_append (codec_associations, ca);
      continue;
    }

    /* No matching blueprint, can't use this codec */
    if (!bp &&
        !fs_codec_get_optional_parameter (codec_pref, RECV_PROFILE_ARG,
                NULL))
    {
      GST_LOG ("Could not find matching blueprint for preferred codec %s/%s",
          fs_media_type_to_string (codec_pref->media_type),
          codec_pref->encoding_name);
      continue;
    }

    /* Now lets see if there is an existing codec that matches this preference
     */

    if (codec_pref->id == FS_CODEC_ID_ANY)
    {
      oldca = lookup_codec_association_custom_internal (
          current_codec_associations, TRUE,
          match_original_codec_and_codec_pref, codec_pref);
    }
    else
    {
      oldca = lookup_codec_association_by_pt_list (current_codec_associations,
          codec_pref->id, FALSE);
      if (oldca && oldca->reserved)
        oldca = NULL;
    }

    /* In this case, we have a matching codec association, lets keep the
     * payload type from it
     */
    if (oldca)
    {
      FsCodec *codec = sdp_negotiate_codec (
          oldca->codec, FS_PARAM_TYPE_BOTH | FS_PARAM_TYPE_CONFIG,
          codec_pref, FS_PARAM_TYPE_ALL);
      FsCodec *send_codec;

      if (codec)
      {
        fs_codec_destroy (codec);

        send_codec = sdp_negotiate_codec (
            oldca->send_codec, FS_PARAM_TYPE_SEND,
            codec_pref, FS_PARAM_TYPE_SEND | FS_PARAM_TYPE_SEND_AVOID_NEGO);
        if (send_codec)
          fs_codec_destroy (send_codec);
        else
          oldca = NULL;
      }
      else
      {
        oldca = NULL;
      }
    }

    ca = g_slice_new0 (CodecAssociation);
    ca->blueprint = bp;
    ca->codec = fs_codec_copy (codec_pref);
    codec_remove_parameter (ca->codec, SEND_PROFILE_ARG);
    codec_remove_parameter (ca->codec, RECV_PROFILE_ARG);
    ca->send_codec = codec_copy_filtered (codec_pref, FS_PARAM_TYPE_CONFIG);
    codec_remove_parameter (ca->send_codec, SEND_PROFILE_ARG);
    codec_remove_parameter (ca->send_codec, RECV_PROFILE_ARG);
    if (oldca)
      ca->send_codec->id = ca->codec->id = oldca->codec->id;
    ca->send_profile = dup_param_value (codec_pref, SEND_PROFILE_ARG);
    ca->recv_profile = dup_param_value (codec_pref, RECV_PROFILE_ARG);

    if (bp)
    {
      /* Codec pref does not come with a number, but
       * The blueprint has its own id, lets use it */
      if (ca->codec->id == FS_CODEC_ID_ANY &&
          (bp->codec->id >= 0 || bp->codec->id < 128))
      {
        ca->send_codec->id = ca->codec->id = bp->codec->id;
      }

      if (ca->codec->clock_rate == 0)
        ca->codec->clock_rate = bp->codec->clock_rate;

      if (ca->codec->channels == 0)
        ca->codec->channels = bp->codec->channels;

      for (bp_param_e = bp->codec->optional_params;
           bp_param_e;
           bp_param_e = g_list_next (bp_param_e))
      {
        FsCodecParameter *bp_param = bp_param_e->data;

        if (fs_codec_get_optional_parameter (ca->codec, bp_param->name, NULL))
          fs_codec_add_optional_parameter (ca->codec, bp_param->name,
              bp_param->value);
      }
    }

    {
      gchar *tmp = fs_codec_to_string (ca->codec);
      GST_LOG ("Added preferred codec %s", tmp);
      g_free (tmp);
    }

    codec_associations = list_insert_local_ca (codec_associations, ca);
  }

  /* Now, only codecs with specified ids are here,
   * the rest are dynamic
   * Lets attribute them here */
  for (lca_e = codec_associations;
       lca_e;
       lca_e = g_list_next (lca_e))
  {
    CodecAssociation *lca = lca_e->data;

    if (lca->reserved)
      continue;

    if (lca->codec->id < 0)
    {
      lca->send_codec->id = lca->codec->id = _find_first_empty_dynamic_entry (
          current_codec_associations, codec_associations);
      if (lca->codec->id < 0)
      {
        GST_ERROR ("We've run out of dynamic payload types");
        goto error;
      }
    }
  }

  /* Now, lets add all other codecs from the blueprints */
  for (bp_e = g_list_first (blueprints); bp_e; bp_e = g_list_next (bp_e)) {
    CodecBlueprint *bp = bp_e->data;
    CodecAssociation *ca = NULL;
    GList *tmpca_e = NULL;
    gboolean next = FALSE;
    FsCodec *codec;

    /* Lets skip codecs that dont have all of the required informations */
    if (bp->codec->clock_rate == 0)
      continue;

    /* Check if its already used */
    for (tmpca_e = codec_associations;
         tmpca_e;
         tmpca_e = g_list_next (tmpca_e))
    {
      CodecAssociation *tmpca = tmpca_e->data;
      if (tmpca->blueprint == bp)
        break;
    }
    if (tmpca_e)
      continue;

    /* Check if it is disabled in the list of preferred codecs */
    if (_is_disabled (codec_prefs, bp))
    {
      gchar *tmp = fs_codec_to_string (bp->codec);
      GST_DEBUG ("Codec %s disabled by config", tmp);
      g_free (tmp);
      continue;
    }

    /* Re-use already existing codec associations with this blueprint
     * if any, we only keep the PT from the old assoc
     * (the rest will be regenerated by the renegotiation)
     */
    for (tmpca_e = current_codec_associations;
         tmpca_e;
         tmpca_e = g_list_next (tmpca_e))
    {
      CodecAssociation *tmpca = tmpca_e->data;

      if (tmpca->blueprint == bp)
      {
        /* Ignore reserved (we've just regenerated them )*/
        if (tmpca->reserved)
          continue;

        /* Ignore it if there is already something for this PT */
        if (lookup_codec_association_by_pt_list (codec_associations,
                tmpca->codec->id, TRUE))
          continue;

        /* Can't keep this codec, for some reason its wrong */
        codec = sdp_negotiate_codec (tmpca->codec, FS_PARAM_TYPE_CONFIG,
            bp->codec, FS_PARAM_TYPE_ALL);
        if (!codec)
          continue;
        fs_codec_destroy (codec);

        ca = g_slice_new0 (CodecAssociation);
        ca->blueprint = bp;
        ca->codec = fs_codec_copy (bp->codec);
        ca->send_codec = codec_copy_filtered (bp->codec, FS_PARAM_TYPE_CONFIG);
        ca->codec->id = ca->send_codec->id = tmpca->codec->id;

        codec_associations = list_insert_local_ca (codec_associations, ca);
        next = TRUE;
      }
    }
    if (next)
      continue;

    codec = sdp_negotiate_codec (bp->codec, FS_PARAM_TYPE_ALL,
        bp->codec, FS_PARAM_TYPE_ALL);

    /* If it does not negotiate against itself, there must be something wrong */
    if (!codec)
      continue;
    fs_codec_destroy (codec);

    ca = g_slice_new0 (CodecAssociation);
    ca->blueprint = bp;
    ca->codec = fs_codec_copy (bp->codec);

    if (ca->codec->id < 0)
    {
      ca->codec->id = _find_first_empty_dynamic_entry (
          current_codec_associations, codec_associations);
      if (ca->codec->id < 0)
      {
        GST_WARNING ("We've run out of dynamic payload types");
        goto error;
      }
    }

    ca->send_codec = codec_copy_filtered (ca->codec, FS_PARAM_TYPE_CONFIG);

    codec_associations = list_insert_local_ca (codec_associations, ca);
  }

  for (lca_e = codec_associations;
       lca_e;
       lca_e = g_list_next (lca_e))
  {
    CodecAssociation *ca = lca_e->data;

    if (codec_association_is_valid_for_sending (ca, TRUE))
      has_valid_codec = TRUE;
  }

  if (!has_valid_codec)
  {
    GST_WARNING ("All codecs disabled by preferences");
    goto error;
  }

  return codec_associations;

 error:
  codec_association_list_destroy (codec_associations);

  return NULL;
}
/**
 * validate_codecs_configuration:
 * @media_type: The #FsMediaType these codecs should be for
 * @blueprints: A #GList of #CodecBlueprints to validate the codecs agsint
 * @codecs: a #GList of #FsCodec that represent the preferences
 *
 * This function validates a GList of passed FarsightCodec structures
 * against the valid discovered payloaders
 * It removes all "invalid" codecs from the list, it modifies the list
 * passed in as an argument.
 *
 * Returns: the #GList of #FsCodec minus the invalid ones
 */
GList *
validate_codecs_configuration (FsMediaType media_type, GList *blueprints,
  GList *codecs)
{
  GList *codec_e = codecs;

  while (codec_e)
  {
    FsCodec *codec = codec_e->data;
    GList *blueprint_e = NULL;
    FsCodecParameter *param;

    /* Check if codec is for the wrong media_type.. this would be wrong
     */
    if (media_type != codec->media_type)
      goto remove_this_codec;

    if (codec->id >= 0 && codec->id < 128 && codec->encoding_name &&
        !g_ascii_strcasecmp (codec->encoding_name, "reserve-pt"))
      goto accept_codec;

    for (blueprint_e = g_list_first (blueprints);
         blueprint_e;
         blueprint_e = g_list_next (blueprint_e))
    {
      CodecBlueprint *blueprint = blueprint_e->data;

      /* First, lets check the encoding name */
      if (g_ascii_strcasecmp (blueprint->codec->encoding_name,
              codec->encoding_name))
        continue;
      /* If both have a clock_rate, it must be the same */
      if (blueprint->codec->clock_rate && codec->clock_rate &&
          blueprint->codec->clock_rate != codec->clock_rate)
        continue;
        /* At least one needs to have a clockrate */
      else if (!blueprint->codec->clock_rate && !codec->clock_rate)
        continue;

      if (codec_sdp_compare (blueprint->codec, codec))
        break;
    }

    /* If there are send and/or recv profiles, lets test them */
    param = fs_codec_get_optional_parameter (codec, RECV_PROFILE_ARG, NULL);
    if (param && !validate_codec_profile (codec, param->value, FALSE))
        goto remove_this_codec;

    param = fs_codec_get_optional_parameter (codec, SEND_PROFILE_ARG, NULL);
    if (param && !validate_codec_profile (codec, param->value, TRUE))
      goto remove_this_codec;

    /* If no blueprint was found */
    if (blueprint_e == NULL)
    {
      /* Accept codecs with no blueprints if they have a valid profile */
      if (fs_codec_get_optional_parameter (codec, RECV_PROFILE_ARG, NULL) &&
          codec->encoding_name && codec->clock_rate)
        goto accept_codec;

      goto remove_this_codec;
    }

  accept_codec:
    codec_e = g_list_next (codec_e);

    continue;
  remove_this_codec:
    {
      GList *nextcodec_e = g_list_next (codec_e);
      gchar *tmp = fs_codec_to_string (codec);
      GST_DEBUG ("Preferred codec %s could not be matched with a blueprint",
          tmp);
      g_free (tmp);
      fs_codec_destroy (codec);
      codecs = g_list_delete_link (codecs, codec_e);
      codec_e = nextcodec_e;
    }
  }

  return codecs;
}