# HG changeset patch # User Mike Ruprecht # Date 1220581095 0 # Node ID 5a774d0817d808211989cb612c51bccddb79b134 # Parent ef161c8f14dfb5ecbe4f6faab8be1505408be85e Wait for Farsight 2's codecs-ready property to be TRUE before using codecs. This will make codecs that need extra configuration, such as THEORA and H264, work consistently. diff -r ef161c8f14df -r 5a774d0817d8 libpurple/media.c --- a/libpurple/media.c Tue Sep 02 08:04:04 2008 +0000 +++ b/libpurple/media.c Fri Sep 05 02:18:15 2008 +0000 @@ -106,6 +106,7 @@ NEW_CANDIDATE, CANDIDATES_PREPARED, CANDIDATE_PAIR, + CODECS_READY, LAST_SIGNAL }; static guint purple_media_signals[LAST_SIGNAL] = {0}; @@ -215,6 +216,10 @@ G_SIGNAL_RUN_LAST, 0, NULL, NULL, purple_smarshal_VOID__BOXED_BOXED, G_TYPE_NONE, 2, FS_TYPE_CANDIDATE, FS_TYPE_CANDIDATE); + purple_media_signals[CODECS_READY] = g_signal_new("codecs-ready", G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, 0, NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, G_TYPE_STRING); g_type_class_add_private(klass, sizeof(PurpleMediaPrivate)); } @@ -663,6 +668,18 @@ } else if (gst_structure_has_name(msg->structure, "farsight-codecs-changed")) { + GList *sessions = g_hash_table_get_values(PURPLE_MEDIA(media)->priv->sessions); + FsSession *fssession = g_value_get_object(gst_structure_get_value(msg->structure, "session")); + for (; sessions; sessions = g_list_delete_link(sessions, sessions)) { + PurpleMediaSession *session = sessions->data; + if (session->session == fssession) { + g_signal_emit(session->media, + purple_media_signals[CODECS_READY], + 0, &session->id); + g_list_free(sessions); + break; + } + } } break; } @@ -880,7 +897,7 @@ src = gst_element_factory_make(video_plugin, "purplevideosource"); gst_bin_add(GST_BIN(*sendbin), src); - tee = gst_element_factory_make("tee", NULL); + tee = gst_element_factory_make("tee", "purplevideosrctee"); gst_bin_add(GST_BIN(*sendbin), tee); gst_element_link(src, tee); @@ -893,13 +910,14 @@ g_object_set (G_OBJECT(src), "is-live", TRUE, NULL); } - pad = gst_element_get_pad(queue, "src"); + pad = gst_element_get_static_pad(queue, "src"); ghost = gst_ghost_pad_new("ghostsrc", pad); + gst_object_unref(pad); gst_element_add_pad(*sendbin, ghost); - queue = gst_element_factory_make("queue", NULL); + queue = gst_element_factory_make("queue", "purplelocalvideoqueue"); gst_bin_add(GST_BIN(*sendbin), queue); - gst_element_link(tee, queue); + /* The queue is linked later, when the local video is ready to be shown */ local_sink = gst_element_factory_make("autovideosink", "purplelocalvideosink"); gst_bin_add(GST_BIN(*sendbin), local_sink); @@ -1316,6 +1334,15 @@ return TRUE; } +gboolean +purple_media_codecs_ready(PurpleMedia *media, const gchar *sess_id) +{ + PurpleMediaSession *session = purple_media_get_session(media, sess_id); + gboolean ret; + g_object_get(session->session, "codecs-ready", &ret, NULL); + return ret; +} + void purple_media_mute(PurpleMedia *media, gboolean active) { GList *sessions = g_hash_table_get_values(media->priv->sessions); diff -r ef161c8f14df -r 5a774d0817d8 libpurple/media.h --- a/libpurple/media.h Tue Sep 02 08:04:04 2008 +0000 +++ b/libpurple/media.h Fri Sep 05 02:18:15 2008 +0000 @@ -472,6 +472,16 @@ gboolean purple_media_set_send_codec(PurpleMedia *media, const gchar *sess_id, FsCodec *codec); /** + * Gets whether a session's codecs are ready to be used. + * + * @param media The media object to find the session in. + * @param sess_id The session id of the session to check. + * + * @return @c TRUE The codecs are ready, or @c FALSE otherwise. + */ +gboolean purple_media_codecs_ready(PurpleMedia *media, const gchar *sess_id); + +/** * Mutes or unmutes all the audio local audio sources. * * @param media The media object to mute or unmute diff -r ef161c8f14df -r 5a774d0817d8 libpurple/protocols/jabber/jingle.c --- a/libpurple/protocols/jabber/jingle.c Tue Sep 02 08:04:04 2008 +0000 +++ b/libpurple/protocols/jabber/jingle.c Fri Sep 05 02:18:15 2008 +0000 @@ -814,6 +814,21 @@ jabber_iq_send(result); } #endif + +static void +jabber_jingle_session_accept(JingleSession *session) +{ + if (jabber_jingle_session_get_state(session) == ACCEPTED && + purple_media_candidates_prepared( + jabber_jingle_session_get_media(session), + jabber_jingle_session_get_remote_jid(session))) { + jabber_iq_send(jabber_jingle_session_create_session_accept(session)); + + purple_debug_info("jingle", "Sent session accept.\n"); + jabber_jingle_session_set_state(session, ACTIVE); + } +} + static void jabber_jingle_session_send_session_accept(JingleSession *session) { @@ -843,13 +858,8 @@ jabber_jingle_session_content_get_name(jsc)))); } - if (purple_media_candidates_prepared(media, remote_jid)) { - jabber_iq_send(jabber_jingle_session_create_session_accept(session)); - - purple_debug_info("jingle", "Sent session accept.\n"); - jabber_jingle_session_set_state(session, ACTIVE); - } else - jabber_jingle_session_set_state(session, ACCEPTED); + jabber_jingle_session_set_state(session, ACCEPTED); + jabber_jingle_session_accept(session); } static void @@ -942,14 +952,90 @@ FsCandidate *remote_candidate, JingleSession *session) { - if (!jabber_jingle_session_is_initiator(session) && - jabber_jingle_session_get_state(session) == ACCEPTED && - purple_media_candidates_prepared(media, - jabber_jingle_session_get_remote_jid(session))) { - jabber_iq_send(jabber_jingle_session_create_session_accept(session)); - - purple_debug_info("jingle", "Sent session accept.\n"); - jabber_jingle_session_set_state(session, ACTIVE); + if (!jabber_jingle_session_is_initiator(session)) { + jabber_jingle_session_accept(session); + } +} + +static void +jabber_jingle_session_initiate_result_cb(JabberStream *js, xmlnode *packet, gpointer data) +{ + const char *from = xmlnode_get_attrib(packet, "from"); + JingleSession *session = jabber_jingle_session_find_by_jid(js, from); + PurpleMedia *media; + GList *contents; + + if (!session) { + /* respond with an error here */ + purple_debug_error("jingle", "Received session-initiate ack" + " to nonexistent session\n"); + return; + } + + media = session->media; + + if (!strcmp(xmlnode_get_attrib(packet, "type"), "error")) { + purple_media_got_hangup(media); + return; + } + + /* catch errors */ + if (xmlnode_get_child(packet, "error")) { + purple_media_got_hangup(media); + return; + } + + /* create transport-info packages */ + contents = jabber_jingle_session_get_contents(session); + for (; contents; contents = contents->next) { + JingleSessionContent *jsc = contents->data; + GList *candidates = purple_media_get_local_candidates( + jabber_jingle_session_get_media(session), + jabber_jingle_session_content_get_name(jsc), + jabber_jingle_session_get_remote_jid(session)); + purple_debug_info("jingle", + "jabber_session_candidates_prepared: %d candidates\n", + g_list_length(candidates)); + for (; candidates; candidates = candidates->next) { + FsCandidate *candidate = candidates->data; + JabberIq *result = jabber_jingle_session_create_transport_info(jsc, + candidate); + jabber_iq_send(result); + } + fs_candidate_list_destroy(candidates); + } + + jabber_jingle_session_set_state(session, GOT_ACK); +} + +static void +jabber_jingle_session_codecs_ready_cb(PurpleMedia *media, + const gchar *sess_id, + JingleSession *session) +{ + GList *contents = jabber_jingle_session_get_contents(session); + for (; contents; contents = g_list_delete_link(contents, contents)) { + JingleSessionContent *jsc = contents->data; + if (!purple_media_codecs_ready(media, + jabber_jingle_session_content_get_name(jsc))) { + break; + } + } + + if (contents != NULL) + g_list_free(contents); + else if (jabber_jingle_session_is_initiator(session) + && jabber_jingle_session_get_state(session) == PENDING) { + JabberIq *request; + + /* create request */ + request = jabber_jingle_session_create_session_initiate(session); + jabber_iq_set_callback(request, jabber_jingle_session_initiate_result_cb, NULL); + + /* send request to other part */ + jabber_iq_send(request); + } else { + jabber_jingle_session_accept(session); } } @@ -1027,69 +1113,19 @@ G_CALLBACK(jabber_jingle_session_new_candidate_cb), session); g_signal_connect(G_OBJECT(media), "candidate-pair", G_CALLBACK(jabber_jingle_session_candidate_pair_established_cb), session); + g_signal_connect(G_OBJECT(media), "codecs-ready", + G_CALLBACK(jabber_jingle_session_codecs_ready_cb), session); purple_media_ready(media); return TRUE; } -static void -jabber_jingle_session_initiate_result_cb(JabberStream *js, xmlnode *packet, gpointer data) -{ - const char *from = xmlnode_get_attrib(packet, "from"); - JingleSession *session = jabber_jingle_session_find_by_jid(js, from); - PurpleMedia *media; - GList *contents; - - if (!session) { - /* respond with an error here */ - purple_debug_error("jingle", "Received session-initiate ack" - " to nonexistent session\n"); - return; - } - - media = session->media; - - if (!strcmp(xmlnode_get_attrib(packet, "type"), "error")) { - purple_media_got_hangup(media); - return; - } - - /* catch errors */ - if (xmlnode_get_child(packet, "error")) { - purple_media_got_hangup(media); - return; - } - - /* create transport-info packages */ - contents = jabber_jingle_session_get_contents(session); - for (; contents; contents = contents->next) { - JingleSessionContent *jsc = contents->data; - GList *candidates = purple_media_get_local_candidates( - jabber_jingle_session_get_media(session), - jabber_jingle_session_content_get_name(jsc), - jabber_jingle_session_get_remote_jid(session)); - purple_debug_info("jingle", - "jabber_session_candidates_prepared: %d candidates\n", - g_list_length(candidates)); - for (; candidates; candidates = candidates->next) { - FsCandidate *candidate = candidates->data; - JabberIq *result = jabber_jingle_session_create_transport_info(jsc, - candidate); - jabber_iq_send(result); - } - fs_candidate_list_destroy(candidates); - } - - jabber_jingle_session_set_state(session, GOT_ACK); -} - PurpleMedia * jabber_jingle_session_initiate_media(JabberStream *js, const char *who, PurpleMediaSessionType type) { /* create content negotiation */ - JabberIq *request; JingleSession *session; JabberBuddy *jb; JabberBuddyResource *jbr; @@ -1129,13 +1165,6 @@ g_free(jid); g_free(me); - /* create request */ - request = jabber_jingle_session_create_session_initiate(session); - jabber_iq_set_callback(request, jabber_jingle_session_initiate_result_cb, NULL); - - /* send request to other part */ - jabber_iq_send(request); - return session->media; } diff -r ef161c8f14df -r 5a774d0817d8 pidgin/gtkmedia.c --- a/pidgin/gtkmedia.c Tue Sep 02 08:04:04 2008 +0000 +++ b/pidgin/gtkmedia.c Fri Sep 05 02:18:15 2008 +0000 @@ -314,18 +314,18 @@ if (!audiosendbin && (type & PURPLE_MEDIA_SEND_AUDIO)) { purple_media_audio_init_src(&audiosendbin, &audiosendlevel); purple_media_set_src(media, sessions->data, audiosendbin); - gst_element_set_state(audiosendbin, GST_STATE_READY); + gst_element_set_state(audiosendbin, GST_STATE_PLAYING); } if (!audiorecvbin && (type & PURPLE_MEDIA_RECV_AUDIO)) { purple_media_audio_init_recv(&audiorecvbin, &audiorecvlevel); purple_media_set_sink(media, sessions->data, audiorecvbin); gst_element_set_state(audiorecvbin, GST_STATE_READY); } - } else if (purple_media_get_session_type(media, sessions->data) & PURPLE_MEDIA_VIDEO) { + } else if (type & PURPLE_MEDIA_VIDEO) { if (!videosendbin && (type & PURPLE_MEDIA_SEND_VIDEO)) { purple_media_video_init_src(&videosendbin); purple_media_set_src(media, sessions->data, videosendbin); - gst_element_set_state(videosendbin, GST_STATE_READY); + gst_element_set_state(videosendbin, GST_STATE_PLAYING); } if (!videorecvbin && (type & PURPLE_MEDIA_RECV_VIDEO)) { purple_media_video_init_recv(&videorecvbin); @@ -401,6 +401,7 @@ if (videosendbin) { GtkWidget *aspect; GtkWidget *local_video; + GstElement *tee, *queue; aspect = gtk_aspect_frame_new(NULL, 0.5, 0.5, 4.0/3.0, FALSE); gtk_frame_set_shadow_type(GTK_FRAME(aspect), GTK_SHADOW_IN); @@ -414,7 +415,11 @@ gtkmedia->priv->local_video = local_video; - gst_element_set_state(videosendbin, GST_STATE_PLAYING); + tee = gst_bin_get_by_name(GST_BIN(videosendbin), "purplevideosrctee"); + queue = gst_bin_get_by_name(GST_BIN(videosendbin), "purplelocalvideoqueue"); + gst_element_link(tee, queue); + gst_object_unref(tee); + gst_object_unref(queue); } if (audiorecvbin) { @@ -435,7 +440,6 @@ gtk_box_pack_end(GTK_BOX(send_widget), gtkmedia->priv->send_progress, FALSE, FALSE, 0); gtk_widget_show(gtkmedia->priv->send_progress); - gst_element_set_state(audiosendbin, GST_STATE_PLAYING); gtk_widget_show(gtkmedia->priv->mute); }