pidgin.vv.yahoo.voice: 77a5acca: Add support to receive a voice call. Thi...
maiku at pidgin.im
maiku at pidgin.im
Fri Aug 28 23:05:21 EDT 2009
-----------------------------------------------------------------
Revision: 77a5accab64083fba4a6d68d1275b135288234a1
Ancestor: bad95bf79c54addda84101885ba9fc4b2f17c12d
Author: maiku at pidgin.im
Date: 2009-08-29T02:58:21
Branch: im.pidgin.pidgin.vv.yahoo.voice
URL: http://d.pidgin.im/viewmtn/revision/info/77a5accab64083fba4a6d68d1275b135288234a1
Modified files:
libpurple/protocols/yahoo/yahoo_sip.c
ChangeLog:
Add support to receive a voice call. This requires an uncommited Yahoo
compatibility mode to both Farsight2's nice transmitter plugin and libnice.
For some reason SPEEX/8000 has poor audio quality and SPEEX/16000 isn't
received at all. PCMU, however, works perfectly. The SPEEX modes may need
to be ignored if not resolved.
-------------- next part --------------
============================================================
--- libpurple/protocols/yahoo/yahoo_sip.c e7371b3954a1b79de94601ab7b89f2bae32a39dc
+++ libpurple/protocols/yahoo/yahoo_sip.c 73fde3dbf78211630f110ec6c86fbecf2bd3ba9d
@@ -26,6 +26,7 @@
#include "cipher.h"
#include "debug.h"
+#include "mediamanager.h"
#include "yahoo_sip.h"
#include "libymsg.h"
@@ -33,7 +34,9 @@
#include <glib.h>
#include <sofia-sip/nua.h>
#include <sofia-sip/su_glib.h>
+#include <sofia-sip/soa.h>
#include <sofia-sip/sip_header.h>
+#include <sofia-sip/sdp.h>
/* This is the y64 alphabet... it's like base64, but has a . and a _ */
static const char base64digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._";
@@ -66,6 +69,11 @@ static void to_y64(char *out, const unsi
*out = '\0';
}
+static void yahoo_sip_candidates_prepared_cb(PurpleMedia *media,
+ gchar *sid, gchar *name, nua_handle_t *nh);
+static void yahoo_sip_codecs_changed_cb(PurpleMedia *media,
+ gchar *sid, nua_handle_t *nh);
+
static gboolean
send_yahooref(gpointer nh)
{
@@ -74,6 +82,131 @@ static void
}
static void
+yahoo_sip_send_response(PurpleMedia *media, nua_handle_t *nh)
+{
+ const sip_to_t *remote = nua_handle_remote(nh);
+ GList *codecs, *candidates;
+ gchar **codec_strs, **candidate_strs,
+ *codec_str, *candidate_str, *sdp_str;
+ guint port = 0;
+ guint i = 0;
+
+ codecs = purple_media_get_codecs(media, "yahoo-voice");
+ codec_strs = g_new0(gchar*, g_list_length(codecs) + 1);
+
+ for (; codecs; codecs = g_list_delete_link(codecs, codecs)) {
+ PurpleMediaCodec *codec = codecs->data;
+ gchar *encoding_name =
+ purple_media_codec_get_encoding_name(codec);
+ codec_strs[i] = g_strdup_printf("a=rtpmap:%d %s/%d\r\n",
+ purple_media_codec_get_id(codec), encoding_name,
+ purple_media_codec_get_clock_rate(codec));
+ g_free(encoding_name);
+ ++i;
+ }
+ codec_str = g_strjoinv(NULL, codec_strs);
+ g_strfreev(codec_strs);
+ purple_debug_info("yahoo", "local codecs:\n%s", codec_str);
+
+ candidates = purple_media_get_local_candidates(media,
+ "yahoo-voice", remote->a_display);
+ candidate_strs = g_new0(gchar*, g_list_length(candidates) + 1);
+
+ if (candidates->data)
+ port = purple_media_candidate_get_port(candidates->data);
+
+ i = 0;
+ for (; candidates; candidates =
+ g_list_delete_link(candidates, candidates)) {
+ PurpleMediaCandidate *candidate = candidates->data;
+ gchar *ip = purple_media_candidate_get_ip(candidate);
+ PurpleMediaCandidateType type =
+ purple_media_candidate_get_candidate_type(candidate);
+ gchar *username = purple_media_candidate_get_username(candidate);
+ gchar *password = purple_media_candidate_get_password(candidate);
+ candidate_strs[i] = g_strdup_printf(
+ "a=candidate:%s %d %s %s 1 %s %d channel-type %d\r\n", username,
+ purple_media_candidate_get_component_id(candidate), password,
+ purple_media_candidate_get_protocol(candidate) ==
+ PURPLE_MEDIA_NETWORK_PROTOCOL_UDP ? "UDP" : "TCP",
+ ip, purple_media_candidate_get_port(candidate),
+ type == PURPLE_MEDIA_CANDIDATE_TYPE_HOST ? 1 : type ==
+ PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX ? 2 : type ==
+ PURPLE_MEDIA_CANDIDATE_TYPE_RELAY ? 3 : 0);
+ g_free(ip);
+ ++i;
+ }
+ candidate_str = g_strjoinv(NULL, candidate_strs);
+ g_strfreev(candidate_strs);
+ purple_debug_info("yahoo", "local candidates:\n%s", candidate_str);
+
+ sdp_str = g_strdup_printf("m=audio %d RTP/AVP 97 0 8 101 100\r"
+ "\n%s%sa=sendrecv\r\n", port, codec_str, candidate_str);
+ g_free(codec_str);
+ g_free(candidate_str);
+
+ nua_respond(nh, 200, "OK",
+ SOATAG_USER_SDP_STR(sdp_str),
+ TAG_END());
+ g_free(sdp_str);
+}
+
+static void
+yahoo_sip_ready(PurpleMedia *media, nua_handle_t *nh)
+{
+ purple_debug_info("yahoo", "sip ready\n");
+ if (purple_media_candidates_prepared(media, NULL, NULL) &&
+ purple_media_codecs_ready(media, NULL) &&
+ (purple_media_is_initiator(media, NULL, NULL) ||
+ purple_media_accepted(media, NULL, NULL))) {
+ if (purple_media_is_initiator(media, NULL, NULL)) {
+ /* send initiate */
+ } else {
+ yahoo_sip_send_response(media, nh);
+ }
+
+ g_signal_handlers_disconnect_by_func(G_OBJECT(media),
+ G_CALLBACK(yahoo_sip_candidates_prepared_cb),
+ nh);
+ g_signal_handlers_disconnect_by_func(G_OBJECT(media),
+ G_CALLBACK(yahoo_sip_codecs_changed_cb),
+ nh);
+ }
+}
+
+static void
+yahoo_sip_candidates_prepared_cb(PurpleMedia *media,
+ gchar *sid, gchar *name, nua_handle_t *nh)
+{
+ if (sid == NULL && name == NULL)
+ yahoo_sip_ready(media, nh);
+}
+
+static void
+yahoo_sip_codecs_changed_cb(PurpleMedia *media, gchar *sid, nua_handle_t *nh)
+{
+
+}
+
+static void
+yahoo_sip_state_changed_cb(PurpleMedia *media, PurpleMediaState state,
+ gchar *sid, gchar *name, nua_handle_t *nh)
+{
+
+}
+
+static void
+yahoo_sip_stream_info_cb(PurpleMedia *media, PurpleMediaInfoType type,
+ gchar *sid, gchar *name, gboolean local,
+ nua_handle_t *nh)
+{
+ if (type == PURPLE_MEDIA_INFO_ACCEPT && local == TRUE &&
+ sid == NULL && name == NULL) {
+ yahoo_sip_ready(media, nh);
+ }
+}
+
+static void
event_callback(nua_event_t event, int status, const gchar *phrase, nua_t *nua,
nua_magic_t *magic, nua_handle_t *nh, nua_hmagic_t *hmagic,
const sip_t *sip, tagi_t tags[])
@@ -148,6 +281,138 @@ event_callback(nua_event_t event, int st
nua_shutdown(nua);
} else if (event == nua_r_shutdown && status == 200) {
nua_destroy(nua);
+ } else if (event == nua_i_invite) {
+ PurpleMedia *media;
+ PurpleAccount *account = magic;
+ const sip_to_t *remote = nua_handle_remote(nh);
+ GParameter param;
+ purple_debug_info("yahoo", "INVITE status %d display: %s\n",
+ status, remote->a_display);
+ nua_respond(nh, 180, "Ringing", TAG_END());
+ media = purple_media_manager_create_media(
+ purple_media_manager_get(),
+ account, "fsrtpconference",
+ remote->a_display, FALSE);
+
+ if (!media) {
+ purple_debug_error("yahoo",
+ "Couldn't create media session\n");
+ return;
+ }
+
+ purple_media_set_prpl_data(media, nh);
+
+ /* connect callbacks */
+ g_signal_connect(G_OBJECT(media), "candidates-prepared",
+ G_CALLBACK(yahoo_sip_candidates_prepared_cb), nh);
+ g_signal_connect(G_OBJECT(media), "codecs-changed",
+ G_CALLBACK(yahoo_sip_codecs_changed_cb), nh);
+ g_signal_connect(G_OBJECT(media), "state-changed",
+ G_CALLBACK(yahoo_sip_state_changed_cb), nh);
+ g_signal_connect(G_OBJECT(media), "stream-info",
+ G_CALLBACK(yahoo_sip_stream_info_cb), nh);
+
+ param.name = "compatibility-mode";
+ param.value.g_type = 0;
+ g_value_init(¶m.value, G_TYPE_UINT);
+ g_value_set_uint(¶m.value, 4); /* NICE_COMPATIBILITY_YAHOO */
+ purple_media_add_stream(media, "yahoo-voice", remote->a_display,
+ PURPLE_MEDIA_AUDIO, FALSE, "nice", 1, ¶m);
+ } else if (event == nua_i_state && status == 100) {
+ /*
+ * This has a phrase of "Trying" if not,
+ * I need to add the check back.
+ */
+ PurpleAccount *account = magic;
+ const sdp_session_t *sdp_session = NULL;
+ const sip_to_t *remote = nua_handle_remote(nh);
+ sdp_media_t *sdp_media;
+ sdp_rtpmap_t *codec_iter;
+ sdp_attribute_t *conn_iter;
+ GList *codecs = NULL, *candidates = NULL;
+ PurpleMedia *media = NULL;
+ GList *iter;
+
+ tl_gets(tags, SOATAG_REMOTE_SDP_REF(sdp_session), TAG_END());
+ if (!sdp_session) {
+ purple_debug_error("yahoo", "Couldn't retrieve "
+ "remote SDP from invitation.\n");
+ return;
+ }
+ sdp_media = sdp_session->sdp_media;
+ codec_iter = sdp_media->m_rtpmaps;
+ conn_iter = sdp_media->m_attributes;
+
+ /*
+ * Find PurpleMedia associated with this handle.
+ * Need to use a structure to hold this information.
+ * Then this won't be necessary.
+ */
+ iter = purple_media_manager_get_media_by_account(
+ purple_media_manager_get(), account);
+ for (; iter; iter = g_list_delete_link(iter, iter)) {
+ nua_handle_t *nh_media =
+ purple_media_get_prpl_data(iter->data);
+ if (nh_media == nh) {
+ media = iter->data;
+ break;
+ }
+ }
+ g_list_free(iter);
+
+ if (!media) {
+ purple_debug_error("yahoo", "Couldn't find media "
+ "session associated with this SIP call.\n");
+ return;
+ }
+
+ for (; codec_iter; codec_iter = codec_iter->rm_next) {
+ PurpleMediaCodec *codec = purple_media_codec_new(
+ codec_iter->rm_pt, codec_iter->rm_encoding,
+ PURPLE_MEDIA_AUDIO, codec_iter->rm_rate);
+ /* XXX: Need to add FsCodec parameters if they exist */
+ purple_debug_info("yahoo", "codec: a=rtpmap:%d %s/%lu"
+ " rm_params: %s rm_fmtp: %s\n",
+ codec_iter->rm_pt, codec_iter->rm_encoding,
+ codec_iter->rm_rate, codec_iter->rm_params,
+ codec_iter->rm_fmtp);
+ codecs = g_list_append(codecs, codec);
+ }
+ purple_media_set_remote_codecs(media, "yahoo-voice",
+ remote->a_display, codecs);
+ purple_media_codec_list_free(codecs);
+
+ for (; conn_iter; conn_iter = conn_iter->a_next) {
+ PurpleMediaCandidate *candidate;
+ gchar **c;
+ guint type;
+ if (strcmp(conn_iter->a_name, "candidate"))
+ continue;
+ c = g_strsplit(conn_iter->a_value, " ", 0);
+ purple_debug_info("yahoo", "candidate ?: %s "
+ "component-id: %s ?: %s network-type:"
+ " %s ?: %s ip: %s port: %s "
+ "channel-type: %s\n", c[0], c[1],
+ c[2], c[3], c[4], c[5], c[6], c[8]);
+ type = atoi(c[8]);
+ candidate= purple_media_candidate_new(c[0], atoi(c[1]), type == 1 ?
+ PURPLE_MEDIA_CANDIDATE_TYPE_HOST : type == 2 ?
+ PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX :
+ PURPLE_MEDIA_CANDIDATE_TYPE_RELAY,
+ !strcmp(c[3], "UDP") ?
+ PURPLE_MEDIA_NETWORK_PROTOCOL_UDP :
+ PURPLE_MEDIA_NETWORK_PROTOCOL_TCP,
+ c[5], atoi(c[6]));
+ g_object_set(G_OBJECT(candidate), "username",
+ c[0], "password", c[2], NULL);
+ purple_debug_info("yahoo", "candidate a_value: %s\n",
+ conn_iter->a_value);
+ g_strfreev(c);
+ candidates = g_list_append(candidates, candidate);
+ }
+ purple_media_add_remote_candidates(media, "yahoo-voice",
+ remote->a_display, candidates);
+ purple_media_codec_list_free(candidates);
}
}
@@ -158,7 +423,6 @@ yahoo_sip_init(PurpleAccount *account)
YahooData *yd = purple_connection_get_protocol_data(pc);
GSource *gsource;
su_root_t *sofia_event_loop;
- su_timer_t *timer;
gchar *sip_str;
purple_debug_info("yahoo", "Starting Sofia-SIP\n");
@@ -168,9 +432,6 @@ yahoo_sip_init(PurpleAccount *account)
gsource = su_glib_root_gsource(sofia_event_loop);
g_source_attach(gsource, g_main_context_default());
- timer = su_timer_create(su_root_task(sofia_event_loop), 200L);
-
-
yd->nua = nua_create(sofia_event_loop, event_callback, account,
NUTAG_URL("sip:*:*;transport=tcp"),
NUTAG_M_PARAMS("transport=tcp"),
More information about the Commits
mailing list