static void _codec_association_destroy (CodecAssociation *ca) { if (!ca) return; fs_codec_destroy (ca->codec); fs_codec_destroy (ca->send_codec); g_free (ca->send_profile); g_free (ca->recv_profile); g_slice_free (CodecAssociation, ca); }
static void empathy_call_handler_finalize (GObject *object) { EmpathyCallHandlerPriv *priv = GET_PRIV (object); fs_codec_destroy (priv->send_audio_codec); fs_codec_destroy (priv->send_video_codec); fs_codec_list_destroy (priv->recv_audio_codecs); fs_codec_list_destroy (priv->recv_video_codecs); fs_candidate_destroy (priv->audio_remote_candidate); fs_candidate_destroy (priv->video_remote_candidate); fs_candidate_destroy (priv->audio_local_candidate); fs_candidate_destroy (priv->video_local_candidate); G_OBJECT_CLASS (empathy_call_handler_parent_class)->finalize (object); }
static void fs_rtp_special_source_finalize (GObject *object) { FsRtpSpecialSource *self = FS_RTP_SPECIAL_SOURCE (object); if (self->priv->rtpmuxer) { gst_object_unref (self->priv->rtpmuxer); self->priv->rtpmuxer = NULL; } if (self->priv->outer_bin) { gst_object_unref (self->priv->outer_bin); self->priv->outer_bin = NULL; } if (self->codec) fs_codec_destroy (self->codec); self->codec = NULL; if (self->priv->mutex) g_mutex_free (self->priv->mutex); self->priv->mutex = NULL; G_OBJECT_CLASS (fs_rtp_special_source_parent_class)->finalize (object); }
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 void negotiate_stream_codec (CodecAssociation *old_ca, FsCodec *remote_codec, gboolean multi_stream, FsCodec **nego_codec, FsCodec **nego_send_codec) { if (multi_stream) *nego_codec = sdp_negotiate_codec (old_ca->codec, FS_PARAM_TYPE_ALL, remote_codec, FS_PARAM_TYPE_SEND | FS_PARAM_TYPE_SEND_AVOID_NEGO); else *nego_codec = sdp_negotiate_codec (old_ca->codec, FS_PARAM_TYPE_ALL, remote_codec, FS_PARAM_TYPE_SEND); if (*nego_codec) { if (multi_stream) *nego_send_codec = sdp_negotiate_codec ( old_ca->send_codec, FS_PARAM_TYPE_BOTH | FS_PARAM_TYPE_SEND_AVOID_NEGO, remote_codec, FS_PARAM_TYPE_SEND | FS_PARAM_TYPE_SEND_AVOID_NEGO); else *nego_send_codec = sdp_negotiate_codec ( old_ca->send_codec, FS_PARAM_TYPE_BOTH, remote_codec, FS_PARAM_TYPE_SEND | FS_PARAM_TYPE_SEND_AVOID_NEGO); /* If send codec can't be negotiated, try another one */ if (!*nego_send_codec) { fs_codec_destroy (*nego_codec); *nego_codec = NULL; } } }
/** * fs_codec_list_destroy: (skip): * @codec_list: a GList of #FsCodec to delete * * Deletes a list of #FsCodec structures and the list itself. * Does nothing on %NULL lists. */ void fs_codec_list_destroy (GList *codec_list) { GList *lp; FsCodec *codec; for (lp = codec_list; lp; lp = g_list_next (lp)) { codec = (FsCodec *) lp->data; fs_codec_destroy (codec); lp->data = NULL; } g_list_free (codec_list); }
static gboolean codec_sdp_compare (FsCodec *local_codec, FsCodec *remote_codec) { FsCodec *nego_codec = sdp_negotiate_codec ( local_codec, FS_PARAM_TYPE_ALL & ~FS_PARAM_TYPE_CONFIG, remote_codec, FS_PARAM_TYPE_ALL & ~FS_PARAM_TYPE_CONFIG); if (!nego_codec) return FALSE; fs_codec_destroy (nego_codec); return TRUE; }
static void fs_rtp_sub_stream_finalize (GObject *object) { FsRtpSubStream *self = FS_RTP_SUB_STREAM (object); if (self->codec) fs_codec_destroy (self->codec); if (self->priv->caps) gst_caps_unref (self->priv->caps); if (self->priv->mutex) g_mutex_free (self->priv->mutex); G_OBJECT_CLASS (fs_rtp_sub_stream_parent_class)->finalize (object); }
void codec_blueprint_destroy (CodecBlueprint *codec_blueprint) { GList *walk; if (codec_blueprint->codec) { fs_codec_destroy (codec_blueprint->codec); } if (codec_blueprint->media_caps) { gst_caps_unref (codec_blueprint->media_caps); } if (codec_blueprint->rtp_caps) { gst_caps_unref (codec_blueprint->rtp_caps); } for (walk = codec_blueprint->send_pipeline_factory; walk; walk = g_list_next (walk)) { if (walk->data) { g_list_foreach (walk->data, (GFunc) gst_object_unref, NULL); g_list_free (walk->data); } } for (walk = codec_blueprint->receive_pipeline_factory; walk; walk = g_list_next (walk)) { if (walk->data) { g_list_foreach (walk->data, (GFunc) gst_object_unref, NULL); g_list_free (walk->data); } } g_list_free (codec_blueprint->send_pipeline_factory); g_list_free (codec_blueprint->receive_pipeline_factory); g_slice_free (CodecBlueprint, codec_blueprint); }
static void _connected ( FsMsnConnection *connection, guint fd, gpointer user_data) { FsMsnStream *self = FS_MSN_STREAM (user_data); GError *error = NULL; GstPad *pad; GstElement *fdelem; int checkfd; FsMsnConference *conference = fs_msn_stream_get_conference (self, NULL); GstElement *codecbin = NULL; GstElement *recv_valve = NULL; GstElement *send_valve = NULL; gboolean drop; if (!conference) goto error; GST_DEBUG ("******** CONNECTED %d**********", fd); gst_element_post_message (GST_ELEMENT (conference), gst_message_new_element (GST_OBJECT (conference), gst_structure_new ("farstream-component-state-changed", "stream", FS_TYPE_STREAM, self, "component", G_TYPE_UINT, 1, "state", FS_TYPE_STREAM_STATE, FS_STREAM_STATE_READY, NULL))); if (self->priv->conference->max_direction == FS_DIRECTION_RECV) codecbin = gst_parse_bin_from_description ( "fdsrc name=fdsrc do-timestamp=true ! mimdec ! valve name=recv_valve", TRUE, &error); else codecbin = gst_parse_bin_from_description ( "videoconvert ! videoscale ! mimenc name=enc !" " fdsink name=fdsink sync=false async=false", TRUE, &error); if (!codecbin) { g_prefix_error (&error, "Error creating codecbin: "); fs_stream_emit_error (FS_STREAM (self), FS_ERROR_CONSTRUCTION, error->message); g_clear_error (&error); goto error; } /* So we don't require an unlreased gst-plugins-bad mimenc */ if (self->priv->conference->max_direction == FS_DIRECTION_SEND) { GstElement *mimenc = gst_bin_get_by_name (GST_BIN (codecbin), "enc"); if (g_object_class_find_property ( G_OBJECT_GET_CLASS (mimenc), "paused-mode")) g_object_set (mimenc, "paused-mode", TRUE, NULL); gst_object_unref (mimenc); } if (self->priv->conference->max_direction == FS_DIRECTION_RECV) { fdelem = gst_bin_get_by_name (GST_BIN (codecbin), "fdsrc"); gst_base_src_set_format (GST_BASE_SRC (fdelem), GST_FORMAT_TIME); } else { fdelem = gst_bin_get_by_name (GST_BIN (codecbin), "fdsink"); } if (!fdelem) { fs_stream_emit_error (FS_STREAM (self), FS_ERROR_CONSTRUCTION, "Could not get fd element"); goto error; } g_object_set (fdelem, "fd", fd, NULL); g_object_get (fdelem, "fd", &checkfd, NULL); gst_object_unref (fdelem); if (fd != checkfd) { fs_stream_emit_error (FS_STREAM (self), FS_ERROR_INTERNAL, "Could not set file descriptor"); goto error; } if (self->priv->conference->max_direction == FS_DIRECTION_RECV) pad = gst_element_get_static_pad (codecbin, "src"); else pad = gst_element_get_static_pad (codecbin, "sink"); if (!pad) { fs_stream_emit_error (FS_STREAM (self), FS_ERROR_CONSTRUCTION, "Could not get codecbin pad"); goto error; } if (!gst_bin_add (GST_BIN (conference), codecbin)) { gst_object_unref (pad); fs_stream_emit_error (FS_STREAM (self), FS_ERROR_CONSTRUCTION, "Could not add codecbin to the conference"); goto error; } GST_OBJECT_LOCK (conference); self->priv->fd = fd; self->priv->codecbin = gst_object_ref (codecbin); GST_OBJECT_UNLOCK (conference); if (self->priv->conference->max_direction == FS_DIRECTION_RECV) { FsCodec *mimic_codec; GstPad *src_pad; src_pad = gst_ghost_pad_new ("src_1_1_1", pad); gst_object_unref (pad); GST_OBJECT_LOCK (conference); self->priv->src_pad = gst_object_ref (src_pad); GST_OBJECT_UNLOCK (conference); gst_pad_set_active (src_pad, TRUE); if (!gst_element_add_pad (GST_ELEMENT (conference), src_pad)) { fs_stream_emit_error (FS_STREAM (self), FS_ERROR_CONSTRUCTION, "Could not add src_1_1_1 pad"); gst_object_unref (src_pad); goto error; } recv_valve = gst_bin_get_by_name (GST_BIN (codecbin), "recv_valve"); if (!recv_valve) { fs_stream_emit_error (FS_STREAM (self), FS_ERROR_CONSTRUCTION, "Could not get recv_valve"); gst_object_unref (src_pad); goto error; } GST_OBJECT_LOCK (conference); self->priv->recv_valve = gst_object_ref (recv_valve); drop = !(self->priv->direction & FS_DIRECTION_RECV); GST_OBJECT_UNLOCK (conference); g_object_set (recv_valve, "drop", drop, NULL); mimic_codec = fs_codec_new (0, "mimic", FS_MEDIA_TYPE_VIDEO, 0); fs_stream_emit_src_pad_added (FS_STREAM (self), src_pad, mimic_codec); fs_codec_destroy (mimic_codec); gst_object_unref (src_pad); } else { GstPad *valvepad; GST_OBJECT_LOCK (conference); if (self->priv->session->valve) send_valve = gst_object_ref (self->priv->session->valve); GST_OBJECT_UNLOCK (conference); if (!send_valve) { fs_stream_emit_error (FS_STREAM (self), FS_ERROR_DISPOSED, "Session was disposed"); goto error; } valvepad = gst_element_get_static_pad (send_valve, "src"); if (!valvepad) { gst_object_unref (pad); fs_stream_emit_error (FS_STREAM (self), FS_ERROR_CONSTRUCTION, "Could not get valve sink pad"); goto error; } if (GST_PAD_LINK_FAILED (gst_pad_link (valvepad, pad))) { gst_object_unref (valvepad); gst_object_unref (pad); fs_stream_emit_error (FS_STREAM (self), FS_ERROR_CONSTRUCTION, "Could not link valve to codec bin"); goto error; } gst_object_unref (valvepad); gst_object_unref (pad); } if (!gst_element_sync_state_with_parent (codecbin)) { fs_stream_emit_error (FS_STREAM (self), FS_ERROR_CONSTRUCTION, "Could not start codec bin"); goto error; } if (self->priv->conference->max_direction == FS_DIRECTION_SEND) { GST_OBJECT_LOCK (conference); fs_msn_stream_set_tos_locked (self, self->priv->tos); drop = !(self->priv->direction & FS_DIRECTION_SEND); GST_OBJECT_UNLOCK (conference); g_object_set (send_valve, "drop", drop, NULL); } error: if (send_valve) gst_object_unref (send_valve); if (recv_valve) gst_object_unref (recv_valve); if (codecbin) gst_object_unref (codecbin); if (conference) gst_object_unref (conference); }
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; }
gboolean skype_audio_stream_send_dtmf (SkypeAudioStream *self, int event, int type) { SkypeAudioStreamPrivate *priv = self->priv; FsuSession *session; FsSession *fssession; FsDTMFMethod method; gboolean ret = TRUE; GstStructure *structure; GstEvent *gstevent; g_debug ("Sending telephony event: %d, type: %d", event, type); structure = gst_structure_new ("dtmf-event", "type", G_TYPE_INT, 1, "number", G_TYPE_INT, event, "volume", G_TYPE_INT, 8, "start", G_TYPE_BOOLEAN, TRUE, NULL); gstevent = gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM, structure); if (!gst_element_send_event (priv->dtmfsrc, gstevent)) g_warning ("DTMF start event wasn't applied"); structure = gst_structure_new ("dtmf-event", "type", G_TYPE_INT, 1, "number", G_TYPE_INT, event, "volume", G_TYPE_INT, 8, "start", G_TYPE_BOOLEAN, FALSE, NULL); gstevent = gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM, structure); if (!gst_element_send_event (priv->dtmfsrc, gstevent)) g_warning ("DTMF start event wasn't applied"); if (g_queue_is_empty (priv->event_queue)) { /* The type argument doubles as both the type of event * (RTP or in-band) as well as the PT to use if it's RTP */ if (type == SKYPE_DTMF_EVENT_TYPE_IN_BAND) { method = FS_DTMF_METHOD_IN_BAND; } else if (type == priv->last_telephony_pt) { /* Play now only if the current PT matches the desired one */ method = FS_DTMF_METHOD_RTP_RFC4733; } else { FsCodec *codec; /* Can't play the DTMF event now, queue the event and update codecs */ DTMFQueueEvent *dtmf_event = g_slice_new0 (DTMFQueueEvent); dtmf_event->event_nr = event; dtmf_event->rtp_type = type; g_queue_push_tail (priv->event_queue, dtmf_event); priv->pending_telephony_pt = type; /* Trigger a codec update */ g_object_get (self, "codec", &codec, NULL); g_object_set (self, "codec", codec, NULL); fs_codec_destroy (codec); return ret; } } else { /* Other events are pending, queue this one */ DTMFQueueEvent *dtmf_event = g_slice_new0 (DTMFQueueEvent); dtmf_event->event_nr = event; dtmf_event->rtp_type = type; g_queue_push_tail (priv->event_queue, dtmf_event); return ret; } g_object_get (priv->stream, "fsu-session", &session, NULL); if (session == NULL) { g_warning ("SendDTMF: session == NULL"); return FALSE; } g_object_get (session, "fs-session", &fssession, NULL); g_object_unref (session); if (fssession == NULL) { g_warning ("SendDTMF: fssession == NULL"); return FALSE; } /* Play the event */ if (!fs_session_start_telephony_event (fssession, event, 0, method)) { g_warning ("Telephony event type not supported"); ret = FALSE; } else { fs_session_stop_telephony_event (fssession, method); } g_object_unref (fssession); return ret; }
/** * 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; }
static gboolean fs_rtp_sub_stream_set_codecbin (FsRtpSubStream *substream, FsCodec *codec, GstElement *codecbin, GError **error) { GstCaps *caps = NULL; gchar *tmp; gboolean ret = FALSE; GstPad *pad; if (substream->priv->codecbin) { gst_element_set_locked_state (substream->priv->codecbin, TRUE); if (gst_element_set_state (substream->priv->codecbin, GST_STATE_NULL) != GST_STATE_CHANGE_SUCCESS) { gst_element_set_locked_state (substream->priv->codecbin, FALSE); g_set_error (error, FS_ERROR, FS_ERROR_INTERNAL, "Could not set the codec bin for ssrc %u" " and payload type %d to the state NULL", substream->ssrc, substream->pt); gst_object_unref (codecbin); fs_codec_destroy (codec); return FALSE; } gst_bin_remove (GST_BIN (substream->priv->conference), substream->priv->codecbin); FS_RTP_SESSION_LOCK (substream->priv->session); substream->priv->codecbin = NULL; if (substream->codec) { fs_codec_destroy (substream->codec); substream->codec = NULL; } if (substream->priv->caps) gst_caps_unref (substream->priv->caps); substream->priv->caps = NULL; FS_RTP_SESSION_UNLOCK (substream->priv->session); } if (!gst_bin_add (GST_BIN (substream->priv->conference), codecbin)) { gst_object_unref (codecbin); fs_codec_destroy (codec); g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION, "Could not add the codec bin to the conference"); return FALSE; } if (gst_element_set_state (codecbin, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION, "Could not set the codec bin to the playing state"); goto error; } if (!gst_element_link_pads (codecbin, "src", substream->priv->output_valve, "sink")) { g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION, "Could not link the codec bin to the output_valve"); goto error; } if (!gst_element_link_pads (substream->priv->capsfilter, "src", codecbin, "sink")) { g_set_error (error, FS_ERROR, FS_ERROR_CONSTRUCTION, "Could not link the receive capsfilter and the codecbin for pt %d", substream->pt); goto error; } caps = fs_codec_to_gst_caps (codec); tmp = gst_caps_to_string (caps); GST_DEBUG ("Setting caps %s on recv substream", tmp); g_free (tmp); g_object_set (substream->priv->capsfilter, "caps", caps, NULL); pad = gst_element_get_static_pad (codecbin, "sink"); if (!pad) { g_set_error (error, FS_ERROR, FS_ERROR_INTERNAL, "Could not get sink pad" " from codecbin"); goto error; } /* This is a non-error error * Some codecs require config data to start.. so we should just ignore them */ if (!gst_pad_set_caps (pad, caps)) { ret = TRUE; gst_object_unref (pad); gst_caps_unref (caps); GST_DEBUG ("Could not set the caps on the codecbin, waiting on config-data" " for SSRC:%x pt:%d", substream->ssrc, substream->pt); /* We call this to drop all buffers until something comes up */ fs_rtp_sub_stream_add_probe_locked (substream); goto error; } GST_DEBUG ("New recv codec accepted"); gst_object_unref (pad); FS_RTP_SESSION_LOCK (substream->priv->session); substream->priv->caps = caps; substream->priv->codecbin = codecbin; substream->codec = codec; codec = NULL; if (substream->priv->stream && !substream->priv->output_ghostpad) { if (!fs_rtp_sub_stream_add_output_ghostpad_unlock (substream, error)) goto error; } else { FS_RTP_SESSION_UNLOCK (substream->priv->session); g_signal_emit (substream, signals[CODEC_CHANGED], 0); } return TRUE; error: gst_element_set_locked_state (codecbin, TRUE); gst_element_set_state (codecbin, GST_STATE_NULL); gst_bin_remove (GST_BIN (substream->priv->conference), codecbin); fs_codec_destroy (codec); return ret; }
gboolean skype_audio_stream_handle_message (SkypeBaseStream *self, GstMessage *message) { SkypeAudioStreamPrivate *priv = SKYPE_AUDIO_STREAM (self)->priv; GstStructure *structure; FsSession *session = NULL; GList *secondary_codecs = NULL; GList *iter; if (GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT) return FALSE; structure = (GstStructure *)gst_message_get_structure (message); if (!gst_structure_has_name (structure, "farsight-send-codec-changed")) return FALSE; gst_structure_get (structure, "session", FS_TYPE_SESSION, &session, "secondary-codecs", FS_TYPE_CODEC_LIST, &secondary_codecs, NULL); /* Update the current telephony PT */ for (iter = secondary_codecs; iter != NULL; iter = g_list_next (iter)) { FsCodec *codec = (FsCodec *)iter->data; if (codec != NULL && !g_strcmp0 (codec->encoding_name, "telephone-event")) { priv->last_telephony_pt = codec->id; if (priv->pending_telephony_pt != FS_CODEC_ID_DISABLE && priv->pending_telephony_pt == priv->last_telephony_pt) priv->pending_telephony_pt = FS_CODEC_ID_DISABLE; break; } } while (!g_queue_is_empty (priv->event_queue)) { DTMFQueueEvent *event = (DTMFQueueEvent *) g_queue_pop_head (priv->event_queue); FsDTMFMethod method = FS_DTMF_METHOD_AUTO; if (event->rtp_type == SKYPE_DTMF_EVENT_TYPE_IN_BAND) { method = FS_DTMF_METHOD_IN_BAND; } else if (event->rtp_type == priv->last_telephony_pt) { method = FS_DTMF_METHOD_RTP_RFC4733; } else { /* New PT needed. Update codecs */ FsCodec *codec; g_queue_push_head (priv->event_queue, event); priv->pending_telephony_pt = event->rtp_type; /* Trigger a codec update */ g_object_get (self, "codec", &codec, NULL); g_object_set (self, "codec", codec, NULL); fs_codec_destroy (codec); break; } if (!fs_session_start_telephony_event (session, event->event_nr, 0, method)) { g_warning ("Telephony event type not supported"); g_queue_push_head (priv->event_queue, event); } else { fs_session_stop_telephony_event (session, method); } g_slice_free (DTMFQueueEvent, event); } g_object_unref (session); fs_codec_list_destroy (secondary_codecs); return TRUE; }
/** * fs_codec_list_from_keyfile * @filename: Name of the #GKeyFile to read the codecs parameters from * @error: location of a #GError, or NULL if no error occured * * Reads the content of a #GKeyFile of the following format into * a #GList of #FsCodec structures. * * * Example: * |[ * [audio/codec1] * clock-rate=8000 * * [audio/codec1:1] * clock-rate=16000 * * [audio/codec2] * one_param=QCIF * another_param=WOW * ]| * * Return value: The #GList of #FsCodec or %NULL if the keyfile was empty * or an error occured. */ GList * fs_codec_list_from_keyfile (const gchar *filename, GError **error) { GKeyFile *keyfile = NULL; GList *codecs = NULL; GError *gerror = NULL; gchar **groups = NULL; gsize groups_count = 0; int i; g_assert (filename); keyfile = g_key_file_new (); if (!g_key_file_load_from_file (keyfile, filename, G_KEY_FILE_NONE, error)) { goto out; } groups = g_key_file_get_groups (keyfile, &groups_count); if (!groups) goto out; for (i=0; i < groups_count && groups[i]; i++) { FsCodec *codec = g_slice_new0 (FsCodec); gchar **keys = NULL; gsize keys_count; int j; gchar *encoding_name = NULL; gchar *next_tok = NULL; codec->id = FS_CODEC_ID_ANY; keys = g_key_file_get_keys (keyfile, groups[i], &keys_count, &gerror); if (!keys || gerror) { if (gerror) { GST_WARNING ("Unable to read parameters for %s: %s\n", groups[i], gerror->message); } else { GST_WARNING ("Unknown errors while reading parameters for %s", groups[i]); } g_clear_error (&gerror); goto next_codec; } next_tok = strchr (groups[i], '/'); if (!next_tok) { GST_WARNING ("Invalid codec name: %s", groups[i]); goto next_codec; } if ((next_tok - groups[i]) == 5 /* strlen ("audio") */ && !g_ascii_strncasecmp ("audio", groups[i], 5)) codec->media_type = FS_MEDIA_TYPE_AUDIO; else if ((next_tok - groups[i]) == 5 /* strlen ("video") */ && !g_ascii_strncasecmp ("video", groups[i], 5)) codec->media_type = FS_MEDIA_TYPE_VIDEO; else { GST_WARNING ("Invalid media type in codec name name %s", groups[i]); goto next_codec; } encoding_name = next_tok+1; next_tok = strchr (groups[i], ':'); if (next_tok) { codec->encoding_name = g_strndup (encoding_name, next_tok - encoding_name); } else { codec->encoding_name = g_strdup (encoding_name); } if (!codec->encoding_name || codec->encoding_name[0] == 0) { goto next_codec; } for (j = 0; j < keys_count && keys[j]; j++) { if (!strcmp ("clock-rate", keys[j])) { codec->clock_rate = g_key_file_get_integer (keyfile, groups[i], keys[j], &gerror); if (gerror) { codec->clock_rate = 0; goto keyerror; } } else if (!strcmp ("id", keys[j])) { codec->id = g_key_file_get_integer (keyfile, groups[i], keys[j], &gerror); if (gerror) { codec->id = FS_CODEC_ID_ANY; goto keyerror; } if (codec->id < 0) codec->id = FS_CODEC_ID_DISABLE; } else if (!strcmp ("channels", keys[j])) { codec->channels = g_key_file_get_integer (keyfile, groups[i], keys[j], &gerror); if (gerror) { codec->channels = 0; goto keyerror; } } else { FsCodecParameter *param = g_slice_new (FsCodecParameter); param->name = g_strdup (keys[j]); param->value = g_key_file_get_string (keyfile, groups[i], keys[j], &gerror); if (gerror) { g_free (param->name); g_free (param->value); g_slice_free (FsCodecParameter, param); goto keyerror; } if (!param->name || !param->value) { g_free (param->name); g_free (param->value); g_slice_free (FsCodecParameter, param); } else { codec->optional_params = g_list_append (codec->optional_params, param); } } continue; keyerror: GST_WARNING ("Error reading key %s codec %s: %s", keys[j], groups[i], gerror->message); g_clear_error (&gerror); } codecs = g_list_append (codecs, codec); g_strfreev (keys); continue; next_codec: fs_codec_destroy (codec); g_strfreev (keys); } out: g_strfreev (groups); g_key_file_free (keyfile); return codecs; }
/* 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; } } }
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 void skype_audio_stream_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { SkypeAudioStreamPrivate *priv = SKYPE_AUDIO_STREAM (object)->priv; switch (property_id) { case PROP_BITRATE: skype_dynamic_properties_set (priv->properties, "bitrate", g_value_get_uint (value)); break; case PROP_CHANNEL_ID: priv->channel_id = g_value_get_uint (value); break; case PROP_CONVERSATION_ID: priv->conversation_id = g_value_get_uint (value); break; case PROP_CALL_MEMBER_ID: priv->call_member_id = g_value_get_uint (value); break; case PROP_PTIME: { FsCodec *codec = NULL; priv->ptime = g_value_get_uint (value); /* Trigger a codec update */ g_object_get (object, "codec", &codec, NULL); g_object_set (object, "codec", codec, NULL); fs_codec_destroy (codec); } break; case PROP_VOLUME: { priv->volume = g_value_get_double (value); if (priv->volume_id != NULL) { FsuFilterManager *manager; g_object_get (G_OBJECT (priv->stream), "filter-manager", &manager, NULL); if (manager == NULL) { g_warning ("Error fetching FsuFilterManager"); } else { FsuFilter *filter; filter = fsu_filter_manager_get_filter_by_id (manager, priv->volume_id); if (filter == NULL) { g_warning ("Error retrieving volume filter"); } else { g_object_set (filter, "volume", priv->volume, NULL); g_object_unref (filter); } g_object_unref (manager); } } } break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } }