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; }
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); }
/** * 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 (©, 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; }
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; } } }
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; }