GList *
codec_associations_to_codecs_internal (GList *codec_associations,
    gboolean include_config, gboolean send_codecs)
{
  GList *codecs = NULL;
  GList *item = NULL;

  for (item = g_list_first (codec_associations);
       item;
       item = g_list_next (item))
  {
    CodecAssociation *ca = item->data;
    if (!ca->disable && !ca->reserved && !ca->recv_only && ca->codec)
    {
      FsCodec *codec = NULL;

      if (send_codecs)
        codec = fs_codec_copy (ca->send_codec);
      else if (include_config)
        codec = fs_codec_copy (ca->codec);
      else
        codec = codec_copy_filtered (ca->codec, FS_PARAM_TYPE_CONFIG);

      codecs = g_list_append (codecs, codec);
    }
  }

  return codecs;
}
static CodecAssociation *
codec_association_copy (CodecAssociation *ca)
{
  CodecAssociation *newca = g_slice_new (CodecAssociation);

  g_return_val_if_fail (ca, NULL);

  memcpy (newca, ca, sizeof(CodecAssociation));
  newca->codec = fs_codec_copy (ca->codec);
  newca->send_codec = fs_codec_copy (ca->send_codec);
  newca->send_profile = g_strdup (ca->send_profile);
  newca->recv_profile = g_strdup (ca->recv_profile);

  return newca;
}
static gboolean
match_send_codec_no_pt (CodecAssociation *old_ca, gpointer user_data)
{
  FsCodec *old_codec;
  FsCodec *tmpcodec = NULL;
  CodecAssociation *new_ca = user_data;
  gboolean ret;

  if (old_ca->disable || old_ca->reserved)
    return FALSE;

  if (new_ca->send_codec->id == old_ca->send_codec->id)
  {
    old_codec = old_ca->send_codec;
  }
  else
  {
    tmpcodec = old_codec = fs_codec_copy (old_ca->send_codec);
    old_codec->id = new_ca->codec->id;
  }

  ret = fs_codec_are_equal (old_codec, new_ca->codec);
  fs_codec_destroy (tmpcodec);

  return ret;
}
static GList *
empathy_call_handler_tf_channel_codec_config_get_defaults (FsCodec *codecs)
{
  GList *l = NULL;
  int i;

  for (i = 0; codecs[i].encoding_name != NULL; i++)
      l = g_list_append (l, fs_codec_copy (codecs + i));

  return l;
}
Exemple #5
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);
}
Exemple #6
0
/**
 * fs_codec_list_copy:
 * @codec_list: (transfer none) (element-type FsCodec):
 *   a GList of #FsCodec to copy
 *
 * Copies a list of #FsCodec structures.
 *
 * Returns: (element-type FsCodec) (transfer full): The new list.
 */
GList *
fs_codec_list_copy (const GList *codec_list)
{
  GQueue copy = G_QUEUE_INIT;
  const GList *lp;

  for (lp = codec_list; lp; lp = g_list_next (lp)) {
    FsCodec *codec = (FsCodec *) lp->data;

    g_queue_push_tail (&copy, fs_codec_copy (codec));
  }

  return copy.head;
}
/**
 * fs_codec_list_copy:
 * @codec_list: a GList of #FsCodec to copy
 *
 * Copies a list of #FsCodec structures.
 *
 * Returns: The new list.
 */
GList *
fs_codec_list_copy (const GList *codec_list)
{
  GList *copy = NULL;
  const GList *lp;
  FsCodec *codec;

  for (lp = codec_list; lp; lp = g_list_next (lp)) {
    codec = (FsCodec *) lp->data;
    /* prepend then reverse the list for efficiency */
    copy = g_list_prepend (copy, fs_codec_copy (codec));
  }
  copy = g_list_reverse (copy);
  return copy;
}
static void
update_sending_codec (EmpathyCallHandler *self,
    FsCodec *codec,
    FsSession *session)
{
  EmpathyCallHandlerPriv *priv = GET_PRIV (self);
  FsMediaType type;

  if (codec == NULL || session == NULL)
    return;

  g_object_get (session, "media-type", &type, NULL);

  if (type == FS_MEDIA_TYPE_AUDIO)
    {
      priv->send_audio_codec = fs_codec_copy (codec);
      g_object_notify (G_OBJECT (self), "send-audio-codec");
    }
  else if (type == FS_MEDIA_TYPE_VIDEO)
    {
      priv->send_video_codec = fs_codec_copy (codec);
      g_object_notify (G_OBJECT (self), "send-video-codec");
    }
}
GList *
fs_rtp_special_sources_get_codecs_locked (GList *special_sources,
    GList *codec_associations, FsCodec *main_codec)
{
  GList *result = NULL;

  for (; special_sources; special_sources = special_sources->next)
  {
    FsRtpSpecialSource *source = special_sources->data;

    if (main_codec->id != source->codec->id)
    {
      CodecAssociation *ca =
        lookup_codec_association_by_pt (codec_associations, source->codec->id);
      result = g_list_prepend (result, fs_codec_copy (ca->codec));
    }
  }

  result = g_list_reverse (result);

  return result;
}
Exemple #10
0
static void
fs_rtp_stream_get_property (GObject *object,
                            guint prop_id,
                            GValue *value,
                            GParamSpec *pspec)
{
  FsRtpStream *self = FS_RTP_STREAM (object);
  FsRtpSession *session = fs_rtp_stream_get_session (self, NULL);

  if (!session)
    return;

  switch (prop_id) {
    case PROP_REMOTE_CODECS:
      FS_RTP_SESSION_LOCK (session);
      g_value_set_boxed (value, self->remote_codecs);
      FS_RTP_SESSION_UNLOCK (session);
      break;
    case PROP_NEGOTIATED_CODECS:
      FS_RTP_SESSION_LOCK (session);
      g_value_set_boxed (value, self->negotiated_codecs);
      FS_RTP_SESSION_UNLOCK (session);
      break;
    case PROP_SESSION:
      g_value_set_object (value, session);
      break;
    case PROP_PARTICIPANT:
      FS_RTP_SESSION_LOCK (session);
      g_value_set_object (value, self->participant);
      FS_RTP_SESSION_UNLOCK (session);
      break;
    case PROP_DIRECTION:
      g_value_set_flags (value, self->priv->direction);
      break;
    case PROP_CURRENT_RECV_CODECS:
      {
        GList *codeclist = NULL;
        GList *substream_item;

        FS_RTP_SESSION_LOCK (session);
        for (substream_item = g_list_first (self->substreams);
             substream_item;
             substream_item = g_list_next (substream_item))
        {
          FsRtpSubStream *substream = substream_item->data;

          if (substream->codec)
          {
            if (!_codec_list_has_codec (codeclist, substream->codec))
              codeclist = g_list_append (codeclist,
                  fs_codec_copy (substream->codec));
          }
        }

        g_value_take_boxed (value, codeclist);
        FS_RTP_SESSION_UNLOCK (session);
      }
      break;
    case PROP_RTP_HEADER_EXTENSIONS:
      FS_RTP_SESSION_LOCK (session);
      g_value_set_boxed (value, self->hdrext);
      FS_RTP_SESSION_UNLOCK (session);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }

  g_object_unref (session);
}
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;
}
static GstElement *
fs_rtp_dtmf_sound_source_build (FsRtpSpecialSource *source,
                                GList *negotiated_codecs,
                                FsCodec *selected_codec)
{
    FsCodec *telephony_codec = NULL;
    GstCaps *caps = NULL;
    GstPad *pad = NULL;
    GstElement *dtmfsrc = NULL;
    GstElement *capsfilter = NULL;
    GstPad *ghostpad = NULL;
    GstElement *bin = NULL;
    GstElement *encoder = NULL;
    GstElement *payloader = NULL;
    gchar *encoder_name = NULL;
    gchar *payloader_name = NULL;

    telephony_codec = get_pcm_law_sound_codec (negotiated_codecs,
                      &encoder_name, &payloader_name);

    g_return_val_if_fail (telephony_codec, NULL);

    source->codec = fs_codec_copy (telephony_codec);

    GST_DEBUG ("Creating dtmf sound source for " FS_CODEC_FORMAT,
               FS_CODEC_ARGS (telephony_codec));

    bin = gst_bin_new (NULL);

    dtmfsrc = gst_element_factory_make ("dtmfsrc", NULL);
    if (!dtmfsrc)
    {
        GST_ERROR ("Could not make rtpdtmfsrc");
        goto error;
    }
    if (!gst_bin_add (GST_BIN (bin), dtmfsrc))
    {
        GST_ERROR ("Could not add rtpdtmfsrc to bin");
        gst_object_unref (dtmfsrc);
        goto error;
    }

    encoder = gst_element_factory_make (encoder_name, NULL);
    if (!encoder)
    {
        GST_ERROR ("Could not make %s", encoder_name);
        goto error;
    }
    if (!gst_bin_add (GST_BIN (bin), encoder))
    {
        GST_ERROR ("Could not add %s to bin", encoder_name);
        gst_object_unref (dtmfsrc);
        goto error;
    }

    if (!gst_element_link_pads (dtmfsrc, "src", encoder, "sink"))
    {
        GST_ERROR ("Could not link the rtpdtmfsrc and %s", encoder_name);
        goto error;
    }

    payloader = gst_element_factory_make (payloader_name, NULL);
    if (!payloader)
    {
        GST_ERROR ("Could not make %s", payloader_name);
        goto error;
    }
    if (!gst_bin_add (GST_BIN (bin), payloader))
    {
        GST_ERROR ("Could not add %s to bin", payloader_name);
        gst_object_unref (dtmfsrc);
        goto error;
    }

    if (!gst_element_link_pads (encoder, "src", payloader, "sink"))
    {
        GST_ERROR ("Could not link the %s and %s", encoder_name, payloader_name);
        goto error;
    }

    capsfilter = gst_element_factory_make ("capsfilter", NULL);
    if (!capsfilter)
    {
        GST_ERROR ("Could not make capsfilter");
        goto error;
    }
    if (!gst_bin_add (GST_BIN (bin), capsfilter))
    {
        GST_ERROR ("Could not add capsfilter to bin");
        gst_object_unref (capsfilter);
        goto error;
    }

    caps = fs_codec_to_gst_caps (telephony_codec);
    g_object_set (capsfilter, "caps", caps, NULL);
    {
        gchar *str = gst_caps_to_string (caps);
        GST_DEBUG ("Using caps %s for dtmf", str);
        g_free (str);
    }
    gst_caps_unref (caps);

    if (!gst_element_link_pads (payloader, "src", capsfilter, "sink"))
    {
        GST_ERROR ("Could not link the %s and its capsfilter", payloader_name);
        goto error;
    }

    pad = gst_element_get_static_pad (capsfilter, "src");
    if (!pad)
    {
        GST_ERROR ("Could not get \"src\" pad from capsfilter");
        goto error;
    }
    ghostpad = gst_ghost_pad_new ("src", pad);
    if (!ghostpad)
    {
        GST_ERROR ("Could not create a ghostpad for capsfilter src pad"
                   " for dtmfsrc");
        goto error;
    }
    if (!gst_element_add_pad (bin, ghostpad))
    {
        GST_ERROR ("Could not get \"src\" ghostpad to dtmf sound source bin");
        gst_object_unref (pad);
        goto error;
    }
    gst_object_unref (pad);

    return bin;

error:
    gst_object_unref (bin);

    return NULL;
}
/* insert given codec_cap list into list_codecs and list_codec_blueprints */
static void
parse_codec_cap_list (GList *list, FsMediaType media_type)
{
  GList *walk;
  CodecCap *codec_cap;
  FsCodec *codec;
  CodecBlueprint *codec_blueprint;
  gint i;
  gchar *tmp;
  GstElementFactory *tmpfact;

  /* go thru all common caps */
  for (walk = list; walk; walk = g_list_next (walk))
  {
    codec_cap = (CodecCap *)(walk->data);

    codec = g_slice_new0 (FsCodec);
    codec->id = FS_CODEC_ID_ANY;
    codec->clock_rate = 0;

    for (i = 0; i < gst_caps_get_size (codec_cap->rtp_caps); i++)
    {
      GstStructure *structure = gst_caps_get_structure (codec_cap->rtp_caps, i);

      gst_structure_foreach (structure, extract_field_data,
            (gpointer) codec);
    }

    if (!codec->encoding_name)
    {
      GstStructure *caps = gst_caps_get_structure (codec_cap->rtp_caps, 0);
      const gchar *encoding_name = codec->encoding_name ? codec->encoding_name
        : gst_structure_get_string (caps, "encoding-name");

      GST_DEBUG ("skipping codec %s/%s, no encoding name specified"
          " (pt: %d clock_rate:%u",
          media_type == FS_MEDIA_TYPE_AUDIO ? "audio" : "video",
          encoding_name ? encoding_name : "unknown", codec->id,
          codec->clock_rate);

      encoding_name = NULL;
      fs_codec_destroy (codec);
      continue;
    }

    switch (codec->media_type) {
      case FS_MEDIA_TYPE_VIDEO:
        if (!validate_h263_codecs (codec_cap)) {
          fs_codec_destroy (codec);
          continue;
        }
        break;
      case FS_MEDIA_TYPE_AUDIO:
        if (!validate_amr_codecs (codec_cap)) {
          fs_codec_destroy (codec);
          continue;
        }
        break;
      default:
        break;
    }

  another:

    codec_blueprint = g_slice_new0 (CodecBlueprint);
    codec_blueprint->codec = codec;
    codec_blueprint->media_caps = gst_caps_copy (codec_cap->caps);
    codec_blueprint->rtp_caps = gst_caps_copy (codec_cap->rtp_caps);

    codec_blueprint->send_pipeline_factory =
      copy_element_list (codec_cap->element_list2);
    codec_blueprint->receive_pipeline_factory =
      copy_element_list (codec_cap->element_list1);

    /* Lets add the converters at the beginning of the encoding pipelines */
    if (media_type == FS_MEDIA_TYPE_VIDEO)
    {
      tmpfact = gst_element_factory_find ("ffmpegcolorspace");
      if (tmpfact)
      {
        codec_blueprint->send_pipeline_factory = g_list_append (
            codec_blueprint->send_pipeline_factory,
            g_list_append (NULL, tmpfact));
      }
      tmpfact = gst_element_factory_find ("videoscale");
      if (tmpfact)
      {
        codec_blueprint->send_pipeline_factory = g_list_append (
            codec_blueprint->send_pipeline_factory,
            g_list_append (NULL, tmpfact));
      }
    }
    else if (media_type == FS_MEDIA_TYPE_AUDIO)
    {
      tmpfact = gst_element_factory_find ("audioconvert");
      if (tmpfact)
      {
        codec_blueprint->send_pipeline_factory = g_list_append (
            codec_blueprint->send_pipeline_factory,
            g_list_append (NULL, tmpfact));
      }
      tmpfact = gst_element_factory_find ("audioresample");
      if (tmpfact)
      {
        codec_blueprint->send_pipeline_factory = g_list_append (
            codec_blueprint->send_pipeline_factory,
            g_list_append (NULL, tmpfact));
      }
      tmpfact = gst_element_factory_find ("audioconvert");
      if (tmpfact)
      {
        codec_blueprint->send_pipeline_factory = g_list_append (
            codec_blueprint->send_pipeline_factory,
            g_list_append (NULL, tmpfact));
      }
    }

    /* insert new information into tables */
    list_codec_blueprints[media_type] = g_list_append (
        list_codec_blueprints[media_type], codec_blueprint);
    GST_DEBUG ("adding codec %s with pt %d, send_pipeline %p, receive_pipeline %p",
        codec->encoding_name, codec->id,
        codec_blueprint->send_pipeline_factory,
        codec_blueprint->receive_pipeline_factory);
    tmp = gst_caps_to_string (codec_blueprint->media_caps);
    GST_DEBUG ("media_caps: %s", tmp);
    g_free (tmp);
    tmp = gst_caps_to_string (codec_blueprint->rtp_caps);
    GST_DEBUG ("rtp_caps: %s", tmp);
    g_free (tmp);
    debug_pipeline (codec_blueprint->send_pipeline_factory);
    debug_pipeline (codec_blueprint->receive_pipeline_factory);

    if (!g_ascii_strcasecmp (codec->encoding_name, "H263-1998")) {
      codec = fs_codec_copy (codec);
      g_free (codec->encoding_name);
      codec->encoding_name = g_strdup ("H263-N800");
      goto another;
    }
  }
}
Exemple #15
0
static void
_substream_codec_changed (FsRtpSubStream *substream,
    FsRtpStream *stream)
{
  GList *substream_item = NULL;
  GList *codeclist = NULL;
  FsRtpSession *session = fs_rtp_stream_get_session (stream, NULL);

  if (!session)
    return;

  FS_RTP_SESSION_LOCK (session);

  if (!substream->codec)
  {
    FS_RTP_SESSION_UNLOCK (session);
    g_object_unref (session);
    return;
  }

  codeclist = g_list_prepend (NULL, fs_codec_copy (substream->codec));

  for (substream_item = stream->substreams;
       substream_item;
       substream_item = g_list_next (substream_item))
  {
    FsRtpSubStream *othersubstream = substream_item->data;

    if (othersubstream != substream)
    {
      if (othersubstream->codec)
      {
        if (fs_codec_are_equal (substream->codec, othersubstream->codec))
          break;

        if (!_codec_list_has_codec (codeclist, othersubstream->codec))
          codeclist = g_list_append (codeclist,
              fs_codec_copy (othersubstream->codec));
      }
    }
  }

  FS_RTP_SESSION_UNLOCK (session);

  if (substream_item == NULL)
  {
    GstElement *conf = NULL;

    g_object_notify (G_OBJECT (stream), "current-recv-codecs");

    g_object_get (session, "conference", &conf, NULL);

    gst_element_post_message (conf,
        gst_message_new_element (GST_OBJECT (conf),
            gst_structure_new ("farstream-recv-codecs-changed",
                "stream", FS_TYPE_STREAM, stream,
                "codecs", FS_TYPE_CODEC_LIST, codeclist,
                NULL)));

    gst_object_unref (conf);
  }

  fs_codec_list_destroy (codeclist);
  g_object_unref (session);
}
gboolean
fs_rtp_sub_stream_add_output_ghostpad_unlock (FsRtpSubStream *substream,
    GError **error)
{
  GstPad *valve_srcpad;
  gchar *padname = NULL;
  GstPad *ghostpad = NULL;
  FsCodec *codec = NULL;

  if (fs_rtp_sub_stream_has_stopped_enter (substream))
  {
    FS_RTP_SESSION_UNLOCK (substream->priv->session);
    return TRUE;
  }

  if (substream->priv->adding_output_ghostpad)
  {
    FS_RTP_SESSION_UNLOCK (substream->priv->session);
    goto out;
  }

  g_assert (substream->priv->output_ghostpad == NULL);

  substream->priv->adding_output_ghostpad = TRUE;

  padname = g_strdup_printf ("src_%u_%u_%d", substream->priv->session->id,
      substream->ssrc,
      substream->pt);

  FS_RTP_SESSION_UNLOCK (substream->priv->session);

  valve_srcpad = gst_element_get_static_pad (substream->priv->output_valve,
      "src");
  g_assert (valve_srcpad);

  ghostpad = gst_ghost_pad_new_from_template (padname, valve_srcpad,
      gst_element_class_get_pad_template (
          GST_ELEMENT_GET_CLASS (substream->priv->conference),
          "src_%d_%d_%d"));

  gst_object_unref (valve_srcpad);
  g_free (padname);

  if (!ghostpad)
  {
    g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION,
        "Could not build ghostpad src_%u_%u_%d", substream->priv->session->id,
        substream->ssrc, substream->pt);
    goto error;
  }

  if (!gst_pad_set_active (ghostpad, TRUE))
  {
    g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION,
        "Could not activate the src_%u_%u_%d", substream->priv->session->id,
        substream->ssrc, substream->pt);
    gst_object_unref (ghostpad);
    goto error;
  }

  if (!gst_element_add_pad (GST_ELEMENT (substream->priv->conference),
          ghostpad))
  {
    g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION,
        "Could add build ghostpad src_%u_%u_%d to the conference",
        substream->priv->session->id, substream->ssrc, substream->pt);
    gst_object_unref (ghostpad);
    goto error;
  }

  FS_RTP_SESSION_LOCK (substream->priv->session);
  substream->priv->output_ghostpad = ghostpad;

  GST_DEBUG ("Src pad added on substream for ssrc:%X pt:%u " FS_CODEC_FORMAT,
      substream->ssrc, substream->pt,
      FS_CODEC_ARGS (substream->codec));

  codec = fs_codec_copy (substream->codec);

  FS_RTP_SESSION_UNLOCK (substream->priv->session);

  g_signal_emit (substream, signals[SRC_PAD_ADDED], 0,
                 ghostpad, codec);
  g_signal_emit (substream, signals[CODEC_CHANGED], 0);

  fs_codec_destroy (codec);

  g_object_set (substream->priv->output_valve, "drop", FALSE, NULL);

 out:

  fs_rtp_sub_stream_has_stopped_exit (substream);
  return TRUE;

 error:

  substream->priv->adding_output_ghostpad = FALSE;
  fs_rtp_sub_stream_has_stopped_exit (substream);
  return FALSE;
}
static GstElement *
fs_rtp_dtmf_event_source_build (FsRtpSpecialSource *source,
                                GList *negotiated_codec_associations,
                                FsCodec *selected_codec)
{
    FsCodec *telephony_codec = NULL;
    GstCaps *caps = NULL;
    GstPad *pad = NULL;
    GstElement *dtmfsrc = NULL;
    GstElement *capsfilter = NULL;
    GstPad *ghostpad = NULL;
    GstElement *bin = NULL;

    telephony_codec = fs_rtp_dtmf_event_source_get_codec (
                          FS_RTP_SPECIAL_SOURCE_GET_CLASS(source), negotiated_codec_associations,
                          selected_codec);

    g_return_val_if_fail (telephony_codec, NULL);

    source->codec = fs_codec_copy (telephony_codec);

    bin = gst_bin_new (NULL);

    GST_DEBUG ("Creating telephone-event source for " FS_CODEC_FORMAT,
               FS_CODEC_ARGS (telephony_codec));

    dtmfsrc = gst_element_factory_make ("rtpdtmfsrc", NULL);
    if (!dtmfsrc)
    {
        GST_ERROR ("Could not make rtpdtmfsrc");
        goto error;
    }
    if (!gst_bin_add (GST_BIN (bin), dtmfsrc))
    {
        GST_ERROR ("Could not add rtpdtmfsrc to bin");
        gst_object_unref (dtmfsrc);
        goto error;
    }

    capsfilter = gst_element_factory_make ("capsfilter", NULL);
    if (!capsfilter)
    {
        GST_ERROR ("Could not make capsfilter");
        goto error;
    }
    if (!gst_bin_add (GST_BIN (bin), capsfilter))
    {
        GST_ERROR ("Could not add capsfilter to bin");
        gst_object_unref (capsfilter);
        goto error;
    }

    caps = fs_codec_to_gst_caps (telephony_codec);
    g_object_set (capsfilter, "caps", caps, NULL);
    {
        gchar *str = gst_caps_to_string (caps);
        GST_DEBUG ("Using caps %s for dtmf", str);
        g_free (str);
    }
    gst_caps_unref (caps);

    if (!gst_element_link_pads (dtmfsrc, "src", capsfilter, "sink"))
    {
        GST_ERROR ("Could not link the rtpdtmfsrc and its capsfilter");
        goto error;
    }

    pad = gst_element_get_static_pad (capsfilter, "src");
    if (!pad)
    {
        GST_ERROR ("Could not get \"src\" pad from capsfilter");
        goto error;
    }
    ghostpad = gst_ghost_pad_new ("src", pad);
    if (!ghostpad)
    {
        GST_ERROR ("Could not create a ghostpad for capsfilter src pad for"
                   " rtpdtmfsrc");
        goto error;
    }
    if (!gst_element_add_pad (bin, ghostpad))
    {
        GST_ERROR ("Could not get \"src\" ghostpad to dtmf source bin");
        gst_object_unref (pad);
        goto error;
    }
    gst_object_unref (pad);

    return bin;

error:
    gst_object_unref (bin);

    return NULL;
}