Mercurial > pidgin.yaz
comparison libpurple/protocols/jabber/jingle/rtp.c @ 26023:7252e3d0c627
Add files I missed committing before and remove a few unnecessary functions.
author | Mike Ruprecht <maiku@soc.pidgin.im> |
---|---|
date | Mon, 20 Oct 2008 00:11:33 +0000 |
parents | |
children | 1a2d446cb8a0 |
comparison
equal
deleted
inserted
replaced
26022:46387cbfaf85 | 26023:7252e3d0c627 |
---|---|
1 /** | |
2 * @file rtp.c | |
3 * | |
4 * purple | |
5 * | |
6 * This program is free software; you can redistribute it and/or modify | |
7 * it under the terms of the GNU General Public License as published by | |
8 * the Free Software Foundation; either version 2 of the License, or | |
9 * (at your option) any later version. | |
10 * | |
11 * This program is distributed in the hope that it will be useful, | |
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 * GNU General Public License for more details. | |
15 * | |
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 | |
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA | |
19 */ | |
20 | |
21 #include "config.h" | |
22 | |
23 #include "jabber.h" | |
24 #include "jingle.h" | |
25 #include "media.h" | |
26 #include "mediamanager.h" | |
27 #include "rawudp.h" | |
28 #include "rtp.h" | |
29 #include "session.h" | |
30 #include "debug.h" | |
31 | |
32 #include <string.h> | |
33 | |
34 struct _JingleRtpPrivate | |
35 { | |
36 gchar *media_type; | |
37 gboolean candidates_ready; | |
38 gboolean codecs_ready; | |
39 }; | |
40 | |
41 #define JINGLE_RTP_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), JINGLE_TYPE_RTP, JingleRtpPrivate)) | |
42 | |
43 static void jingle_rtp_class_init (JingleRtpClass *klass); | |
44 static void jingle_rtp_init (JingleRtp *rtp); | |
45 static void jingle_rtp_finalize (GObject *object); | |
46 static void jingle_rtp_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); | |
47 static void jingle_rtp_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); | |
48 static JingleContent *jingle_rtp_parse_internal(xmlnode *rtp); | |
49 static xmlnode *jingle_rtp_to_xml_internal(JingleContent *rtp, xmlnode *content, JingleActionType action); | |
50 static void jingle_rtp_handle_action_internal(JingleContent *content, xmlnode *jingle, JingleActionType action); | |
51 | |
52 static PurpleMedia *jingle_rtp_get_media(JingleSession *session); | |
53 | |
54 static JingleContentClass *parent_class = NULL; | |
55 #if 0 | |
56 enum { | |
57 LAST_SIGNAL | |
58 }; | |
59 static guint jingle_rtp_signals[LAST_SIGNAL] = {0}; | |
60 #endif | |
61 | |
62 enum { | |
63 PROP_0, | |
64 PROP_MEDIA_TYPE, | |
65 }; | |
66 | |
67 GType | |
68 jingle_rtp_get_type() | |
69 { | |
70 static GType type = 0; | |
71 | |
72 if (type == 0) { | |
73 static const GTypeInfo info = { | |
74 sizeof(JingleRtpClass), | |
75 NULL, | |
76 NULL, | |
77 (GClassInitFunc) jingle_rtp_class_init, | |
78 NULL, | |
79 NULL, | |
80 sizeof(JingleRtp), | |
81 0, | |
82 (GInstanceInitFunc) jingle_rtp_init, | |
83 NULL | |
84 }; | |
85 type = g_type_register_static(JINGLE_TYPE_CONTENT, "JingleRtp", &info, 0); | |
86 } | |
87 return type; | |
88 } | |
89 | |
90 static void | |
91 jingle_rtp_class_init (JingleRtpClass *klass) | |
92 { | |
93 GObjectClass *gobject_class = (GObjectClass*)klass; | |
94 parent_class = g_type_class_peek_parent(klass); | |
95 | |
96 gobject_class->finalize = jingle_rtp_finalize; | |
97 gobject_class->set_property = jingle_rtp_set_property; | |
98 gobject_class->get_property = jingle_rtp_get_property; | |
99 klass->parent_class.to_xml = jingle_rtp_to_xml_internal; | |
100 klass->parent_class.parse = jingle_rtp_parse_internal; | |
101 klass->parent_class.description_type = JINGLE_APP_RTP; | |
102 klass->parent_class.handle_action = jingle_rtp_handle_action_internal; | |
103 | |
104 g_object_class_install_property(gobject_class, PROP_MEDIA_TYPE, | |
105 g_param_spec_string("media-type", | |
106 "Media Type", | |
107 "The media type (\"audio\" or \"video\") for this rtp session.", | |
108 NULL, | |
109 G_PARAM_READWRITE)); | |
110 g_type_class_add_private(klass, sizeof(JingleRtpPrivate)); | |
111 } | |
112 | |
113 static void | |
114 jingle_rtp_init (JingleRtp *rtp) | |
115 { | |
116 rtp->priv = JINGLE_RTP_GET_PRIVATE(rtp); | |
117 memset(rtp->priv, 0, sizeof(rtp->priv)); | |
118 } | |
119 | |
120 static void | |
121 jingle_rtp_finalize (GObject *rtp) | |
122 { | |
123 JingleRtpPrivate *priv = JINGLE_RTP_GET_PRIVATE(rtp); | |
124 purple_debug_info("jingle-rtp","jingle_rtp_finalize\n"); | |
125 | |
126 g_free(priv->media_type); | |
127 } | |
128 | |
129 static void | |
130 jingle_rtp_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) | |
131 { | |
132 JingleRtp *rtp; | |
133 g_return_if_fail(JINGLE_IS_RTP(object)); | |
134 | |
135 rtp = JINGLE_RTP(object); | |
136 | |
137 switch (prop_id) { | |
138 case PROP_MEDIA_TYPE: | |
139 g_free(rtp->priv->media_type); | |
140 rtp->priv->media_type = g_value_dup_string(value); | |
141 break; | |
142 default: | |
143 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); | |
144 break; | |
145 } | |
146 } | |
147 | |
148 static void | |
149 jingle_rtp_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) | |
150 { | |
151 JingleRtp *rtp; | |
152 g_return_if_fail(JINGLE_IS_RTP(object)); | |
153 | |
154 rtp = JINGLE_RTP(object); | |
155 | |
156 switch (prop_id) { | |
157 case PROP_MEDIA_TYPE: | |
158 g_value_set_string(value, rtp->priv->media_type); | |
159 break; | |
160 default: | |
161 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); | |
162 break; | |
163 } | |
164 } | |
165 | |
166 static gboolean | |
167 jingle_rtp_ready_to_initiate(JingleSession *session, PurpleMedia *media) | |
168 { | |
169 if (jingle_session_is_initiator(session)) { | |
170 GList *iter = jingle_session_get_contents(session); | |
171 for (; iter; iter = g_list_next(iter)) { | |
172 JingleContent *content = iter->data; | |
173 gchar *name = jingle_content_get_name(content); | |
174 if (!JINGLE_IS_RTP(content) | |
175 || JINGLE_RTP_GET_PRIVATE(content)->codecs_ready == FALSE | |
176 || JINGLE_RTP_GET_PRIVATE(content)->candidates_ready == FALSE) { | |
177 g_free(name); | |
178 return FALSE; | |
179 } | |
180 g_free(name); | |
181 } | |
182 return TRUE; | |
183 } | |
184 return FALSE; | |
185 } | |
186 | |
187 gchar * | |
188 jingle_rtp_get_media_type(JingleContent *content) | |
189 { | |
190 gchar *media_type; | |
191 g_object_get(content, "media-type", &media_type, NULL); | |
192 return media_type; | |
193 } | |
194 | |
195 static PurpleMedia * | |
196 jingle_rtp_get_media(JingleSession *session) | |
197 { | |
198 JabberStream *js = jingle_session_get_js(session); | |
199 gchar *sid = jingle_session_get_sid(session); | |
200 | |
201 PurpleMedia *media = (PurpleMedia *) (js->medias) ? | |
202 g_hash_table_lookup(js->medias, sid) : NULL; | |
203 g_free(sid); | |
204 | |
205 return media; | |
206 } | |
207 | |
208 static JingleTransport * | |
209 jingle_rtp_candidate_to_transport(GType type, guint generation, FsCandidate *candidate) | |
210 { | |
211 if (type == JINGLE_TYPE_RAWUDP) { | |
212 return JINGLE_TRANSPORT(jingle_rawudp_create(generation, | |
213 candidate->foundation, candidate->ip, candidate->port)); | |
214 #if 0 | |
215 } else if (type == JINGLE_TYPE_ICEUDP) { | |
216 return NULL; | |
217 #endif | |
218 } else { | |
219 return NULL; | |
220 } | |
221 } | |
222 | |
223 static FsCandidate * | |
224 jingle_rtp_transport_to_candidate(xmlnode *transport) | |
225 { | |
226 xmlnode *candidate = xmlnode_get_child(transport, "candidate"); | |
227 const gchar *type = xmlnode_get_namespace(transport); | |
228 if (!strcmp(type, JINGLE_TRANSPORT_RAWUDP)) { | |
229 return fs_candidate_new("", FS_COMPONENT_RTP, | |
230 FS_CANDIDATE_TYPE_SRFLX, FS_NETWORK_PROTOCOL_UDP, | |
231 xmlnode_get_attrib(candidate, "ip"), | |
232 atoi(xmlnode_get_attrib(candidate, "port"))); | |
233 #if 0 | |
234 } else if (type == JINGLE_TRANSPORT_ICEUDP) { | |
235 return NULL; | |
236 #endif | |
237 } else { | |
238 return NULL; | |
239 } | |
240 } | |
241 | |
242 static void | |
243 jingle_rtp_accept_cb(PurpleMedia *media, JingleSession *session) | |
244 { | |
245 jabber_iq_send(jingle_session_to_packet(session, JINGLE_TRANSPORT_INFO)); | |
246 jabber_iq_send(jingle_session_to_packet(session, JINGLE_SESSION_ACCEPT)); | |
247 } | |
248 | |
249 static void | |
250 jingle_rtp_reject_cb(PurpleMedia *media, JingleSession *session) | |
251 { | |
252 jabber_iq_send(jingle_session_to_packet(session, JINGLE_SESSION_TERMINATE)); | |
253 g_object_unref(session); | |
254 } | |
255 | |
256 static void | |
257 jingle_rtp_hangup_cb(PurpleMedia *media, JingleSession *session) | |
258 { | |
259 jabber_iq_send(jingle_session_to_packet(session, JINGLE_SESSION_TERMINATE)); | |
260 g_object_unref(session); | |
261 } | |
262 | |
263 static void | |
264 jingle_rtp_new_candidate_cb(PurpleMedia *media, gchar *sid, gchar *name, FsCandidate *candidate, JingleSession *session) | |
265 { | |
266 purple_debug_info("jingle-rtp", "jingle_rtp_new_candidate_cb\n"); | |
267 | |
268 if (candidate->component_id == 1) { | |
269 JingleContent *content = jingle_session_find_content(session, sid, "initiator"); | |
270 JingleTransport *transport = | |
271 JINGLE_TRANSPORT(jingle_rtp_candidate_to_transport( | |
272 JINGLE_TYPE_RAWUDP, 0, candidate)); | |
273 jingle_content_set_pending_transport(content, transport); | |
274 jingle_content_accept_transport(content); | |
275 } | |
276 } | |
277 | |
278 static void | |
279 jingle_rtp_candidates_prepared_cb(PurpleMedia *media, gchar *sid, gchar *name, JingleSession *session) | |
280 { | |
281 JingleContent *content = jingle_session_find_content(session, sid, "initiator"); | |
282 JINGLE_RTP_GET_PRIVATE(content)->candidates_ready = TRUE; | |
283 | |
284 if (jingle_rtp_ready_to_initiate(session, media)) | |
285 jabber_iq_send(jingle_session_to_packet(session, JINGLE_SESSION_INITIATE)); | |
286 } | |
287 | |
288 static void | |
289 jingle_rtp_candidate_pair_established_cb(PurpleMedia *media, FsCandidate *local_candidate, FsCandidate *remote_candidate, JingleSession *session) | |
290 { | |
291 | |
292 } | |
293 | |
294 static void | |
295 jingle_rtp_codecs_ready_cb(PurpleMedia *media, gchar *sid, JingleSession *session) | |
296 { | |
297 JingleContent *content = jingle_session_find_content(session, sid, "initiator"); | |
298 | |
299 if (content == NULL) | |
300 content = jingle_session_find_content(session, sid, "responder"); | |
301 | |
302 if (JINGLE_RTP_GET_PRIVATE(content)->codecs_ready == FALSE) { | |
303 JINGLE_RTP_GET_PRIVATE(content)->codecs_ready = | |
304 purple_media_codecs_ready(media, sid); | |
305 | |
306 if (jingle_rtp_ready_to_initiate(session, media)) | |
307 jabber_iq_send(jingle_session_to_packet(session, JINGLE_SESSION_INITIATE)); | |
308 } | |
309 } | |
310 | |
311 static PurpleMedia * | |
312 jingle_rtp_create_media(JingleContent *content) | |
313 { | |
314 JingleSession *session = jingle_content_get_session(content); | |
315 JabberStream *js = jingle_session_get_js(session); | |
316 gchar *remote_jid = jingle_session_get_remote_jid(session); | |
317 gchar *sid = jingle_session_get_sid(session); | |
318 | |
319 PurpleMedia *media = purple_media_manager_create_media(purple_media_manager_get(), | |
320 js->gc, "fsrtpconference", remote_jid); | |
321 g_free(remote_jid); | |
322 | |
323 if (!media) { | |
324 purple_debug_error("jingle-rtp", "Couldn't create media session\n"); | |
325 return NULL; | |
326 } | |
327 | |
328 /* insert it into the hash table */ | |
329 if (!js->medias) { | |
330 purple_debug_info("jingle-rtp", "Creating hash table for media\n"); | |
331 js->medias = g_hash_table_new(g_str_hash, g_str_equal); | |
332 } | |
333 purple_debug_info("jingle-rtp", "inserting media with sid: %s into table\n", sid); | |
334 g_hash_table_insert(js->medias, sid, media); | |
335 | |
336 /* connect callbacks */ | |
337 g_signal_connect(G_OBJECT(media), "accepted", | |
338 G_CALLBACK(jingle_rtp_accept_cb), session); | |
339 g_signal_connect(G_OBJECT(media), "reject", | |
340 G_CALLBACK(jingle_rtp_reject_cb), session); | |
341 g_signal_connect(G_OBJECT(media), "hangup", | |
342 G_CALLBACK(jingle_rtp_hangup_cb), session); | |
343 g_signal_connect(G_OBJECT(media), "new-candidate", | |
344 G_CALLBACK(jingle_rtp_new_candidate_cb), session); | |
345 g_signal_connect(G_OBJECT(media), "candidates-prepared", | |
346 G_CALLBACK(jingle_rtp_candidates_prepared_cb), session); | |
347 g_signal_connect(G_OBJECT(media), "candidate-pair", | |
348 G_CALLBACK(jingle_rtp_candidate_pair_established_cb), session); | |
349 g_signal_connect(G_OBJECT(media), "codecs-ready", | |
350 G_CALLBACK(jingle_rtp_codecs_ready_cb), session); | |
351 | |
352 g_object_unref(session); | |
353 return media; | |
354 } | |
355 | |
356 static gboolean | |
357 jingle_rtp_init_media(JingleContent *content) | |
358 { | |
359 JingleSession *session = jingle_content_get_session(content); | |
360 PurpleMedia *media = jingle_rtp_get_media(session); | |
361 gchar *media_type; | |
362 gchar *remote_jid; | |
363 gchar *senders; | |
364 gchar *name; | |
365 const gchar *transmitter; | |
366 FsMediaType type; | |
367 FsStreamDirection direction; | |
368 JingleTransport *transport; | |
369 | |
370 /* maybe this create ought to just be in initiate and handle initiate */ | |
371 if (media == NULL) | |
372 media = jingle_rtp_create_media(content); | |
373 | |
374 if (media == NULL) | |
375 return FALSE; | |
376 | |
377 name = jingle_content_get_name(content); | |
378 media_type = jingle_rtp_get_media_type(content); | |
379 remote_jid = jingle_session_get_remote_jid(session); | |
380 senders = jingle_content_get_senders(content); | |
381 transport = jingle_content_get_transport(content); | |
382 | |
383 if (JINGLE_IS_RAWUDP(transport)) | |
384 transmitter = "rawudp"; | |
385 else | |
386 transmitter = "notransmitter"; | |
387 | |
388 if (!strcmp(media_type, "audio")) | |
389 type = FS_MEDIA_TYPE_AUDIO; | |
390 else | |
391 type = FS_MEDIA_TYPE_VIDEO; | |
392 | |
393 if (!strcmp(senders, "both")) | |
394 direction = FS_DIRECTION_BOTH; | |
395 else if (!strcmp(senders, "initiator") | |
396 && jingle_session_is_initiator(session)) | |
397 direction = FS_DIRECTION_SEND; | |
398 else | |
399 direction = FS_DIRECTION_RECV; | |
400 | |
401 purple_media_add_stream(media, name, remote_jid, | |
402 purple_media_from_fs(type, direction), | |
403 transmitter, 0, NULL); | |
404 | |
405 | |
406 g_free(name); | |
407 g_free(media_type); | |
408 g_free(remote_jid); | |
409 g_free(senders); | |
410 g_object_unref(session); | |
411 | |
412 /* needs to be after all the streams have been added */ | |
413 purple_media_ready(media); | |
414 | |
415 return TRUE; | |
416 } | |
417 | |
418 static GList * | |
419 jingle_rtp_parse_codecs(xmlnode *description) | |
420 { | |
421 GList *codecs = NULL; | |
422 xmlnode *codec_element = NULL; | |
423 const char *encoding_name,*id, *clock_rate; | |
424 FsCodec *codec; | |
425 const gchar *media = xmlnode_get_attrib(description, "media"); | |
426 FsMediaType type = !strcmp(media, "video") ? FS_MEDIA_TYPE_VIDEO : | |
427 !strcmp(media, "audio") ? FS_MEDIA_TYPE_AUDIO : 0; | |
428 | |
429 for (codec_element = xmlnode_get_child(description, "payload-type") ; | |
430 codec_element ; | |
431 codec_element = xmlnode_get_next_twin(codec_element)) { | |
432 xmlnode *param; | |
433 gchar *codec_str; | |
434 encoding_name = xmlnode_get_attrib(codec_element, "name"); | |
435 | |
436 id = xmlnode_get_attrib(codec_element, "id"); | |
437 clock_rate = xmlnode_get_attrib(codec_element, "clockrate"); | |
438 | |
439 codec = fs_codec_new(atoi(id), encoding_name, | |
440 type, | |
441 clock_rate ? atoi(clock_rate) : 0); | |
442 | |
443 for (param = xmlnode_get_child(codec_element, "parameter"); | |
444 param; param = xmlnode_get_next_twin(param)) { | |
445 fs_codec_add_optional_parameter(codec, | |
446 xmlnode_get_attrib(param, "name"), | |
447 xmlnode_get_attrib(param, "value")); | |
448 } | |
449 | |
450 codec_str = fs_codec_to_string(codec); | |
451 purple_debug_info("jingle-rtp", "received codec: %s\n", codec_str); | |
452 g_free(codec_str); | |
453 | |
454 codecs = g_list_append(codecs, codec); | |
455 } | |
456 return codecs; | |
457 } | |
458 | |
459 static JingleContent * | |
460 jingle_rtp_parse_internal(xmlnode *rtp) | |
461 { | |
462 JingleContent *content = parent_class->parse(rtp); | |
463 xmlnode *description = xmlnode_get_child(rtp, "description"); | |
464 const gchar *media_type = xmlnode_get_attrib(description, "media"); | |
465 purple_debug_info("jingle-rtp", "rtp parse\n"); | |
466 g_object_set(content, "media-type", media_type, NULL); | |
467 return content; | |
468 } | |
469 | |
470 static void | |
471 jingle_rtp_add_payloads(xmlnode *description, GList *codecs) | |
472 { | |
473 for (; codecs ; codecs = codecs->next) { | |
474 FsCodec *codec = (FsCodec*)codecs->data; | |
475 GList *iter = codec->optional_params; | |
476 char id[8], clockrate[10], channels[10]; | |
477 gchar *codec_str; | |
478 xmlnode *payload = xmlnode_new_child(description, "payload-type"); | |
479 | |
480 g_snprintf(id, sizeof(id), "%d", codec->id); | |
481 g_snprintf(clockrate, sizeof(clockrate), "%d", codec->clock_rate); | |
482 g_snprintf(channels, sizeof(channels), "%d", codec->channels); | |
483 | |
484 xmlnode_set_attrib(payload, "name", codec->encoding_name); | |
485 xmlnode_set_attrib(payload, "id", id); | |
486 xmlnode_set_attrib(payload, "clockrate", clockrate); | |
487 xmlnode_set_attrib(payload, "channels", channels); | |
488 | |
489 for (; iter; iter = g_list_next(iter)) { | |
490 FsCodecParameter *fsparam = iter->data; | |
491 xmlnode *param = xmlnode_new_child(payload, "parameter"); | |
492 xmlnode_set_attrib(param, "name", fsparam->name); | |
493 xmlnode_set_attrib(param, "value", fsparam->value); | |
494 } | |
495 | |
496 codec_str = fs_codec_to_string(codec); | |
497 purple_debug_info("jingle", "adding codec: %s\n", codec_str); | |
498 g_free(codec_str); | |
499 } | |
500 } | |
501 | |
502 static xmlnode * | |
503 jingle_rtp_to_xml_internal(JingleContent *rtp, xmlnode *content, JingleActionType action) | |
504 { | |
505 xmlnode *node = parent_class->to_xml(rtp, content, action); | |
506 xmlnode *description = xmlnode_get_child(node, "description"); | |
507 if (description != NULL) { | |
508 JingleSession *session = jingle_content_get_session(rtp); | |
509 PurpleMedia *media = jingle_rtp_get_media(session); | |
510 gchar *media_type = jingle_rtp_get_media_type(rtp); | |
511 gchar *name = jingle_content_get_name(rtp); | |
512 GList *codecs = purple_media_get_local_codecs(media, name); | |
513 | |
514 xmlnode_set_attrib(description, "media", media_type); | |
515 | |
516 g_free(media_type); | |
517 g_free(name); | |
518 g_object_unref(session); | |
519 | |
520 jingle_rtp_add_payloads(description, codecs); | |
521 } | |
522 return node; | |
523 } | |
524 | |
525 static void | |
526 jingle_rtp_handle_action_internal(JingleContent *content, xmlnode *jingle, JingleActionType action) | |
527 { | |
528 switch (action) { | |
529 case JINGLE_SESSION_ACCEPT: { | |
530 JingleSession *session = jingle_content_get_session(content); | |
531 xmlnode *description = xmlnode_get_child(jingle, "content/description"); | |
532 GList *codecs = jingle_rtp_parse_codecs(description); | |
533 | |
534 purple_media_set_remote_codecs(jingle_rtp_get_media(session), | |
535 jingle_content_get_name(content), | |
536 jingle_session_get_remote_jid(session), codecs); | |
537 | |
538 g_object_unref(session); | |
539 break; | |
540 } | |
541 case JINGLE_SESSION_INITIATE: { | |
542 JingleSession *session = jingle_content_get_session(content); | |
543 xmlnode *description = xmlnode_get_child(jingle, "content/description"); | |
544 xmlnode *transport = xmlnode_get_child(jingle, "content/transport"); | |
545 FsCandidate *candidate = jingle_rtp_transport_to_candidate(transport); | |
546 GList *candidates = g_list_append(NULL, candidate); | |
547 GList *codecs = jingle_rtp_parse_codecs(description); | |
548 | |
549 jingle_rtp_init_media(content); | |
550 | |
551 purple_media_set_remote_codecs(jingle_rtp_get_media(session), | |
552 jingle_content_get_name(content), | |
553 jingle_session_get_remote_jid(session), codecs); | |
554 | |
555 /* manufacture rtcp candidate */ | |
556 candidate = fs_candidate_copy(candidate); | |
557 candidate->component_id = 2; | |
558 candidate->port = candidate->port + 1; | |
559 candidates = g_list_append(candidates, candidate); | |
560 | |
561 purple_media_add_remote_candidates(jingle_rtp_get_media(session), | |
562 jingle_content_get_name(content), | |
563 jingle_session_get_remote_jid(session), | |
564 candidates); | |
565 | |
566 g_object_unref(session); | |
567 break; | |
568 } | |
569 case JINGLE_SESSION_TERMINATE: { | |
570 JingleSession *session = jingle_content_get_session(content); | |
571 purple_media_got_hangup(jingle_rtp_get_media(session)); | |
572 g_object_unref(session); | |
573 break; | |
574 } | |
575 case JINGLE_TRANSPORT_INFO: { | |
576 JingleSession *session = jingle_content_get_session(content); | |
577 xmlnode *transport = xmlnode_get_child(jingle, "content/transport"); | |
578 FsCandidate *candidate = jingle_rtp_transport_to_candidate(transport); | |
579 GList *candidates = g_list_append(NULL, candidate); | |
580 | |
581 /* manufacture rtcp candidate */ | |
582 candidate = fs_candidate_copy(candidate); | |
583 candidate->component_id = 2; | |
584 candidate->port = candidate->port + 1; | |
585 candidates = g_list_append(candidates, candidate); | |
586 | |
587 purple_media_add_remote_candidates(jingle_rtp_get_media(session), | |
588 jingle_content_get_name(content), | |
589 jingle_session_get_remote_jid(session), | |
590 candidates); | |
591 purple_media_got_accept(jingle_rtp_get_media(session)); | |
592 g_object_unref(session); | |
593 break; | |
594 } | |
595 default: | |
596 break; | |
597 } | |
598 } | |
599 | |
600 PurpleMedia * | |
601 jingle_rtp_initiate_media(JabberStream *js, const gchar *who, | |
602 PurpleMediaSessionType type) | |
603 { | |
604 /* create content negotiation */ | |
605 JingleSession *session; | |
606 JingleContent *content; | |
607 JingleTransport *transport; | |
608 JabberBuddy *jb; | |
609 JabberBuddyResource *jbr; | |
610 | |
611 gchar *jid = NULL, *me = NULL, *sid = NULL; | |
612 | |
613 /* construct JID to send to */ | |
614 jb = jabber_buddy_find(js, who, FALSE); | |
615 if (!jb) { | |
616 purple_debug_error("jingle-rtp", "Could not find Jabber buddy\n"); | |
617 return NULL; | |
618 } | |
619 jbr = jabber_buddy_find_resource(jb, NULL); | |
620 if (!jbr) { | |
621 purple_debug_error("jingle-rtp", "Could not find buddy's resource\n"); | |
622 } | |
623 | |
624 if ((strchr(who, '/') == NULL) && jbr && (jbr->name != NULL)) { | |
625 jid = g_strdup_printf("%s/%s", who, jbr->name); | |
626 } else { | |
627 jid = g_strdup(who); | |
628 } | |
629 | |
630 /* set ourselves as initiator */ | |
631 me = g_strdup_printf("%s@%s/%s", js->user->node, js->user->domain, js->user->resource); | |
632 | |
633 sid = jabber_get_next_id(js); | |
634 session = jingle_session_create(js, sid, me, jid, TRUE); | |
635 g_free(sid); | |
636 | |
637 transport = jingle_transport_create(JINGLE_TRANSPORT_RAWUDP); | |
638 content = jingle_content_create(JINGLE_APP_RTP, "initiator", "session", "test-session", "both", transport); | |
639 jingle_session_add_content(session, content); | |
640 if (purple_media_to_fs_media_type(type) == FS_MEDIA_TYPE_AUDIO) | |
641 JINGLE_RTP(content)->priv->media_type = g_strdup("audio"); | |
642 else | |
643 JINGLE_RTP(content)->priv->media_type = g_strdup("video"); | |
644 | |
645 jingle_rtp_init_media(content); | |
646 | |
647 purple_media_wait(jingle_rtp_get_media(session)); | |
648 | |
649 g_free(jid); | |
650 g_free(me); | |
651 | |
652 return NULL; | |
653 } | |
654 | |
655 void | |
656 jingle_rtp_terminate_session(JabberStream *js, const gchar *who) | |
657 { | |
658 JingleSession *session; | |
659 /* XXX: This may cause file transfers and xml sessions to stop as well */ | |
660 session = jingle_session_find_by_jid(js, who); | |
661 | |
662 if (session) { | |
663 PurpleMedia *media = jingle_rtp_get_media(session); | |
664 if (media) { | |
665 purple_debug_info("jingle-rtp", "hanging up media\n"); | |
666 purple_media_hangup(media); | |
667 } | |
668 } | |
669 } | |
670 |