libpurple/protocols/jabber/google.c

branch
soc.2008.vv
changeset 23697
299bafcd8eb8
parent 22648
e286d795c5f9
child 23700
e47be56bdd2b
equal deleted inserted replaced
23696:1049b744d8c8 23697:299bafcd8eb8
16 * You should have received a copy of the GNU General Public License 16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software 17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
19 */ 19 */
20 20
21 #include <farsight/farsight-transport.h> 21 #include <gst/farsight/fs-conference-iface.h>
22 22
23 #include "internal.h" 23 #include "internal.h"
24 #include "debug.h" 24 #include "debug.h"
25 #include "mediamanager.h" 25 #include "mediamanager.h"
26 #include "util.h" 26 #include "util.h"
47 47
48 typedef struct { 48 typedef struct {
49 GoogleSessionId id; 49 GoogleSessionId id;
50 GoogleSessionState state; 50 GoogleSessionState state;
51 PurpleMedia *media; 51 PurpleMedia *media;
52 FarsightStream *stream;
53 JabberStream *js; 52 JabberStream *js;
54 char *remote_jid; 53 char *remote_jid;
55 } GoogleSession; 54 } GoogleSession;
56 55
57 GHashTable *sessions = NULL; 56 GHashTable *sessions = NULL;
82 g_hash_table_remove(sessions, &(session->id)); 81 g_hash_table_remove(sessions, &(session->id));
83 g_free(session->id.id); 82 g_free(session->id.id);
84 g_free(session->id.initiator); 83 g_free(session->id.initiator);
85 g_free(session->remote_jid); 84 g_free(session->remote_jid);
86 g_object_unref(session->media); 85 g_object_unref(session->media);
87 g_object_unref(session->stream);
88 g_free(session); 86 g_free(session);
89 } 87 }
90 88
91 static xmlnode * 89 static xmlnode *
92 google_session_create_xmlnode(GoogleSession *session, const char *type) 90 google_session_create_xmlnode(GoogleSession *session, const char *type)
101 99
102 static void 100 static void
103 google_session_send_accept(GoogleSession *session) 101 google_session_send_accept(GoogleSession *session)
104 { 102 {
105 xmlnode *sess, *desc, *payload; 103 xmlnode *sess, *desc, *payload;
106 GList *codecs = farsight_stream_get_codec_intersection(session->stream); 104 GList *codecs = purple_media_get_negotiated_audio_codecs(session->media);
107 JabberIq *iq = jabber_iq_new(session->js, JABBER_IQ_SET); 105 JabberIq *iq = jabber_iq_new(session->js, JABBER_IQ_SET);
108 106
109 xmlnode_set_attrib(iq->node, "to", session->remote_jid); 107 xmlnode_set_attrib(iq->node, "to", session->remote_jid);
110 sess = google_session_create_xmlnode(session, "accept"); 108 sess = google_session_create_xmlnode(session, "accept");
111 xmlnode_insert_child(iq->node, sess); 109 xmlnode_insert_child(iq->node, sess);
112 desc = xmlnode_new_child(sess, "description"); 110 desc = xmlnode_new_child(sess, "description");
113 xmlnode_set_namespace(desc, "http://www.google.com/session/phone"); 111 xmlnode_set_namespace(desc, "http://www.google.com/session/phone");
114 112
115 for (;codecs; codecs = codecs->next) { 113 for (;codecs; codecs = codecs->next) {
116 FarsightCodec *codec = (FarsightCodec*)codecs->data; 114 FsCodec *codec = (FsCodec*)codecs->data;
117 char id[8], clockrate[10]; 115 char id[8], clockrate[10];
118 payload = xmlnode_new_child(desc, "payload-type"); 116 payload = xmlnode_new_child(desc, "payload-type");
119 g_snprintf(id, sizeof(id), "%d", codec->id); 117 g_snprintf(id, sizeof(id), "%d", codec->id);
120 g_snprintf(clockrate, sizeof(clockrate), "%d", codec->clock_rate); 118 g_snprintf(clockrate, sizeof(clockrate), "%d", codec->clock_rate);
121 xmlnode_set_attrib(payload, "name", codec->encoding_name); 119 xmlnode_set_attrib(payload, "name", codec->encoding_name);
122 xmlnode_set_attrib(payload, "id", id); 120 xmlnode_set_attrib(payload, "id", id);
123 xmlnode_set_attrib(payload, "clockrate", clockrate); 121 xmlnode_set_attrib(payload, "clockrate", clockrate);
124 } 122 }
125 123
124 fs_codec_list_destroy(codecs);
126 jabber_iq_send(iq); 125 jabber_iq_send(iq);
127 farsight_stream_start(session->stream); 126 gst_element_set_state(purple_media_get_audio_pipeline(session->media), GST_STATE_PLAYING);
128 } 127 }
129 128
130 static void 129 static void
131 google_session_send_terminate(GoogleSession *session) 130 google_session_send_terminate(GoogleSession *session)
132 { 131 {
133 xmlnode *sess; 132 xmlnode *sess;
134 GList *codecs = farsight_stream_get_codec_intersection(session->stream);
135 JabberIq *iq = jabber_iq_new(session->js, JABBER_IQ_SET); 133 JabberIq *iq = jabber_iq_new(session->js, JABBER_IQ_SET);
136 134
137 xmlnode_set_attrib(iq->node, "to", session->remote_jid); 135 xmlnode_set_attrib(iq->node, "to", session->remote_jid);
138 sess = google_session_create_xmlnode(session, "terminate"); 136 sess = google_session_create_xmlnode(session, "terminate");
139 xmlnode_insert_child(iq->node, sess); 137 xmlnode_insert_child(iq->node, sess);
140 138
141 jabber_iq_send(iq); 139 jabber_iq_send(iq);
142 farsight_stream_stop(session->stream);
143 google_session_destroy(session); 140 google_session_destroy(session);
144 } 141 }
145 142
146 static void 143 static void
147 google_session_send_reject(GoogleSession *session) 144 google_session_send_reject(GoogleSession *session)
148 { 145 {
149 xmlnode *sess; 146 xmlnode *sess;
150 GList *codecs = farsight_stream_get_codec_intersection(session->stream);
151 JabberIq *iq = jabber_iq_new(session->js, JABBER_IQ_SET); 147 JabberIq *iq = jabber_iq_new(session->js, JABBER_IQ_SET);
152 148
153 xmlnode_set_attrib(iq->node, "to", session->remote_jid); 149 xmlnode_set_attrib(iq->node, "to", session->remote_jid);
154 sess = google_session_create_xmlnode(session, "reject"); 150 sess = google_session_create_xmlnode(session, "reject");
155 xmlnode_insert_child(iq->node, sess); 151 xmlnode_insert_child(iq->node, sess);
156 152
157 jabber_iq_send(iq); 153 jabber_iq_send(iq);
158 farsight_stream_stop(session->stream);
159 google_session_destroy(session); 154 google_session_destroy(session);
160 } 155 }
161 156
162 157
163 static void 158 static void
164 google_session_candidates_prepared (FarsightStream *stream, gchar *candidate_id, GoogleSession *session) 159 google_session_candidates_prepared (PurpleMedia *media, GoogleSession *session)
165 { 160 {
166 JabberIq *iq = jabber_iq_new(session->js, JABBER_IQ_SET); 161 JabberIq *iq = jabber_iq_new(session->js, JABBER_IQ_SET);
167 GList *candidates = farsight_stream_get_native_candidate_list(stream); 162 GList *candidates = purple_media_get_local_audio_candidates(session->media);
168 FarsightTransportInfo *transport; 163 FsCandidate *transport;
169 xmlnode *sess; 164 xmlnode *sess;
170 xmlnode *candidate; 165 xmlnode *candidate;
171 sess = google_session_create_xmlnode(session, "candidates"); 166 sess = google_session_create_xmlnode(session, "candidates");
172 xmlnode_insert_child(iq->node, sess); 167 xmlnode_insert_child(iq->node, sess);
173 xmlnode_set_attrib(iq->node, "to", session->remote_jid); 168 xmlnode_set_attrib(iq->node, "to", session->remote_jid);
174 169
175 for (;candidates;candidates = candidates->next) { 170 for (;candidates;candidates = candidates->next) {
176 transport = (FarsightTransportInfo*)(candidates->data);
177 char port[8]; 171 char port[8];
178 char pref[8]; 172 char pref[8];
173 transport = (FsCandidate*)(candidates->data);
179 174
180 if (!strcmp(transport->ip, "127.0.0.1")) 175 if (!strcmp(transport->ip, "127.0.0.1"))
181 continue; 176 continue;
182 177
183 candidate = xmlnode_new("candidate"); 178 candidate = xmlnode_new("candidate");
184 179
185 g_snprintf(port, sizeof(port), "%d", transport->port); 180 g_snprintf(port, sizeof(port), "%d", transport->port);
186 g_snprintf(pref, sizeof(pref), "%f", transport->preference); 181 g_snprintf(pref, sizeof(pref), "%d", transport->priority);
187 182
188 xmlnode_set_attrib(candidate, "address", transport->ip); 183 xmlnode_set_attrib(candidate, "address", transport->ip);
189 xmlnode_set_attrib(candidate, "port", port); 184 xmlnode_set_attrib(candidate, "port", port);
190 xmlnode_set_attrib(candidate, "name", "rtp"); 185 xmlnode_set_attrib(candidate, "name", "rtp");
191 xmlnode_set_attrib(candidate, "username", transport->username); 186 xmlnode_set_attrib(candidate, "username", transport->username);
192 xmlnode_set_attrib(candidate, "password", transport->password); 187 xmlnode_set_attrib(candidate, "password", transport->password);
193 xmlnode_set_attrib(candidate, "preference", pref); 188 xmlnode_set_attrib(candidate, "preference", pref);
194 xmlnode_set_attrib(candidate, "protocol", transport->proto == FARSIGHT_NETWORK_PROTOCOL_UDP ? "udp" : "tcp"); 189 xmlnode_set_attrib(candidate, "protocol", transport->proto == FS_NETWORK_PROTOCOL_UDP ? "udp" : "tcp");
195 xmlnode_set_attrib(candidate, "type", transport->type == FARSIGHT_CANDIDATE_TYPE_LOCAL ? "local" : 190 xmlnode_set_attrib(candidate, "type", transport->type == FS_CANDIDATE_TYPE_HOST ? "local" :
196 transport->type == FARSIGHT_CANDIDATE_TYPE_DERIVED ? "stun" : 191 transport->type == FS_CANDIDATE_TYPE_PRFLX ? "stun" :
197 transport->type == FARSIGHT_CANDIDATE_TYPE_RELAY ? "relay" : NULL); 192 transport->type == FS_CANDIDATE_TYPE_RELAY ? "relay" : NULL);
198 xmlnode_set_attrib(candidate, "generation", "0"); 193 xmlnode_set_attrib(candidate, "generation", "0");
199 xmlnode_set_attrib(candidate, "network", "0"); 194 xmlnode_set_attrib(candidate, "network", "0");
200 xmlnode_insert_child(sess, candidate); 195 xmlnode_insert_child(sess, candidate);
201 196
202 } 197 }
204 } 199 }
205 200
206 static void 201 static void
207 google_session_handle_initiate(JabberStream *js, GoogleSession *session, xmlnode *packet, xmlnode *sess) 202 google_session_handle_initiate(JabberStream *js, GoogleSession *session, xmlnode *packet, xmlnode *sess)
208 { 203 {
209 PurpleMedia *media;
210 JabberIq *result; 204 JabberIq *result;
211 FarsightSession *fs;
212 GList *codecs = NULL; 205 GList *codecs = NULL;
213 xmlnode *desc_element, *codec_element; 206 xmlnode *desc_element, *codec_element;
214 FarsightCodec *codec; 207 FsCodec *codec;
215 const char *id, *encoding_name, *clock_rate; 208 const char *id, *encoding_name, *clock_rate;
216 int res;
217 209
218 if (session->state != UNINIT) { 210 if (session->state != UNINIT) {
219 purple_debug_error("jabber", "Received initiate for active session.\n"); 211 purple_debug_error("jabber", "Received initiate for active session.\n");
220 return FALSE; 212 return;
221 } 213 }
222 214
223 fs = farsight_session_factory_make("rtp"); 215 session->media = purple_media_manager_create_media(purple_media_manager_get(), js->gc,
224 if (!fs) { 216 "fsrtpconference", session->remote_jid);
225 purple_debug_error("jabber", "Farsight's rtp plugin not installed"); 217
226 return FALSE; 218 /* "rawudp" will need to be changed to "nice" when libnice is finished */
227 } 219 purple_media_add_stream(session->media, session->remote_jid,
228 220 PURPLE_MEDIA_AUDIO, "rawudp");
229 session->stream = farsight_session_create_stream(fs, FARSIGHT_MEDIA_TYPE_AUDIO, FARSIGHT_STREAM_DIRECTION_BOTH); 221
230
231 g_object_set(G_OBJECT(session->stream), "transmitter", "libjingle", NULL);
232
233 desc_element = xmlnode_get_child(sess, "description"); 222 desc_element = xmlnode_get_child(sess, "description");
234 223
235 for (codec_element = xmlnode_get_child(desc_element, "payload-type"); 224 for (codec_element = xmlnode_get_child(desc_element, "payload-type");
236 codec_element; 225 codec_element;
237 codec_element = xmlnode_get_next_twin(codec_element)) { 226 codec_element = xmlnode_get_next_twin(codec_element)) {
238 encoding_name = xmlnode_get_attrib(codec_element, "name"); 227 encoding_name = xmlnode_get_attrib(codec_element, "name");
239 id = xmlnode_get_attrib(codec_element, "id"); 228 id = xmlnode_get_attrib(codec_element, "id");
240 clock_rate = xmlnode_get_attrib(codec_element, "clockrate"); 229 clock_rate = xmlnode_get_attrib(codec_element, "clockrate");
241 230
242 codec = g_new0(FarsightCodec, 1); 231 codec = fs_codec_new(atoi(id), encoding_name, FS_MEDIA_TYPE_AUDIO,
243 farsight_codec_init(codec, atoi(id), encoding_name, FARSIGHT_MEDIA_TYPE_AUDIO, clock_rate ? atoi(clock_rate) : 0); 232 clock_rate ? atoi(clock_rate) : 0);
244 codecs = g_list_append(codecs, codec); 233 codecs = g_list_append(codecs, codec);
245 } 234 }
246 235
247 session->media = media = purple_media_manager_create_media(purple_media_manager_get(), js->gc, session->remote_jid, session->stream, NULL); 236 purple_media_set_remote_audio_codecs(session->media, session->remote_jid, codecs);
248 237
249 g_signal_connect_swapped(G_OBJECT(media), "accepted", G_CALLBACK(google_session_send_accept), session); 238 g_signal_connect_swapped(G_OBJECT(session->media), "accepted",
250 g_signal_connect_swapped(G_OBJECT(media), "reject", G_CALLBACK(google_session_send_reject), session); 239 G_CALLBACK(google_session_send_accept), session);
251 g_signal_connect_swapped(G_OBJECT(media), "hangup", G_CALLBACK(google_session_send_terminate), session); 240 g_signal_connect_swapped(G_OBJECT(session->media), "reject",
252 241 G_CALLBACK(google_session_send_reject), session);
242 g_signal_connect_swapped(G_OBJECT(session->media), "hangup",
243 G_CALLBACK(google_session_send_terminate), session);
244 g_signal_connect(G_OBJECT(session->media), "candidates-prepared",
245 G_CALLBACK(google_session_candidates_prepared), session);
246 purple_media_ready(session->media);
247
248 fs_codec_list_destroy(codecs);
253 249
254 GstElement *e = purple_media_get_audio_src(media);
255 farsight_stream_set_source(session->stream, e);
256
257 e = purple_media_get_audio_sink(media);
258 farsight_stream_set_sink(session->stream, e);
259
260 farsight_stream_prepare_transports(session->stream);
261 res = farsight_stream_set_remote_codecs(session->stream, codecs);
262
263 purple_media_ready(media);
264
265 farsight_codec_list_destroy(codecs);
266 g_signal_connect(G_OBJECT(session->stream), "new-native-candidate", G_CALLBACK(google_session_candidates_prepared), session);
267 result = jabber_iq_new(js, JABBER_IQ_RESULT); 250 result = jabber_iq_new(js, JABBER_IQ_RESULT);
268 jabber_iq_set_id(result, xmlnode_get_attrib(packet, "id")); 251 jabber_iq_set_id(result, xmlnode_get_attrib(packet, "id"));
269 xmlnode_set_attrib(result->node, "to", session->remote_jid); 252 xmlnode_set_attrib(result->node, "to", session->remote_jid);
270 jabber_iq_send(result); 253 jabber_iq_send(result);
271 } 254 }
278 xmlnode *cand; 261 xmlnode *cand;
279 static int name = 0; 262 static int name = 0;
280 char n[4]; 263 char n[4];
281 264
282 for (cand = xmlnode_get_child(sess, "candidate"); cand; cand = xmlnode_get_next_twin(cand)) { 265 for (cand = xmlnode_get_child(sess, "candidate"); cand; cand = xmlnode_get_next_twin(cand)) {
283 FarsightTransportInfo *info = g_new0(FarsightTransportInfo, 1); 266 FsCandidate *info;
284 g_snprintf(n, sizeof(n), "S%d", name++); 267 g_snprintf(n, sizeof(n), "S%d", name++);
285 info->ip = xmlnode_get_attrib(cand, "address"); 268 info = fs_candidate_new(n, FS_COMPONENT_RTP, !strcmp(xmlnode_get_attrib(cand, "type"), "local") ?
286 info->port = atoi(xmlnode_get_attrib(cand, "port")); 269 FS_CANDIDATE_TYPE_HOST :
287 info->proto = !strcmp(xmlnode_get_attrib(cand, "protocol"),"udp") ? FARSIGHT_NETWORK_PROTOCOL_UDP : FARSIGHT_NETWORK_PROTOCOL_TCP; 270 !strcmp(xmlnode_get_attrib(cand, "type"), "stun") ?
288 info->preference = atof(xmlnode_get_attrib(cand, "preference")); 271 FS_CANDIDATE_TYPE_PRFLX :
289 info->type = !strcmp(xmlnode_get_attrib(cand, "type"), "local") ? FARSIGHT_CANDIDATE_TYPE_LOCAL : 272 !strcmp(xmlnode_get_attrib(cand, "type"), "relay") ?
290 !strcmp(xmlnode_get_attrib(cand, "type"), "stun") ? FARSIGHT_CANDIDATE_TYPE_DERIVED : 273 FS_CANDIDATE_TYPE_RELAY : FS_CANDIDATE_TYPE_HOST,
291 !strcmp(xmlnode_get_attrib(cand, "type"), "relay") ? FARSIGHT_CANDIDATE_TYPE_RELAY : FARSIGHT_CANDIDATE_TYPE_LOCAL; 274 !strcmp(xmlnode_get_attrib(cand, "protocol"),"udp") ?
292 info->candidate_id = n; 275 FS_NETWORK_PROTOCOL_UDP : FS_NETWORK_PROTOCOL_TCP,
293 info->username = xmlnode_get_attrib(cand, "username"); 276 xmlnode_get_attrib(cand, "address"), atoi(xmlnode_get_attrib(cand, "port")));
294 info->password = xmlnode_get_attrib(cand, "password"); 277
278 info->username = g_strdup(xmlnode_get_attrib(cand, "username"));
279 info->password = g_strdup(xmlnode_get_attrib(cand, "password"));
280
295 list = g_list_append(list, info); 281 list = g_list_append(list, info);
296 } 282 }
297 283
298 farsight_stream_add_remote_candidate(session->stream, list); 284 purple_media_add_remote_audio_candidates(session->media, session->remote_jid, list);
299 g_list_foreach(list, g_free, NULL); 285 fs_candidate_list_destroy(list);
300 g_list_free(list);
301 286
302 result = jabber_iq_new(js, JABBER_IQ_RESULT); 287 result = jabber_iq_new(js, JABBER_IQ_RESULT);
303 jabber_iq_set_id(result, xmlnode_get_attrib(packet, "id")); 288 jabber_iq_set_id(result, xmlnode_get_attrib(packet, "id"));
304 xmlnode_set_attrib(result->node, "to", session->remote_jid); 289 xmlnode_set_attrib(result->node, "to", session->remote_jid);
305 jabber_iq_send(result); 290 jabber_iq_send(result);
306 } 291 }
307 292
308 static void 293 static void
309 google_session_handle_reject(JabberStream *js, GoogleSession *session, xmlnode *packet, xmlnode *sess) 294 google_session_handle_reject(JabberStream *js, GoogleSession *session, xmlnode *packet, xmlnode *sess)
310 { 295 {
311 farsight_stream_stop(session->stream);
312 purple_media_got_hangup(session->media); 296 purple_media_got_hangup(session->media);
313 297
314 google_session_destroy(session); 298 google_session_destroy(session);
315 } 299 }
316 300
317 static void 301 static void
318 google_session_handle_terminate(JabberStream *js, GoogleSession *session, xmlnode *packet, xmlnode *sess) 302 google_session_handle_terminate(JabberStream *js, GoogleSession *session, xmlnode *packet, xmlnode *sess)
319 { 303 {
320 farsight_stream_stop(session->stream);
321 purple_media_got_hangup(session->media); 304 purple_media_got_hangup(session->media);
322 305
323 google_session_destroy(session); 306 google_session_destroy(session);
324 } 307 }
325 308
344 void 327 void
345 jabber_google_session_parse(JabberStream *js, xmlnode *packet) 328 jabber_google_session_parse(JabberStream *js, xmlnode *packet)
346 { 329 {
347 GoogleSession *session; 330 GoogleSession *session;
348 GoogleSessionId id; 331 GoogleSessionId id;
349 JabberIq *result;
350 332
351 xmlnode *session_node; 333 xmlnode *session_node;
352 xmlnode *desc_node; 334 xmlnode *desc_node;
353 335
354 if (strcmp(xmlnode_get_attrib(packet, "type"), "set")) 336 if (strcmp(xmlnode_get_attrib(packet, "type"), "set"))
356 338
357 session_node = xmlnode_get_child(packet, "session"); 339 session_node = xmlnode_get_child(packet, "session");
358 if (!session_node) 340 if (!session_node)
359 return; 341 return;
360 342
361 id.id = xmlnode_get_attrib(session_node, "id"); 343 id.id = (gchar*)xmlnode_get_attrib(session_node, "id");
362 if (!id.id) 344 if (!id.id)
363 return; 345 return;
364 346
365 id.initiator = xmlnode_get_attrib(session_node, "initiator"); 347 id.initiator = (gchar*)xmlnode_get_attrib(session_node, "initiator");
366 if (!id.initiator) 348 if (!id.initiator)
367 return; 349 return;
368 350
369 if (sessions == NULL) 351 if (sessions == NULL)
370 sessions = g_hash_table_new(google_session_id_hash, google_session_id_equal); 352 sessions = g_hash_table_new(google_session_id_hash, google_session_id_equal);

mercurial