/** * fs_rtp_stream_set_negotiated_codecs_unlock * @stream: a #FsRtpStream * @codecs: The #GList of #FsCodec to set for the negotiated-codecs property * * This function sets the value of the FsStream:negotiated-codecs property. * Unlike most other functions in this element, it TAKES the reference to the * codecs, so you have to give it its own copy. * * You must enter this function with the session lock held and it will release * it. */ void fs_rtp_stream_set_negotiated_codecs_unlock (FsRtpStream *stream, GList *codecs) { FsRtpSession *session = fs_rtp_stream_get_session (stream, NULL); if (!session) return; if (fs_codec_list_are_equal (stream->negotiated_codecs, codecs)) { fs_codec_list_destroy (codecs); FS_RTP_SESSION_UNLOCK (session); g_object_unref (session); return; } if (stream->negotiated_codecs) fs_codec_list_destroy (stream->negotiated_codecs); stream->negotiated_codecs = codecs; FS_RTP_SESSION_UNLOCK (session); g_object_notify (G_OBJECT (stream), "negotiated-codecs"); g_object_unref (session); }
static void set_initial_codecs ( struct SimpleTestConference *from, struct SimpleTestStream *to) { GList *codecs = NULL; GList *filtered_codecs = NULL; GList *item = NULL; GList *rcodecs2 = NULL; GError *error = NULL; g_object_get (from->session, "codecs", &codecs, NULL); ts_fail_if (codecs == NULL, "Could not get the codecs"); for (item = g_list_first (codecs); item; item = g_list_next (item)) { FsCodec *codec = item->data; if (codec->id == 0 || codec->id == 8) filtered_codecs = g_list_append (filtered_codecs, codec); } ts_fail_if (filtered_codecs == NULL, "PCMA and PCMU are not in the codecs" " you must install gst-plugins-good"); g_debug ("Setting initial remote codecs on %d:%d from %d", to->dat->id, to->target->id, from->id); if (!fs_stream_set_remote_codecs (to->stream, filtered_codecs, &error)) { if (error) ts_fail ("Could not set the remote codecs on stream %d:%d (%d): %s", to->dat->id, to->target->id, error->code, error->message); else ts_fail ("Could not set the remote codecs on stream %d" " and we DID not get a GError!!", to->target->id); } g_object_get (to->stream, "remote-codecs", &rcodecs2, NULL); ts_fail_unless (_compare_codec_lists (rcodecs2, filtered_codecs), "Can not get remote codecs correctly"); fs_codec_list_destroy (rcodecs2); if (select_last_codec) ts_fail_unless ( fs_session_set_send_codec (to->dat->session, g_list_last (filtered_codecs)->data, &error), "Error setting the send codec to the last codec: %s", error ? error->message : "No GError"); g_clear_error (&error); g_list_free (filtered_codecs); fs_codec_list_destroy (codecs); }
static void _negotiated_codecs_notify (GObject *object, GParamSpec *paramspec, gpointer user_data) { struct SimpleTestConference *dat = user_data; FsSession *session = FS_SESSION (object); GList *codecs = NULL; GError *error = NULL; GList *item = NULL; g_debug ("%d: New negotiated codecs", dat->id); ts_fail_if (session != dat->session, "Got signal from the wrong object"); g_object_get (dat->session, "codecs", &codecs, NULL); ts_fail_if (codecs == NULL, "Could not get the negotiated codecs"); /* We have to find the stream from the target that points back to us */ for (item = g_list_first (dat->streams); item; item = g_list_next (item)) { struct SimpleTestStream *st = item->data; struct SimpleTestStream *st2 = find_pointback_stream (st->target, dat); GList *rcodecs2; g_debug ("Setting negotiated remote codecs on %d:%d from %d",st2->dat->id, st2->target->id, dat->id); if (!fs_stream_set_remote_codecs (st2->stream, codecs, &error)) { if (error) ts_fail ("Could not set the remote codecs on stream %d:%d (%d): %s", st2->dat->id, st2->target->id, error->code, error->message); else ts_fail ("Could not set the remote codecs on stream %d:%d" " and we DID not get a GError!!", st2->dat->id, st2->target->id); } g_object_get (st2->stream, "remote-codecs", &rcodecs2, NULL); ts_fail_unless (_compare_codec_lists (rcodecs2, codecs), "Can not get remote codecs correctly"); fs_codec_list_destroy (rcodecs2); if (select_last_codec) ts_fail_unless ( fs_session_set_send_codec (st2->dat->session, g_list_last (codecs)->data, &error), "Error setting the send codec to the last codec: %s", error ? error->message : "No GError"); g_clear_error (&error); break; } fs_codec_list_destroy (codecs); }
static void fs_rtp_stream_finalize (GObject *object) { FsRtpStream *self = FS_RTP_STREAM (object); fs_codec_list_destroy (self->remote_codecs); fs_codec_list_destroy (self->negotiated_codecs); g_mutex_clear (&self->priv->mutex); G_OBJECT_CLASS (fs_rtp_stream_parent_class)->finalize (object); }
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 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 set_codecs (struct SimpleTestConference *dat, FsStream *stream) { GList *codecs = NULL; GList *filtered_codecs = NULL; GList *item = NULL; GError *error = NULL; FsCodec *dtmf_codec = NULL; g_object_get (dat->session, "codecs", &codecs, NULL); ts_fail_if (codecs == NULL, "Could not get the local codecs"); for (item = g_list_first (codecs); item; item = g_list_next (item)) { FsCodec *codec = item->data; if (codec->id == 0 || codec->id == 8) { filtered_codecs = g_list_append (filtered_codecs, codec); } else if (codec->clock_rate == 8000 && !g_ascii_strcasecmp (codec->encoding_name, "telephone-event")) { ts_fail_unless (dtmf_codec == NULL, "More than one copy of telephone-event"); dtmf_codec = codec; filtered_codecs = g_list_append (filtered_codecs, codec); } } ts_fail_if (filtered_codecs == NULL, "PCMA and PCMU are not in the codecs" " you must install gst-plugins-good"); ts_fail_unless (dtmf_codec != NULL); dtmf_codec->id = dtmf_id; if (!fs_stream_set_remote_codecs (stream, filtered_codecs, &error)) { if (error) ts_fail ("Could not set the remote codecs on stream (%d): %s", error->code, error->message); else ts_fail ("Could not set the remote codecs on stream" " and we did NOT get a GError!!"); } g_list_free (filtered_codecs); fs_codec_list_destroy (codecs); }
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 TestSession* add_audio_session (GstElement *pipeline, FsConference *conf, guint id, FsParticipant *part, gchar *send_socket, gchar *recv_socket) { TestSession *ses = g_slice_new0 (TestSession); GError *error = NULL; GstPad *pad = NULL, *pad2 = NULL; GstElement *src = NULL; GList *cands = NULL; GParameter param = {0}; gboolean res; FsCandidate *cand; GList *codecs = NULL; ses->send_socket = send_socket; ses->recv_socket = recv_socket; ses->session = fs_conference_new_session (conf, FS_MEDIA_TYPE_AUDIO, &error); print_error (error); g_assert (ses->session); g_object_get (ses->session, "sink-pad", &pad, NULL); if (g_getenv ("AUDIOSRC")) src = gst_parse_bin_from_description (g_getenv ("AUDIOSRC"), TRUE, &error); else src = gst_parse_bin_from_description (DEFAULT_AUDIOSRC, TRUE, &error); print_error (error); g_assert (src); g_assert (gst_bin_add (GST_BIN (pipeline), src)); pad2 = gst_element_get_static_pad (src, "src"); g_assert (pad2); g_assert (GST_PAD_LINK_SUCCESSFUL (gst_pad_link (pad2, pad))); gst_object_unref (pad2); gst_object_unref (pad); ses->stream = fs_session_new_stream (ses->session, part, FS_DIRECTION_BOTH, &error); print_error (error); g_assert (ses->stream); cand = fs_candidate_new ("", FS_COMPONENT_RTP, FS_CANDIDATE_TYPE_HOST, FS_NETWORK_PROTOCOL_UDP, send_socket, 0); cands = g_list_prepend (NULL, cand); param.name = "preferred-local-candidates"; g_value_init (¶m.value, FS_TYPE_CANDIDATE_LIST); g_value_take_boxed (¶m.value, cands); res = fs_stream_set_transmitter (ses->stream, "shm", ¶m, 1, &error); print_error (error); g_value_unset (¶m.value); g_signal_connect (ses->stream, "src-pad-added", G_CALLBACK (src_pad_added_cb), pipeline); codecs = g_list_prepend (NULL, fs_codec_new (FS_CODEC_ID_ANY, "PCMA", FS_MEDIA_TYPE_AUDIO, 0)); codecs = g_list_prepend (codecs, fs_codec_new (FS_CODEC_ID_ANY, "PCMU", FS_MEDIA_TYPE_AUDIO, 0)); res = fs_session_set_codec_preferences (ses->session, codecs, &error); print_error (error); fs_codec_list_destroy (codecs); g_object_get (ses->session, "codecs-without-config", &codecs, NULL); res = fs_stream_set_remote_codecs (ses->stream, codecs, &error); print_error (error); g_assert (res); return ses; }
static void _handoff_handler (GstElement *element, GstBuffer *buffer, GstPad *pad, gpointer user_data) { struct SimpleTestStream *st = user_data; int i; gboolean stop = TRUE; GList *codecs = NULL; g_object_get (st->dat->session, "codecs", &codecs, NULL); ts_fail_if (codecs == NULL, "Could not get codecs"); if (st->flags & WAITING_ON_LAST_CODEC) { if (fs_codec_are_equal ( g_list_last (codecs)->data, g_object_get_data (G_OBJECT (element), "codec"))) { st->flags &= ~WAITING_ON_LAST_CODEC; st->flags |= SHOULD_BE_LAST_CODEC; max_buffer_count += st->buffer_count; g_debug ("We HAVE last codec"); } else { gchar *str = fs_codec_to_string ( g_object_get_data (G_OBJECT (element), "codec")); gchar *str2 = fs_codec_to_string (g_list_last (codecs)->data); g_debug ("not yet the last codec, skipping (we have %s, we want %s)", str, str2); g_free (str); g_free (str2); fs_codec_list_destroy (codecs); return; } } if (select_last_codec || st->flags & SHOULD_BE_LAST_CODEC) ts_fail_unless ( fs_codec_are_equal ( g_list_last (codecs)->data, g_object_get_data (G_OBJECT (element), "codec")), "The handoff handler got a buffer from the wrong codec (last)"); else ts_fail_unless ( fs_codec_are_equal ( g_list_first (codecs)->data, g_object_get_data (G_OBJECT (element), "codec")), "The handoff handler got a buffer from the wrong codec"); fs_codec_list_destroy (codecs); st->buffer_count++; if (st->buffer_count % 10 == 0) g_debug ("%d:%d: Buffer %d", st->dat->id, st->target->id, st->buffer_count); /* ts_fail_if (dat->buffer_count > max_buffer_count, "Too many buffers %d > max_buffer_count", dat->buffer_count); */ for (i = 0; i < count && !stop ; i++) { GList *item; for (item = g_list_first (dats[i]->streams); item; item = g_list_next (item)) { struct SimpleTestStream *st2 = item->data; if (st2->buffer_count < max_buffer_count) { stop = FALSE; break; } } } if (stop) { if (reset_to_last_codec && !(st->flags & HAS_BEEN_RESET)) { GError *error = NULL; GList *nego_codecs = NULL; gchar *str = NULL; g_object_get (st->target->session, "codecs", &nego_codecs, NULL); ts_fail_if (nego_codecs == NULL, "No codecs"); ts_fail_if (g_list_length (nego_codecs) < 2, "Only one negotiated codec"); str = fs_codec_to_string (g_list_last (nego_codecs)->data); g_debug ("Setting codec to: %s", str); g_free (str); ts_fail_unless (fs_session_set_send_codec (st->target->session, g_list_last (nego_codecs)->data, &error), "Could not set the send codec: %s", error ? error->message : "NO GError!!!"); g_clear_error (&error); fs_codec_list_destroy (nego_codecs); st->flags |= HAS_BEEN_RESET | WAITING_ON_LAST_CODEC; g_debug ("RESET TO LAST CODEC"); } else { g_main_loop_quit (loop); } } }
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); }
/** * fs_rtp_stream_set_remote_codecs: * @stream: an #FsStream * @remote_codecs: a #GList of #FsCodec representing the remote codecs * @error: location of a #GError, or NULL if no error occured * * This function will set the list of remote codecs for this stream. If * the given remote codecs couldn't be negotiated with the list of local * codecs or already negotiated codecs for the corresponding #FsSession, @error * will be set and %FALSE will be returned. The @remote_codecs list will be * copied so it must be free'd using fs_codec_list_destroy() when done. * * Returns: %FALSE if the remote codecs couldn't be set. */ static gboolean fs_rtp_stream_set_remote_codecs (FsStream *stream, GList *remote_codecs, GError **error) { FsRtpStream *self = FS_RTP_STREAM (stream); GList *item = NULL; FsMediaType media_type; FsRtpSession *session = fs_rtp_stream_get_session (self, error); if (!session) return FALSE; if (remote_codecs == NULL) { g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS, "You can not set NULL remote codecs"); goto error; } g_object_get (session, "media-type", &media_type, NULL); for (item = g_list_first (remote_codecs); item; item = g_list_next (item)) { FsCodec *codec = item->data; if (!codec->encoding_name) { g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS, "The codec must have an encoding name"); goto error; } if (codec->id < 0 || codec->id > 128) { g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS, "The codec id must be between 0 ans 128 for %s", codec->encoding_name); goto error; } if (codec->media_type != media_type) { g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS, "The media type for codec %s is not %s", codec->encoding_name, fs_media_type_to_string (media_type)); goto error; } } if (self->priv->new_remote_codecs_cb (self, remote_codecs, error, self->priv->user_data_for_cb)) { gboolean is_new = TRUE; FS_RTP_SESSION_LOCK (session); if (self->remote_codecs) { is_new = !fs_codec_list_are_equal (self->remote_codecs, remote_codecs); fs_codec_list_destroy (self->remote_codecs); } self->remote_codecs = fs_codec_list_copy (remote_codecs); FS_RTP_SESSION_UNLOCK (session); if (is_new) g_object_notify (G_OBJECT (stream), "remote-codecs"); } else { goto error; } g_object_unref (session); return TRUE; error: g_object_unref (session); return FALSE; }
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; }