static void skype_audio_stream_update_codecs (SkypeBaseStream *stream, GList **codecs) { SkypeAudioStreamPrivate *priv = SKYPE_AUDIO_STREAM (stream)->priv; FsCodec *codec; gchar *value; guint telephony_pt = priv->last_telephony_pt; if (codecs == NULL || *codecs == NULL || (*codecs)->data == NULL) { g_warning ("update_codecs should not be passed an empty codec list"); return; } codec = (FsCodec *)((*codecs)->data); /* Add ptime value */ value = g_strdup_printf ("%d", priv->ptime); fs_codec_add_optional_parameter (codec, "ptime", value); g_free (value); /* Add telephony codec if needed */ if (priv->pending_telephony_pt != FS_CODEC_ID_DISABLE) telephony_pt = priv->pending_telephony_pt; if (telephony_pt != FS_CODEC_ID_DISABLE) { codec = fs_codec_new (telephony_pt, "telephone-event", FS_MEDIA_TYPE_AUDIO, 8000); fs_codec_add_optional_parameter (codec, "events", "0-11"); *codecs = g_list_append (*codecs, codec); } }
static FsCodec * init_codec_with_three_params (void) { FsCodec *codec = fs_codec_new (1, "aa", FS_MEDIA_TYPE_VIDEO, 650); fs_codec_add_optional_parameter (codec, "aa1", "bb1"); fs_codec_add_optional_parameter (codec, "aa2", "bb2"); fs_codec_add_optional_parameter (codec, "aa3", "bb3"); fs_codec_add_feedback_parameter (codec, "aa1", "bb1", "cc1"); fs_codec_add_feedback_parameter (codec, "aa2", "bb2", "cc2"); fs_codec_add_feedback_parameter (codec, "aa3", "bb3", "cc3"); return codec; }
static void caps_changed (GstPad *pad, GParamSpec *spec, FsStream *stream) { GstCaps *caps; GstStructure *s; FsCodec *codec; GList *codecs; const gchar *config; GError *error = NULL; g_object_get (pad, "caps", &caps, NULL); if (!caps) return; s = gst_caps_get_structure (caps, 0); codec = fs_codec_new (96, "THEORA", FS_MEDIA_TYPE_VIDEO, 90000); config = gst_structure_get_string (s, "configuration"); if (config) fs_codec_add_optional_parameter (codec, "configuration", config); codecs = g_list_prepend (NULL, codec); fail_unless (fs_stream_set_remote_codecs (stream, codecs, &error), "Unable to set remote codec: %s", error ? error->message : "UNKNOWN"); fs_codec_list_destroy (codecs); }
static void keep_config_from_old_codec (FsCodec *new_codec, FsCodec *old_codec) { GList *item; for (item = old_codec->optional_params; item; item = item->next) { FsCodecParameter *oldparam = item->data; if (!fs_codec_get_optional_parameter (new_codec, oldparam->name, NULL) && codec_has_config_data_named (new_codec, oldparam->name)) fs_codec_add_optional_parameter (new_codec, oldparam->name, oldparam->value); } }
static void _simple_profile_init (struct SimpleTestStream *st, guint confid, guint streamid) { GList *prefs = NULL; FsCodec *codec = NULL; gboolean ret; codec = fs_codec_new (0, "PCMU", FS_MEDIA_TYPE_AUDIO, 8000); fs_codec_add_optional_parameter (codec, "farstream-send-profile", "audioconvert ! audioresample ! audioconvert ! mulawenc ! rtppcmupay"); prefs = g_list_append (NULL, codec); ret = fs_session_set_codec_preferences (st->dat->session, prefs, NULL); ts_fail_unless (ret, "set codec prefs"); fs_codec_list_destroy (prefs); }
static CodecBlueprint * load_codec_blueprint (FsMediaType media_type, gchar **in, gsize *size) { CodecBlueprint *codec_blueprint = g_slice_new0 (CodecBlueprint); gchar *tmp; gint tmp_size; int i; gint id; gchar *encoding_name = NULL; guint clock_rate; READ_CHECK (read_codec_blueprint_int (in, size, &(id))); READ_CHECK (read_codec_blueprint_string (in, size, &(encoding_name))); READ_CHECK (read_codec_blueprint_uint (in, size, &(clock_rate))); codec_blueprint->codec = fs_codec_new (id, encoding_name, media_type, clock_rate); g_free (encoding_name); READ_CHECK (read_codec_blueprint_uint (in, size, &(codec_blueprint->codec->channels))); READ_CHECK (read_codec_blueprint_int (in, size, &tmp_size)); for (i = 0; i < tmp_size; i++) { gchar *name, *value; READ_CHECK (read_codec_blueprint_string (in, size, &(name))); READ_CHECK (read_codec_blueprint_string (in, size, &(value))); fs_codec_add_optional_parameter (codec_blueprint->codec, name, value); g_free (name); g_free (value); } READ_CHECK (read_codec_blueprint_string (in, size, &tmp)); codec_blueprint->media_caps = gst_caps_from_string (tmp); g_free (tmp); READ_CHECK (read_codec_blueprint_string (in, size, &tmp)); codec_blueprint->rtp_caps = gst_caps_from_string (tmp); g_free (tmp); READ_CHECK (read_codec_blueprint_int (in, size, &tmp_size)); for (i = 0; i < tmp_size; i++) { int j, tmp_size2; GList *tmplist = NULL; READ_CHECK (read_codec_blueprint_int (in, size, &tmp_size2)); for (j = 0; j < tmp_size2; j++) { GstElementFactory *fact = NULL; READ_CHECK (read_codec_blueprint_string (in, size, &(tmp))); fact = gst_element_factory_find (tmp); g_free (tmp); if (!fact) goto error; tmplist = g_list_append (tmplist, fact); } codec_blueprint->send_pipeline_factory = g_list_append (codec_blueprint->send_pipeline_factory, tmplist); } READ_CHECK (read_codec_blueprint_int (in, size, &tmp_size)); for (i = 0; i < tmp_size; i++) { int j, tmp_size2; GList *tmplist = NULL; READ_CHECK (read_codec_blueprint_int (in, size, &tmp_size2)); for (j = 0; j < tmp_size2; j++) { GstElementFactory *fact = NULL; READ_CHECK (read_codec_blueprint_string (in, size, &(tmp))); fact = gst_element_factory_find (tmp); g_free (tmp); if (!fact) goto error; tmplist = g_list_append (tmplist, fact); } codec_blueprint->receive_pipeline_factory = g_list_append (codec_blueprint->receive_pipeline_factory, tmplist); } GST_DEBUG ("adding codec %s with pt %d, send_pipeline %p, receive_pipeline %p", codec_blueprint->codec->encoding_name, codec_blueprint->codec->id, codec_blueprint->send_pipeline_factory, codec_blueprint->receive_pipeline_factory); return codec_blueprint; error: codec_blueprint_destroy (codec_blueprint); 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; }
/** * fill FarsightCodec fields based on payloader capabilities * TODO: optimise using quarks */ static gboolean extract_field_data (GQuark field_id, const GValue *value, gpointer user_data) { /* TODO : This can be called several times from different rtp caps for the * same codec, it would be good to make sure any duplicate values are the * same, if not then we have several rtp elements that are giving different * caps information, therefore they need to be fixed */ FsCodec *codec = (FsCodec *) user_data; GType type = G_VALUE_TYPE (value); const gchar *field_name = g_quark_to_string (field_id); const gchar *tmp; if (0 == strcmp (field_name, "media")) { if (type != G_TYPE_STRING) { return FALSE; } tmp = g_value_get_string (value); if (strcmp (tmp, "audio") == 0) { codec->media_type = FS_MEDIA_TYPE_AUDIO; } else if (strcmp (tmp, "video") == 0) { codec->media_type = FS_MEDIA_TYPE_VIDEO; } } else if (0 == strcmp (field_name, "payload")) { if (type == GST_TYPE_INT_RANGE) { if (gst_value_get_int_range_min (value) < 96 || gst_value_get_int_range_max (value) > 255) { return FALSE; } } else if (type == G_TYPE_INT) { int id; id = g_value_get_int (value); if (id > 96) { /* Dynamic id that was explicitelly set ?? shouldn't happen */ return FALSE; } codec->id = id; } else { return FALSE; } } else if (0 == strcmp (field_name, "clock-rate")) { if (type == GST_TYPE_INT_RANGE) { /* set to 0, this should be checked by the optional parameters code later * in Farsight */ codec->clock_rate = 0; return TRUE; } else if (type != G_TYPE_INT) { return FALSE; } codec->clock_rate = g_value_get_int (value); } else if (0 == strcmp (field_name, "ssrc") || 0 == strcmp (field_name, "clock-base") || 0 == strcmp (field_name, "seqnum-base")) { // ignore these fields for now ; } else if (0 == strcmp (field_name, "encoding-name")) { if (type != G_TYPE_STRING) { return FALSE; } if (!codec->encoding_name) { codec->encoding_name = g_value_dup_string (value); } } else if (0 == strcmp (field_name, "encoding-params")) { if (type != G_TYPE_STRING) { return FALSE; } codec->channels = (guint) g_ascii_strtoull ( g_value_get_string (value), NULL, 10); } else { if (type == G_TYPE_STRING) fs_codec_add_optional_parameter (codec, field_name, g_value_get_string (value)); } return TRUE; }
static GList* fs_rtp_dtmf_event_source_class_add_blueprint (FsRtpSpecialSourceClass *klass, GList *blueprints) { GList *item; GList *already_done = NULL; GstElementFactory *fact = NULL; GList *new_blueprints = NULL; fact = gst_element_factory_find ("rtpdtmfsrc"); if (fact) { gst_object_unref (fact); } else { GST_CAT_WARNING (fsrtpconference_disco, "Could not find rtpdtmfsrc, will not offer DTMF events"); return blueprints; } fact = gst_element_factory_find ("rtpdtmfdepay"); if (!fact) GST_CAT_WARNING (fsrtpconference_disco, "Could not find rtpdtmfdepay, will not be able to receive DTMF events"); for (item = g_list_first (blueprints); item; item = g_list_next (item)) { CodecBlueprint *bp = item->data; GList *done_item = NULL; gboolean skip = FALSE; CodecBlueprint *new_bp = NULL; if (bp->codec->media_type != FS_MEDIA_TYPE_AUDIO) continue; if (!g_ascii_strcasecmp (bp->codec->encoding_name, "telephone-event")) continue; if (bp->codec->clock_rate == 0) continue; for (done_item = g_list_first (already_done); done_item; done_item = g_list_next (done_item)) { if (GPOINTER_TO_UINT (done_item->data) == bp->codec->clock_rate) { skip = TRUE; break; } } if (skip) continue; new_bp = g_slice_new0 (CodecBlueprint); new_bp->codec = fs_codec_new (FS_CODEC_ID_ANY, "telephone-event", FS_MEDIA_TYPE_AUDIO, bp->codec->clock_rate); fs_codec_add_optional_parameter (new_bp->codec, "events", "0-15"); new_bp->rtp_caps = fs_codec_to_gst_caps (new_bp->codec); new_bp->media_caps = gst_caps_new_any (); if (fact) new_bp->receive_pipeline_factory = g_list_prepend (NULL, g_list_prepend (NULL, gst_object_ref (fact))); new_blueprints = g_list_append (new_blueprints, new_bp); already_done = g_list_prepend (already_done, GUINT_TO_POINTER (bp->codec->clock_rate)); } if (fact) gst_object_unref (fact); g_list_free (already_done); blueprints = g_list_concat (blueprints, new_blueprints); return blueprints; }