Mercurial > pidgin.yaz
comparison libpurple/protocols/jabber/jingle.c @ 25638:9f36ed35615e
Add the new jingle.c/h files.
author | Sadrul Habib Chowdhury <imadil@gmail.com> |
---|---|
date | Sat, 22 Mar 2008 04:48:36 +0000 |
parents | |
children | e1c8ec1259de |
comparison
equal
deleted
inserted
replaced
25637:92e71f6e10d4 | 25638:9f36ed35615e |
---|---|
1 /* | |
2 * purple - Jabber Protocol Plugin | |
3 * | |
4 * This program is free software; you can redistribute it and/or modify | |
5 * it under the terms of the GNU General Public License as published by | |
6 * the Free Software Foundation; either version 2 of the License, or | |
7 * (at your option) any later version. | |
8 * | |
9 * This program is distributed in the hope that it will be useful, | |
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 * GNU General Public License for more details. | |
13 * | |
14 * You should have received a copy of the GNU General Public License | |
15 * along with this program; if not, write to the Free Software | |
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA | |
17 * | |
18 */ | |
19 | |
20 #include "config.h" | |
21 #include "purple.h" | |
22 #include "jingle.h" | |
23 #include "xmlnode.h" | |
24 | |
25 #include <stdlib.h> | |
26 #include <string.h> | |
27 #include <glib.h> | |
28 | |
29 #ifdef USE_FARSIGHT | |
30 | |
31 #include <farsight/farsight.h> | |
32 #include <farsight/farsight-transport.h> | |
33 | |
34 /* keep a hash table of JingleSessions */ | |
35 static GHashTable *sessions = NULL; | |
36 | |
37 static gboolean | |
38 jabber_jingle_session_equal(gconstpointer a, gconstpointer b) | |
39 { | |
40 purple_debug_info("jingle", | |
41 "jabber_jingle_session_equal, comparing %s and %s\n", | |
42 ((JingleSession *)a)->id, | |
43 ((JingleSession *)b)->id); | |
44 return !strcmp(((JingleSession *) a)->id, ((JingleSession *) b)->id); | |
45 } | |
46 | |
47 static JingleSession * | |
48 jabber_jingle_session_create_internal(JabberStream *js, | |
49 const char *id) | |
50 { | |
51 JingleSession *sess = g_new0(JingleSession, 1); | |
52 sess->js = js; | |
53 | |
54 if (id) { | |
55 sess->id = g_strdup(id); | |
56 } else if (js) { | |
57 /* init the session ID... */ | |
58 sess->id = jabber_get_next_id(js); | |
59 } | |
60 | |
61 /* insert it into the hash table */ | |
62 if (!sessions) { | |
63 purple_debug_info("jingle", "Creating hash table for sessions\n"); | |
64 sessions = g_hash_table_new(g_str_hash, g_str_equal); | |
65 } | |
66 purple_debug_info("jingle", "inserting session with key: %s into table\n", | |
67 sess->id); | |
68 g_hash_table_insert(sessions, sess->id, sess); | |
69 | |
70 sess->remote_candidates = NULL; | |
71 sess->remote_codecs = NULL; | |
72 | |
73 return sess; | |
74 } | |
75 | |
76 JabberStream * | |
77 jabber_jingle_session_get_js(const JingleSession *sess) | |
78 { | |
79 return sess->js; | |
80 } | |
81 | |
82 JingleSession * | |
83 jabber_jingle_session_create(JabberStream *js) | |
84 { | |
85 JingleSession *sess = jabber_jingle_session_create_internal(js, NULL); | |
86 sess->is_initiator = TRUE; | |
87 return sess; | |
88 } | |
89 | |
90 JingleSession * | |
91 jabber_jingle_session_create_by_id(JabberStream *js, const char *id) | |
92 { | |
93 JingleSession *sess = jabber_jingle_session_create_internal(js, id); | |
94 sess->is_initiator = FALSE; | |
95 return sess; | |
96 } | |
97 | |
98 const char * | |
99 jabber_jingle_session_get_id(const JingleSession *sess) | |
100 { | |
101 return sess->id; | |
102 } | |
103 | |
104 void | |
105 jabber_jingle_session_destroy(JingleSession *sess) | |
106 { | |
107 g_hash_table_remove(sessions, sess->id); | |
108 g_free(sess->id); | |
109 farsight_codec_list_destroy(sess->remote_codecs); | |
110 g_list_free(sess->remote_candidates); | |
111 g_free(sess); | |
112 } | |
113 | |
114 JingleSession * | |
115 jabber_jingle_session_find_by_id(const char *id) | |
116 { | |
117 purple_debug_info("jingle", "find_by_id %s\n", id); | |
118 purple_debug_info("jingle", "hash table: %lx\n", sessions); | |
119 purple_debug_info("jingle", "hash table size %d\n", | |
120 g_hash_table_size(sessions)); | |
121 purple_debug_info("jingle", "lookup: %lx\n", g_hash_table_lookup(sessions, id)); | |
122 return (JingleSession *) g_hash_table_lookup(sessions, id); | |
123 } | |
124 | |
125 GList * | |
126 jabber_jingle_get_codecs(const xmlnode *description) | |
127 { | |
128 GList *codecs = NULL; | |
129 xmlnode *codec_element = NULL; | |
130 const char *encoding_name,*id, *clock_rate; | |
131 FarsightCodec *codec; | |
132 | |
133 for (codec_element = xmlnode_get_child(description, "payload-type") ; | |
134 codec_element ; | |
135 codec_element = xmlnode_get_next_twin(codec_element)) { | |
136 encoding_name = xmlnode_get_attrib(codec_element, "name"); | |
137 id = xmlnode_get_attrib(codec_element, "id"); | |
138 clock_rate = xmlnode_get_attrib(codec_element, "clockrate"); | |
139 | |
140 codec = g_new0(FarsightCodec, 1); | |
141 farsight_codec_init(codec, atoi(id), encoding_name, | |
142 FARSIGHT_MEDIA_TYPE_AUDIO, | |
143 clock_rate ? atoi(clock_rate) : 0); | |
144 codecs = g_list_append(codecs, codec); | |
145 } | |
146 return codecs; | |
147 } | |
148 | |
149 GList * | |
150 jabber_jingle_get_candidates(const xmlnode *transport) | |
151 { | |
152 GList *candidates = NULL; | |
153 xmlnode *candidate = NULL; | |
154 FarsightTransportInfo *ti; | |
155 | |
156 for (candidate = xmlnode_get_child(transport, "candidate") ; | |
157 candidate ; | |
158 candidate = xmlnode_get_next_twin(candidate)) { | |
159 const char *type = xmlnode_get_attrib(candidate, "type"); | |
160 ti = g_new0(FarsightTransportInfo, 1); | |
161 ti->component = atoi(xmlnode_get_attrib(candidate, "component")); | |
162 ti->ip = xmlnode_get_attrib(candidate, "ip"); | |
163 ti->port = atoi(xmlnode_get_attrib(candidate, "port")); | |
164 ti->proto = strcmp(xmlnode_get_attrib(candidate, "protocol"), | |
165 "udp") == 0 ? | |
166 FARSIGHT_NETWORK_PROTOCOL_UDP : | |
167 FARSIGHT_NETWORK_PROTOCOL_TCP; | |
168 /* it seems Farsight RTP doesn't handle this correctly right now */ | |
169 ti->username = xmlnode_get_attrib(candidate, "ufrag"); | |
170 ti->password = xmlnode_get_attrib(candidate, "pwd"); | |
171 /* not quite sure about this */ | |
172 ti->type = strcmp(type, "host") == 0 ? | |
173 FARSIGHT_CANDIDATE_TYPE_LOCAL : | |
174 strcmp(type, "prflx") == 0 ? | |
175 FARSIGHT_CANDIDATE_TYPE_DERIVED : | |
176 FARSIGHT_CANDIDATE_TYPE_RELAY; | |
177 | |
178 candidates = g_list_append(candidates, ti); | |
179 } | |
180 | |
181 return candidates; | |
182 } | |
183 | |
184 FarsightStream * | |
185 jabber_jingle_session_get_stream(const JingleSession *sess) | |
186 { | |
187 return sess->stream; | |
188 } | |
189 | |
190 void | |
191 jabber_jingle_session_set_stream(JingleSession *sess, FarsightStream *stream) | |
192 { | |
193 sess->stream = stream; | |
194 } | |
195 | |
196 PurpleMedia * | |
197 jabber_jingle_session_get_media(const JingleSession *sess) | |
198 { | |
199 return sess->media; | |
200 } | |
201 | |
202 void | |
203 jabber_jingle_session_set_media(JingleSession *sess, PurpleMedia *media) | |
204 { | |
205 sess->media = media; | |
206 } | |
207 | |
208 const char * | |
209 jabber_jingle_session_get_remote_jid(const JingleSession *sess) | |
210 { | |
211 return sess->remote_jid; | |
212 } | |
213 | |
214 void | |
215 jabber_jingle_session_set_remote_jid(JingleSession *sess, | |
216 const char *remote_jid) | |
217 { | |
218 sess->remote_jid = strdup(remote_jid); | |
219 } | |
220 | |
221 const char * | |
222 jabber_jingle_session_get_initiator(const JingleSession *sess) | |
223 { | |
224 return sess->initiator; | |
225 } | |
226 | |
227 void | |
228 jabber_jingle_session_set_initiator(JingleSession *sess, | |
229 const char *initiator) | |
230 { | |
231 sess->initiator = g_strdup(initiator); | |
232 } | |
233 | |
234 gboolean | |
235 jabber_jingle_session_is_initiator(const JingleSession *sess) | |
236 { | |
237 return sess->is_initiator; | |
238 } | |
239 | |
240 void | |
241 jabber_jingle_session_add_remote_candidate(JingleSession *sess, | |
242 const GList *candidate) | |
243 { | |
244 /* the length of the candidate list should be 1... */ | |
245 GList *cand = candidate; | |
246 for (; cand ; cand = cand->next) { | |
247 purple_debug_info("jingle", "Adding remote candidate with id = %s\n", | |
248 ((FarsightTransportInfo *) cand->data)->candidate_id); | |
249 sess->remote_candidates = g_list_append(sess->remote_candidates, | |
250 cand->data); | |
251 } | |
252 } | |
253 | |
254 static GList * | |
255 jabber_jingle_session_get_remote_candidate(const JingleSession *sess, | |
256 const gchar *id) | |
257 { | |
258 GList *candidates = NULL; | |
259 GList *find = sess->remote_candidates; | |
260 for (; find ; find = find->next) { | |
261 const FarsightTransportInfo *candidate = | |
262 (FarsightTransportInfo *) find->data; | |
263 if (!strcmp(candidate->candidate_id, id)) { | |
264 candidates = g_list_append(candidates, (void *) candidate); | |
265 } | |
266 } | |
267 return candidates; | |
268 } | |
269 | |
270 static xmlnode * | |
271 jabber_jingle_session_create_jingle_element(const JingleSession *sess, | |
272 const char *action) | |
273 { | |
274 xmlnode *jingle = xmlnode_new("jingle"); | |
275 xmlnode_set_namespace(jingle, "urn:xmpp:tmp:jingle"); | |
276 xmlnode_set_attrib(jingle, "action", action); | |
277 xmlnode_set_attrib(jingle, "initiator", | |
278 jabber_jingle_session_get_initiator(sess)); | |
279 xmlnode_set_attrib(jingle, "responder", | |
280 jabber_jingle_session_is_initiator(sess) ? | |
281 jabber_jingle_session_get_remote_jid(sess) : | |
282 jabber_jingle_session_get_initiator(sess)); | |
283 xmlnode_set_attrib(jingle, "sid", sess->id); | |
284 | |
285 return jingle; | |
286 } | |
287 | |
288 xmlnode * | |
289 jabber_jingle_session_create_terminate(const JingleSession *sess, | |
290 const char *reasoncode, | |
291 const char *reasontext) | |
292 { | |
293 xmlnode *jingle = | |
294 jabber_jingle_session_create_jingle_element(sess, "session-terminate"); | |
295 xmlnode_set_attrib(jingle, "resoncode", reasoncode); | |
296 if (reasontext) { | |
297 xmlnode_set_attrib(jingle, "reasontext", reasontext); | |
298 } | |
299 xmlnode_set_attrib(jingle, "sid", sess->id); | |
300 | |
301 return jingle; | |
302 } | |
303 | |
304 static xmlnode * | |
305 jabber_jingle_session_create_description(const JingleSession *sess) | |
306 { | |
307 GList *codecs = | |
308 farsight_stream_get_local_codecs(jabber_jingle_session_get_stream(sess)); | |
309 | |
310 xmlnode *description = xmlnode_new("description"); | |
311 xmlnode_set_namespace(description, "urn:xmpp:tmp:jingle:apps:audio-rtp"); | |
312 | |
313 /* get codecs */ | |
314 for (; codecs ; codecs = codecs->next) { | |
315 FarsightCodec *codec = (FarsightCodec*)codecs->data; | |
316 char id[8], clockrate[10]; | |
317 xmlnode *payload = xmlnode_new_child(description, "payload-type"); | |
318 | |
319 g_snprintf(id, sizeof(id), "%d", codec->id); | |
320 g_snprintf(clockrate, sizeof(clockrate), "%d", codec->clock_rate); | |
321 | |
322 xmlnode_set_attrib(payload, "name", codec->encoding_name); | |
323 xmlnode_set_attrib(payload, "id", id); | |
324 xmlnode_set_attrib(payload, "clockrate", clockrate); | |
325 } | |
326 | |
327 return description; | |
328 } | |
329 | |
330 /* split into two separate methods, one to generate session-accept | |
331 (includes codecs) and one to generate transport-info (includes transports | |
332 candidates) */ | |
333 xmlnode * | |
334 jabber_jingle_session_create_session_accept(const JingleSession *sess) | |
335 { | |
336 xmlnode *jingle = | |
337 jabber_jingle_session_create_jingle_element(sess, "session-accept"); | |
338 xmlnode *content = NULL; | |
339 xmlnode *description = NULL; | |
340 | |
341 | |
342 content = xmlnode_new_child(jingle, "content"); | |
343 xmlnode_set_attrib(content, "creator", "initiator"); | |
344 xmlnode_set_attrib(content, "name", "audio-content"); | |
345 xmlnode_set_attrib(content, "profile", "RTP/AVP"); | |
346 | |
347 description = jabber_jingle_session_create_description(sess); | |
348 xmlnode_insert_child(jingle, description); | |
349 | |
350 return jingle; | |
351 } | |
352 | |
353 static guint | |
354 jabber_jingle_get_priority(guint type, guint network) | |
355 { | |
356 switch (type) { | |
357 case FARSIGHT_CANDIDATE_TYPE_LOCAL: | |
358 return network == 0 ? 4096 : network == 1 ? 2048 : 1024; | |
359 break; | |
360 case FARSIGHT_CANDIDATE_TYPE_DERIVED: | |
361 return 126; | |
362 break; | |
363 case FARSIGHT_CANDIDATE_TYPE_RELAY: | |
364 return 100; | |
365 break; | |
366 default: | |
367 return 0; /* unknown type, should not happen */ | |
368 } | |
369 } | |
370 | |
371 xmlnode * | |
372 jabber_jingle_session_create_transport_info(const JingleSession *sess, | |
373 gchar *candidate_id) | |
374 { | |
375 xmlnode *jingle = | |
376 jabber_jingle_session_create_jingle_element(sess, "transport-info"); | |
377 xmlnode *content = NULL; | |
378 xmlnode *transport = NULL; | |
379 GList *candidates = | |
380 farsight_stream_get_native_candidate( | |
381 jabber_jingle_session_get_stream(sess), candidate_id); | |
382 | |
383 content = xmlnode_new_child(jingle, "content"); | |
384 xmlnode_set_attrib(content, "creator", "initiator"); | |
385 xmlnode_set_attrib(content, "name", "audio-content"); | |
386 xmlnode_set_attrib(content, "profile", "RTP/AVP"); | |
387 | |
388 transport = xmlnode_new_child(content, "transport"); | |
389 xmlnode_set_namespace(transport, "urn:xmpp:tmp:jingle:transports:ice-tcp"); | |
390 | |
391 /* get transport candidate */ | |
392 for (; candidates ; candidates = candidates->next) { | |
393 FarsightTransportInfo *transport_info = | |
394 (FarsightTransportInfo *) candidates->data; | |
395 char port[8]; | |
396 char prio[8]; | |
397 char component[8]; | |
398 xmlnode *candidate = NULL; | |
399 | |
400 if (!strcmp(transport_info->ip, "127.0.0.1")) { | |
401 continue; | |
402 } | |
403 | |
404 candidate = xmlnode_new_child(transport, "candidate"); | |
405 | |
406 g_snprintf(port, sizeof(port), "%d", transport_info->port); | |
407 g_snprintf(prio, sizeof(prio), "%d", | |
408 jabber_jingle_get_priority(transport_info->type, 0)); | |
409 g_snprintf(component, sizeof(component), "%d", transport_info->component); | |
410 | |
411 xmlnode_set_attrib(candidate, "component", component); | |
412 xmlnode_set_attrib(candidate, "foundation", "1"); /* what about this? */ | |
413 xmlnode_set_attrib(candidate, "generation", "0"); /* ? */ | |
414 xmlnode_set_attrib(candidate, "ip", transport_info->ip); | |
415 xmlnode_set_attrib(candidate, "network", "0"); /* ? */ | |
416 xmlnode_set_attrib(candidate, "port", port); | |
417 xmlnode_set_attrib(candidate, "priority", prio); /* Is this correct? */ | |
418 xmlnode_set_attrib(candidate, "protocol", | |
419 transport_info->proto == FARSIGHT_NETWORK_PROTOCOL_UDP ? | |
420 "udp" : "tcp"); | |
421 if (transport_info->username) | |
422 xmlnode_set_attrib(candidate, "ufrag", transport_info->username); | |
423 if (transport_info->password) | |
424 xmlnode_set_attrib(candidate, "pwd", transport_info->password); | |
425 | |
426 xmlnode_set_attrib(candidate, "type", | |
427 transport_info->type == FARSIGHT_CANDIDATE_TYPE_LOCAL ? | |
428 "host" : | |
429 transport_info->type == FARSIGHT_CANDIDATE_TYPE_DERIVED ? | |
430 "prflx" : | |
431 transport_info->type == FARSIGHT_CANDIDATE_TYPE_RELAY ? | |
432 "relay" : NULL); | |
433 | |
434 } | |
435 farsight_transport_list_destroy(candidates); | |
436 | |
437 return jingle; | |
438 } | |
439 | |
440 xmlnode * | |
441 jabber_jingle_session_create_content_replace(const JingleSession *sess, | |
442 gchar *native_candidate_id, | |
443 gchar *remote_candidate_id) | |
444 { | |
445 xmlnode *jingle = | |
446 jabber_jingle_session_create_jingle_element(sess, "content-replace"); | |
447 xmlnode *content = NULL; | |
448 xmlnode *transport = NULL; | |
449 xmlnode *candidate = NULL; | |
450 xmlnode *description = NULL; | |
451 xmlnode *payload_type = NULL; | |
452 char local_port[8]; | |
453 char remote_port[8]; | |
454 char prio[8]; | |
455 char component[8]; | |
456 | |
457 purple_debug_info("jingle", "creating content-modify for native candidate %s " \ | |
458 ", remote candidate %s\n", native_candidate_id, | |
459 remote_candidate_id); | |
460 | |
461 /* It seems the ID's we get from the Farsight callback is phony... */ | |
462 /* | |
463 GList *native_candidates = | |
464 farsight_stream_get_native_candidate(jabber_jingle_session_get_stream(sess), | |
465 native_candidate_id); | |
466 purple_debug_info("jingle", "found %d native candidates with id %s\n", | |
467 g_list_length(native_candidates), native_candidate_id); | |
468 GList *remote_candidates = | |
469 jabber_jingle_session_get_remote_candidate(sess, remote_candidate_id); | |
470 */ | |
471 | |
472 /* we assume lists have length == 1, I think they must... */ | |
473 /* | |
474 FarsightTransportInfo *native = | |
475 (FarsightTransportInfo *) native_candidates->data; | |
476 FarsightTransportInfo *remote = | |
477 (FarsightTransportInfo *) remote_candidates->data; | |
478 */ | |
479 | |
480 content = xmlnode_new_child(jingle, "content"); | |
481 xmlnode_set_attrib(content, "creator", "initiator"); | |
482 xmlnode_set_attrib(content, "name", "audio-content"); | |
483 xmlnode_set_attrib(content, "profile", "RTP/AVP"); | |
484 | |
485 description = xmlnode_new_child(content, "description"); | |
486 xmlnode_set_namespace(description, "urn:xmpp:tmp:jingle:apps:audio-rtp"); | |
487 | |
488 payload_type = xmlnode_new_child(description, "payload-type"); | |
489 /* get top codec from codec_intersection to put here... */ | |
490 /* later on this should probably handle changing codec */ | |
491 | |
492 /* Skip creating the actual "content" element for now, since we don't | |
493 get enough info in the Farsight callback */ | |
494 #if 0 | |
495 transport = xmlnode_new_child(content, "transport"); | |
496 xmlnode_set_namespace(transport, "urn:xmpp:tmp:jingle:transports:ice-tcp"); | |
497 | |
498 candidate = xmlnode_new_child(transport, "candidate"); | |
499 | |
500 g_snprintf(local_port, sizeof(local_port), "%d", native->port); | |
501 g_snprintf(remote_port, sizeof(remote_port), "%d", remote->port); | |
502 g_snprintf(prio, sizeof(prio), "%d", | |
503 jabber_jingle_get_priority(native->type, 0)); | |
504 g_snprintf(component, sizeof(component), "%d", native->component); | |
505 | |
506 xmlnode_set_attrib(candidate, "component", component); | |
507 xmlnode_set_attrib(candidate, "foundation", "1"); /* what about this? */ | |
508 xmlnode_set_attrib(candidate, "generation", "0"); /* ? */ | |
509 xmlnode_set_attrib(candidate, "ip", native->ip); | |
510 xmlnode_set_attrib(candidate, "network", "1"); /* ? */ | |
511 xmlnode_set_attrib(candidate, "port", local_port); | |
512 xmlnode_set_attrib(candidate, "priority", prio); /* Is this correct? */ | |
513 xmlnode_set_attrib(candidate, "protocol", | |
514 native->proto == FARSIGHT_NETWORK_PROTOCOL_UDP ? | |
515 "udp" : "tcp"); | |
516 if (native->username) | |
517 xmlnode_set_attrib(candidate, "ufrag", native->username); | |
518 if (native->password) | |
519 xmlnode_set_attrib(candidate, "pwd", native->password); | |
520 | |
521 xmlnode_set_attrib(candidate, "type", | |
522 native->type == FARSIGHT_CANDIDATE_TYPE_LOCAL ? | |
523 "host" : | |
524 native->type == FARSIGHT_CANDIDATE_TYPE_DERIVED ? | |
525 "prflx" : | |
526 native->type == FARSIGHT_CANDIDATE_TYPE_RELAY ? | |
527 "relay" : NULL); | |
528 /* relay */ | |
529 if (native->type == FARSIGHT_CANDIDATE_TYPE_RELAY) { | |
530 /* set rel-addr and rel-port? How? */ | |
531 } | |
532 | |
533 xmlnode_set_attrib(candidate, "rem-addr", remote->ip); | |
534 xmlnode_set_attrib(candidate, "rem-port", remote_port); | |
535 | |
536 farsight_transport_list_destroy(native_candidates); | |
537 farsight_transport_list_destroy(remote_candidates); | |
538 | |
539 #endif /* 0 */ | |
540 | |
541 purple_debug_info("jingle", "End create content modify\n"); | |
542 | |
543 return jingle; | |
544 } | |
545 | |
546 xmlnode * | |
547 jabber_jingle_session_create_content_accept(const JingleSession *sess) | |
548 { | |
549 xmlnode *jingle = | |
550 jabber_jingle_session_create_jingle_element(sess, "content-accept"); | |
551 | |
552 xmlnode *content = xmlnode_new_child(jingle, "content"); | |
553 xmlnode *description = jabber_jingle_session_create_description(sess); | |
554 | |
555 xmlnode_set_attrib(content, "creator", "initiator"); | |
556 xmlnode_set_attrib(content, "name", "audio-content"); | |
557 xmlnode_set_attrib(content, "profile", "RTP/AVP"); | |
558 | |
559 xmlnode_insert_child(jingle, description); | |
560 | |
561 return jingle; | |
562 } | |
563 | |
564 void | |
565 jabber_jingle_session_set_remote_codecs(JingleSession *sess, GList *codecs) | |
566 { | |
567 if (sess->remote_codecs) { | |
568 farsight_codec_list_destroy(sess->remote_codecs); | |
569 } | |
570 sess->remote_codecs = codecs; | |
571 } | |
572 | |
573 GList * | |
574 jabber_jingle_session_get_remote_codecs(const JingleSession *sess) | |
575 { | |
576 return sess->remote_codecs; | |
577 } | |
578 | |
579 #endif /* USE_FARSIGHT */ |