6 * Purple is the legal property of its developers, whose names are too numerous
7 * to list here. Please refer to the COPYRIGHT file distributed with this
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
26 #include "glibcompat.h"
32 #include "google/google_p2p.h"
34 #include "mediamanager.h"
54 static JingleContent
*jingle_rtp_parse_internal(PurpleXmlNode
*rtp
);
55 static PurpleXmlNode
*jingle_rtp_to_xml_internal(JingleContent
*rtp
, PurpleXmlNode
*content
, JingleActionType action
);
56 static void jingle_rtp_handle_action_internal(JingleContent
*content
, PurpleXmlNode
*jingle
, JingleActionType action
);
58 static PurpleMedia
*jingle_rtp_get_media(JingleSession
*session
);
67 static GParamSpec
*properties
[PROP_LAST
];
69 G_DEFINE_DYNAMIC_TYPE_EXTENDED(
74 G_ADD_PRIVATE_DYNAMIC(JingleRtp
)
77 /******************************************************************************
79 *****************************************************************************/
80 static JingleTransport
*
81 jingle_rtp_candidates_to_transport(JingleSession
*session
, const gchar
*type
, guint generation
, GList
*candidates
)
83 JingleTransport
*transport
;
85 transport
= jingle_transport_create(type
);
89 for (; candidates
; candidates
= g_list_next(candidates
)) {
90 PurpleMediaCandidate
*candidate
= candidates
->data
;
91 gchar
*id
= jabber_get_next_id(jingle_session_get_js(session
));
92 jingle_transport_add_local_candidate(transport
, id
, generation
, candidate
);
99 static void jingle_rtp_ready(JingleSession
*session
);
102 jingle_rtp_candidates_prepared_cb(PurpleMedia
*media
,
103 gchar
*sid
, gchar
*name
, JingleSession
*session
)
105 JingleContent
*content
= jingle_session_find_content(
107 JingleTransport
*oldtransport
, *transport
;
110 purple_debug_info("jingle-rtp", "jingle_rtp_candidates_prepared_cb\n");
112 if (content
== NULL
) {
113 purple_debug_error("jingle-rtp",
114 "jingle_rtp_candidates_prepared_cb: "
115 "Can't find session %s\n", sid
);
119 oldtransport
= jingle_content_get_transport(content
);
120 candidates
= purple_media_get_local_candidates(media
, sid
, name
);
121 transport
= jingle_rtp_candidates_to_transport(
122 session
, jingle_transport_get_transport_type(oldtransport
),
125 g_list_free(candidates
);
126 g_object_unref(oldtransport
);
128 jingle_content_set_pending_transport(content
, transport
);
129 jingle_content_accept_transport(content
);
131 jingle_rtp_ready(session
);
135 jingle_rtp_codecs_changed_cb(PurpleMedia
*media
, gchar
*sid
,
136 JingleSession
*session
)
138 purple_debug_info("jingle-rtp", "jingle_rtp_codecs_changed_cb: "
139 "session_id: %s jingle_session: %p\n", sid
, session
);
140 jingle_rtp_ready(session
);
144 jingle_rtp_new_candidate_cb(PurpleMedia
*media
, gchar
*sid
, gchar
*name
, PurpleMediaCandidate
*candidate
, JingleSession
*session
)
146 JingleContent
*content
= jingle_session_find_content(session
, sid
, NULL
);
147 JingleTransport
*transport
;
150 purple_debug_info("jingle-rtp", "jingle_rtp_new_candidate_cb\n");
152 if (content
== NULL
) {
153 purple_debug_error("jingle-rtp",
154 "jingle_rtp_new_candidate_cb: "
155 "Can't find session %s\n", sid
);
159 transport
= jingle_content_get_transport(content
);
161 id
= jabber_get_next_id(jingle_session_get_js(session
));
162 jingle_transport_add_local_candidate(transport
, id
, 1, candidate
);
165 g_object_unref(transport
);
167 jabber_iq_send(jingle_session_to_packet(session
, JINGLE_TRANSPORT_INFO
));
171 jingle_rtp_initiate_ack_cb(JabberStream
*js
, const char *from
,
172 JabberIqType type
, const char *id
,
173 PurpleXmlNode
*packet
, gpointer data
)
175 JingleSession
*session
= data
;
177 if (type
== JABBER_IQ_ERROR
|| purple_xmlnode_get_child(packet
, "error")) {
178 purple_media_end(jingle_rtp_get_media(session
), NULL
, NULL
);
179 g_object_unref(session
);
185 jingle_rtp_state_changed_cb(PurpleMedia
*media
, PurpleMediaState state
,
186 gchar
*sid
, gchar
*name
, JingleSession
*session
)
188 purple_debug_info("jingle-rtp", "state-changed: state %d "
189 "id: %s name: %s\n", state
, sid
? sid
: "(null)",
190 name
? name
: "(null)");
194 jingle_rtp_stream_info_cb(PurpleMedia
*media
, PurpleMediaInfoType type
,
195 gchar
*sid
, gchar
*name
, gboolean local
,
196 JingleSession
*session
)
198 purple_debug_info("jingle-rtp", "stream-info: type %d "
199 "id: %s name: %s\n", type
, sid
? sid
: "(null)",
200 name
? name
: "(null)");
202 g_return_if_fail(JINGLE_IS_SESSION(session
));
204 if (type
== PURPLE_MEDIA_INFO_HANGUP
||
205 type
== PURPLE_MEDIA_INFO_REJECT
) {
206 jabber_iq_send(jingle_session_terminate_packet(
207 session
, type
== PURPLE_MEDIA_INFO_HANGUP
?
208 "success" : "decline"));
210 g_signal_handlers_disconnect_by_func(G_OBJECT(media
),
211 G_CALLBACK(jingle_rtp_state_changed_cb
),
213 g_signal_handlers_disconnect_by_func(G_OBJECT(media
),
214 G_CALLBACK(jingle_rtp_stream_info_cb
),
216 g_signal_handlers_disconnect_by_func(G_OBJECT(media
),
217 G_CALLBACK(jingle_rtp_new_candidate_cb
),
220 g_object_unref(session
);
221 } else if (type
== PURPLE_MEDIA_INFO_ACCEPT
&&
222 jingle_session_is_initiator(session
) == FALSE
) {
223 jingle_rtp_ready(session
);
228 jingle_rtp_ready(JingleSession
*session
)
230 PurpleMedia
*media
= jingle_rtp_get_media(session
);
232 if (purple_media_candidates_prepared(media
, NULL
, NULL
) &&
233 purple_media_codecs_ready(media
, NULL
) &&
234 (jingle_session_is_initiator(session
) == TRUE
||
235 purple_media_accepted(media
, NULL
, NULL
))) {
236 if (jingle_session_is_initiator(session
)) {
237 JabberIq
*iq
= jingle_session_to_packet(
238 session
, JINGLE_SESSION_INITIATE
);
239 jabber_iq_set_callback(iq
,
240 jingle_rtp_initiate_ack_cb
, session
);
243 jabber_iq_send(jingle_session_to_packet(session
,
244 JINGLE_SESSION_ACCEPT
));
247 g_signal_handlers_disconnect_by_func(G_OBJECT(media
),
248 G_CALLBACK(jingle_rtp_candidates_prepared_cb
),
250 g_signal_handlers_disconnect_by_func(G_OBJECT(media
),
251 G_CALLBACK(jingle_rtp_codecs_changed_cb
),
253 g_signal_connect(G_OBJECT(media
), "new-candidate",
254 G_CALLBACK(jingle_rtp_new_candidate_cb
),
260 jingle_rtp_create_media(JingleContent
*content
)
262 JingleSession
*session
= jingle_content_get_session(content
);
263 JabberStream
*js
= jingle_session_get_js(session
);
264 gchar
*remote_jid
= jingle_session_get_remote_jid(session
);
266 PurpleMedia
*media
= purple_media_manager_create_media(
267 purple_media_manager_get(),
268 purple_connection_get_account(js
->gc
),
269 "fsrtpconference", remote_jid
,
270 jingle_session_is_initiator(session
));
274 purple_debug_error("jingle-rtp", "Couldn't create media session\n");
278 purple_media_set_protocol_data(media
, session
);
280 /* connect callbacks */
281 g_signal_connect(G_OBJECT(media
), "candidates-prepared",
282 G_CALLBACK(jingle_rtp_candidates_prepared_cb
), session
);
283 g_signal_connect(G_OBJECT(media
), "codecs-changed",
284 G_CALLBACK(jingle_rtp_codecs_changed_cb
), session
);
285 g_signal_connect(G_OBJECT(media
), "state-changed",
286 G_CALLBACK(jingle_rtp_state_changed_cb
), session
);
287 g_signal_connect(G_OBJECT(media
), "stream-info",
288 G_CALLBACK(jingle_rtp_stream_info_cb
), session
);
290 g_object_unref(session
);
295 jingle_rtp_init_media(JingleContent
*content
)
297 JingleSession
*session
= jingle_content_get_session(content
);
298 PurpleMedia
*media
= jingle_rtp_get_media(session
);
304 const gchar
*transmitter
;
307 PurpleMediaSessionType type
;
308 JingleTransport
*transport
;
309 GParameter
*params
= NULL
;
312 /* maybe this create ought to just be in initiate and handle initiate */
314 media
= jingle_rtp_create_media(content
);
320 media_type
= jingle_rtp_get_media_type(content
);
321 if (media_type
== NULL
) {
322 g_object_unref(session
);
326 name
= jingle_content_get_name(content
);
327 remote_jid
= jingle_session_get_remote_jid(session
);
328 senders
= jingle_content_get_senders(content
);
329 transport
= jingle_content_get_transport(content
);
331 if (JINGLE_IS_RAWUDP(transport
))
332 transmitter
= "rawudp";
333 else if (JINGLE_IS_ICEUDP(transport
))
334 transmitter
= "nice";
335 else if (JINGLE_IS_GOOGLE_P2P(transport
))
336 transmitter
= "nice";
338 transmitter
= "notransmitter";
339 g_object_unref(transport
);
341 is_audio
= purple_strequal(media_type
, "audio");
343 if (purple_strequal(senders
, "both"))
344 type
= is_audio
? PURPLE_MEDIA_AUDIO
345 : PURPLE_MEDIA_VIDEO
;
346 else if (purple_strequal(senders
, "initiator") ==
347 jingle_session_is_initiator(session
))
348 type
= is_audio
? PURPLE_MEDIA_SEND_AUDIO
349 : PURPLE_MEDIA_SEND_VIDEO
;
351 type
= is_audio
? PURPLE_MEDIA_RECV_AUDIO
352 : PURPLE_MEDIA_RECV_VIDEO
;
355 jingle_get_params(jingle_session_get_js(session
), NULL
, 0, 0, 0,
356 NULL
, NULL
, &num_params
);
358 creator
= jingle_content_get_creator(content
);
359 if (creator
== NULL
) {
365 g_object_unref(session
);
369 if (purple_strequal(creator
, "initiator"))
370 is_creator
= jingle_session_is_initiator(session
);
372 is_creator
= !jingle_session_is_initiator(session
);
375 if(!purple_media_add_stream(media
, name
, remote_jid
,
376 type
, is_creator
, transmitter
, num_params
, params
)) {
377 purple_media_end(media
, NULL
, NULL
);
378 /* TODO: How much clean-up is necessary here? (does calling
379 purple_media_end lead to cleaning up Jingle structs?) */
388 g_object_unref(session
);
394 jingle_rtp_parse_codecs(PurpleXmlNode
*description
)
396 GList
*codecs
= NULL
;
397 PurpleXmlNode
*codec_element
= NULL
;
398 const char *encoding_name
,*id
, *clock_rate
;
399 PurpleMediaCodec
*codec
;
400 const gchar
*media
= purple_xmlnode_get_attrib(description
, "media");
401 PurpleMediaSessionType type
;
404 purple_debug_warning("jingle-rtp", "missing media type\n");
408 if (purple_strequal(media
, "video")) {
409 type
= PURPLE_MEDIA_VIDEO
;
410 } else if (purple_strequal(media
, "audio")) {
411 type
= PURPLE_MEDIA_AUDIO
;
413 purple_debug_warning("jingle-rtp", "unknown media type: %s\n",
418 for (codec_element
= purple_xmlnode_get_child(description
, "payload-type") ;
420 codec_element
= purple_xmlnode_get_next_twin(codec_element
)) {
421 PurpleXmlNode
*param
;
423 encoding_name
= purple_xmlnode_get_attrib(codec_element
, "name");
425 id
= purple_xmlnode_get_attrib(codec_element
, "id");
426 clock_rate
= purple_xmlnode_get_attrib(codec_element
, "clockrate");
428 codec
= purple_media_codec_new(atoi(id
), encoding_name
,
430 clock_rate
? atoi(clock_rate
) : 0);
432 for (param
= purple_xmlnode_get_child(codec_element
, "parameter");
433 param
; param
= purple_xmlnode_get_next_twin(param
)) {
434 purple_media_codec_add_optional_parameter(codec
,
435 purple_xmlnode_get_attrib(param
, "name"),
436 purple_xmlnode_get_attrib(param
, "value"));
439 codec_str
= purple_media_codec_to_string(codec
);
440 purple_debug_info("jingle-rtp", "received codec: %s\n", codec_str
);
443 codecs
= g_list_append(codecs
, codec
);
449 jingle_rtp_add_payloads(PurpleXmlNode
*description
, GList
*codecs
)
451 for (; codecs
; codecs
= codecs
->next
) {
452 PurpleMediaCodec
*codec
= (PurpleMediaCodec
*)codecs
->data
;
453 GList
*iter
= purple_media_codec_get_optional_parameters(codec
);
454 gchar
*id
, *name
, *clockrate
, *channels
;
456 PurpleXmlNode
*payload
= purple_xmlnode_new_child(description
, "payload-type");
458 id
= g_strdup_printf("%d",
459 purple_media_codec_get_id(codec
));
460 name
= purple_media_codec_get_encoding_name(codec
);
461 clockrate
= g_strdup_printf("%d",
462 purple_media_codec_get_clock_rate(codec
));
463 channels
= g_strdup_printf("%d",
464 purple_media_codec_get_channels(codec
));
466 purple_xmlnode_set_attrib(payload
, "name", name
);
467 purple_xmlnode_set_attrib(payload
, "id", id
);
468 purple_xmlnode_set_attrib(payload
, "clockrate", clockrate
);
469 purple_xmlnode_set_attrib(payload
, "channels", channels
);
476 for (; iter
; iter
= g_list_next(iter
)) {
477 PurpleKeyValuePair
*mparam
= iter
->data
;
478 PurpleXmlNode
*param
= purple_xmlnode_new_child(payload
, "parameter");
479 purple_xmlnode_set_attrib(param
, "name", mparam
->key
);
480 purple_xmlnode_set_attrib(param
, "value", mparam
->value
);
483 codec_str
= purple_media_codec_to_string(codec
);
484 purple_debug_info("jingle", "adding codec: %s\n", codec_str
);
489 /******************************************************************************
490 * JingleContent Implementation
491 *****************************************************************************/
492 static PurpleXmlNode
*
493 jingle_rtp_to_xml_internal(JingleContent
*rtp
, PurpleXmlNode
*content
, JingleActionType action
)
495 PurpleXmlNode
*node
= JINGLE_CONTENT_CLASS(jingle_rtp_parent_class
)->to_xml(rtp
, content
, action
);
496 PurpleXmlNode
*description
= purple_xmlnode_get_child(node
, "description");
497 if (description
!= NULL
) {
498 JingleSession
*session
= jingle_content_get_session(rtp
);
499 PurpleMedia
*media
= jingle_rtp_get_media(session
);
500 gchar
*media_type
= jingle_rtp_get_media_type(rtp
);
501 gchar
*ssrc
= jingle_rtp_get_ssrc(rtp
);
502 gchar
*name
= jingle_content_get_name(rtp
);
503 GList
*codecs
= purple_media_get_codecs(media
, name
);
505 purple_xmlnode_set_attrib(description
, "media", media_type
);
508 purple_xmlnode_set_attrib(description
, "ssrc", ssrc
);
512 g_object_unref(session
);
514 jingle_rtp_add_payloads(description
, codecs
);
515 purple_media_codec_list_free(codecs
);
520 static JingleContent
*
521 jingle_rtp_parse_internal(PurpleXmlNode
*rtp
)
523 JingleContent
*content
= JINGLE_CONTENT_CLASS(jingle_rtp_parent_class
)->parse(rtp
);
524 PurpleXmlNode
*description
= purple_xmlnode_get_child(rtp
, "description");
525 const gchar
*media_type
= purple_xmlnode_get_attrib(description
, "media");
526 const gchar
*ssrc
= purple_xmlnode_get_attrib(description
, "ssrc");
527 purple_debug_info("jingle-rtp", "rtp parse\n");
528 g_object_set(content
, "media-type", media_type
, NULL
);
530 g_object_set(content
, "ssrc", ssrc
, NULL
);
535 jingle_rtp_handle_action_internal(JingleContent
*content
, PurpleXmlNode
*xmlcontent
, JingleActionType action
)
538 case JINGLE_SESSION_ACCEPT
:
539 case JINGLE_SESSION_INITIATE
: {
540 JingleSession
*session
;
541 JingleTransport
*transport
;
542 PurpleXmlNode
*description
;
549 session
= jingle_content_get_session(content
);
551 if (action
== JINGLE_SESSION_INITIATE
&&
552 !jingle_rtp_init_media(content
)) {
553 /* XXX: send error */
554 jabber_iq_send(jingle_session_terminate_packet(
555 session
, "general-error"));
556 g_object_unref(session
);
560 transport
= jingle_transport_parse(
561 purple_xmlnode_get_child(xmlcontent
, "transport"));
562 description
= purple_xmlnode_get_child(xmlcontent
, "description");
563 candidates
= jingle_transport_get_remote_candidates(transport
);
564 codecs
= jingle_rtp_parse_codecs(description
);
565 name
= jingle_content_get_name(content
);
566 remote_jid
= jingle_session_get_remote_jid(session
);
568 media
= jingle_rtp_get_media(session
);
569 purple_media_set_remote_codecs(media
,
570 name
, remote_jid
, codecs
);
571 purple_media_add_remote_candidates(media
,
572 name
, remote_jid
, candidates
);
574 if (action
== JINGLE_SESSION_ACCEPT
)
575 purple_media_stream_info(media
,
576 PURPLE_MEDIA_INFO_ACCEPT
,
577 name
, remote_jid
, FALSE
);
581 g_object_unref(session
);
584 case JINGLE_SESSION_TERMINATE
: {
585 JingleSession
*session
= jingle_content_get_session(content
);
586 PurpleMedia
*media
= jingle_rtp_get_media(session
);
589 purple_media_end(media
, NULL
, NULL
);
592 g_object_unref(session
);
595 case JINGLE_TRANSPORT_INFO
: {
596 JingleSession
*session
= jingle_content_get_session(content
);
597 JingleTransport
*transport
= jingle_transport_parse(
598 purple_xmlnode_get_child(xmlcontent
, "transport"));
599 GList
*candidates
= jingle_transport_get_remote_candidates(transport
);
600 gchar
*name
= jingle_content_get_name(content
);
602 jingle_session_get_remote_jid(session
);
604 purple_media_add_remote_candidates(
605 jingle_rtp_get_media(session
),
606 name
, remote_jid
, candidates
);
610 g_object_unref(session
);
613 case JINGLE_DESCRIPTION_INFO
: {
614 JingleSession
*session
=
615 jingle_content_get_session(content
);
616 PurpleXmlNode
*description
= purple_xmlnode_get_child(
617 xmlcontent
, "description");
618 GList
*codecs
, *iter
, *iter2
, *remote_codecs
=
619 jingle_rtp_parse_codecs(description
);
620 gchar
*name
= jingle_content_get_name(content
);
622 jingle_session_get_remote_jid(session
);
625 media
= jingle_rtp_get_media(session
);
628 * This may have problems if description-info is
629 * received without the optional parameters for a
630 * codec with configuration info (such as THEORA
631 * or H264). The local configuration info may be
632 * set for the remote codec.
634 * As of 2.6.3 there's no API to support getting
635 * the remote codecs specifically, just the
636 * intersection. Another option may be to cache
637 * the remote codecs received in initiate/accept.
639 codecs
= purple_media_get_codecs(media
, name
);
641 for (iter
= codecs
; iter
; iter
= g_list_next(iter
)) {
644 id
= purple_media_codec_get_id(iter
->data
);
645 iter2
= remote_codecs
;
647 for (; iter2
; iter2
= g_list_next(iter2
)) {
648 if (purple_media_codec_get_id(
652 g_object_unref(iter
->data
);
653 iter
->data
= iter2
->data
;
654 remote_codecs
= g_list_delete_link(
655 remote_codecs
, iter2
);
660 codecs
= g_list_concat(codecs
, remote_codecs
);
662 purple_media_set_remote_codecs(media
,
663 name
, remote_jid
, codecs
);
665 purple_media_codec_list_free (codecs
);
668 g_object_unref(session
);
677 /******************************************************************************
679 *****************************************************************************/
681 jingle_rtp_init (JingleRtp
*rtp
)
686 jingle_rtp_finalize (GObject
*rtp
)
688 JingleRtpPrivate
*priv
= jingle_rtp_get_instance_private(JINGLE_RTP(rtp
));
689 purple_debug_info("jingle-rtp","jingle_rtp_finalize\n");
691 g_free(priv
->media_type
);
694 G_OBJECT_CLASS(jingle_rtp_parent_class
)->finalize(rtp
);
698 jingle_rtp_set_property (GObject
*object
, guint prop_id
, const GValue
*value
, GParamSpec
*pspec
)
700 JingleRtp
*rtp
= JINGLE_RTP(object
);
701 JingleRtpPrivate
*priv
= jingle_rtp_get_instance_private(rtp
);
704 case PROP_MEDIA_TYPE
:
705 g_free(priv
->media_type
);
706 priv
->media_type
= g_value_dup_string(value
);
710 priv
->ssrc
= g_value_dup_string(value
);
713 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
719 jingle_rtp_get_property (GObject
*object
, guint prop_id
, GValue
*value
, GParamSpec
*pspec
)
721 JingleRtp
*rtp
= JINGLE_RTP(object
);
722 JingleRtpPrivate
*priv
= jingle_rtp_get_instance_private(rtp
);
725 case PROP_MEDIA_TYPE
:
726 g_value_set_string(value
, priv
->media_type
);
729 g_value_set_string(value
, priv
->ssrc
);
732 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
739 jingle_rtp_class_finalize(JingleRtpClass
*klass
) {
743 jingle_rtp_class_init (JingleRtpClass
*klass
)
745 GObjectClass
*obj_class
= G_OBJECT_CLASS(klass
);
746 JingleContentClass
*content_class
= JINGLE_CONTENT_CLASS(klass
);
748 obj_class
->finalize
= jingle_rtp_finalize
;
749 obj_class
->set_property
= jingle_rtp_set_property
;
750 obj_class
->get_property
= jingle_rtp_get_property
;
752 content_class
->to_xml
= jingle_rtp_to_xml_internal
;
753 content_class
->parse
= jingle_rtp_parse_internal
;
754 content_class
->description_type
= JINGLE_APP_RTP
;
755 content_class
->handle_action
= jingle_rtp_handle_action_internal
;
757 properties
[PROP_MEDIA_TYPE
] = g_param_spec_string("media-type",
759 "The media type (\"audio\" or \"video\") for this rtp session.",
761 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
763 properties
[PROP_SSRC
] = g_param_spec_string("ssrc",
765 "The ssrc for this rtp session.",
767 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
769 g_object_class_install_properties(obj_class
, PROP_LAST
, properties
);
772 /******************************************************************************
774 *****************************************************************************/
776 jingle_rtp_register(PurplePlugin
*plugin
) {
777 jingle_rtp_register_type(G_TYPE_MODULE(plugin
));
781 jingle_rtp_get_media_type(JingleContent
*content
)
784 g_object_get(content
, "media-type", &media_type
, NULL
);
789 jingle_rtp_get_ssrc(JingleContent
*content
)
792 g_object_get(content
, "ssrc", &ssrc
, NULL
);
797 jingle_rtp_get_media(JingleSession
*session
)
799 JabberStream
*js
= jingle_session_get_js(session
);
800 PurpleMedia
*media
= NULL
;
801 GList
*iter
= purple_media_manager_get_media_by_account(
802 purple_media_manager_get(),
803 purple_connection_get_account(js
->gc
));
805 for (; iter
; iter
= g_list_delete_link(iter
, iter
)) {
806 JingleSession
*media_session
=
807 purple_media_get_protocol_data(iter
->data
);
808 if (media_session
== session
) {
820 jingle_rtp_initiate_media(JabberStream
*js
, const gchar
*who
,
821 PurpleMediaSessionType type
)
823 /* create content negotiation */
824 JingleSession
*session
;
825 JingleContent
*content
;
826 JingleTransport
*transport
;
828 JabberBuddyResource
*jbr
;
829 gboolean ret
= FALSE
;
830 const gchar
*transport_type
;
832 gchar
*resource
= NULL
, *me
= NULL
, *sid
= NULL
;
834 /* construct JID to send to */
835 jb
= jabber_buddy_find(js
, who
, FALSE
);
837 purple_debug_error("jingle-rtp", "Could not find Jabber buddy\n");
841 resource
= jabber_get_resource(who
);
842 jbr
= jabber_buddy_find_resource(jb
, resource
);
845 purple_debug_error("jingle-rtp", "Could not find buddy's resource - %s\n", resource
);
849 if (jabber_resource_has_capability(jbr
, JINGLE_TRANSPORT_ICEUDP
)) {
850 transport_type
= JINGLE_TRANSPORT_ICEUDP
;
851 } else if (jabber_resource_has_capability(jbr
, JINGLE_TRANSPORT_RAWUDP
)) {
852 transport_type
= JINGLE_TRANSPORT_RAWUDP
;
853 } else if (jabber_resource_has_capability(jbr
, NS_GOOGLE_TRANSPORT_P2P
)) {
854 transport_type
= NS_GOOGLE_TRANSPORT_P2P
;
856 purple_debug_error("jingle-rtp", "Resource doesn't support "
857 "the same transport types\n");
861 /* set ourselves as initiator */
862 me
= g_strdup_printf("%s@%s/%s", js
->user
->node
, js
->user
->domain
, js
->user
->resource
);
864 sid
= jabber_get_next_id(js
);
865 session
= jingle_session_create(js
, sid
, me
, who
, TRUE
);
868 if (type
& PURPLE_MEDIA_AUDIO
) {
869 JingleRtpPrivate
*priv
= NULL
;
871 transport
= jingle_transport_create(transport_type
);
872 content
= jingle_content_create(JINGLE_APP_RTP
, "initiator",
873 "session", "audio-session", "both", transport
);
875 priv
= jingle_rtp_get_instance_private(JINGLE_RTP(content
));
877 jingle_session_add_content(session
, content
);
878 priv
->media_type
= g_strdup("audio");
879 jingle_rtp_init_media(content
);
880 g_object_notify_by_pspec(G_OBJECT(content
), properties
[PROP_MEDIA_TYPE
]);
882 if (type
& PURPLE_MEDIA_VIDEO
) {
883 JingleRtpPrivate
*priv
= NULL
;
885 transport
= jingle_transport_create(transport_type
);
886 content
= jingle_content_create(JINGLE_APP_RTP
, "initiator",
887 "session", "video-session", "both", transport
);
889 priv
= jingle_rtp_get_instance_private(JINGLE_RTP(content
));
891 jingle_session_add_content(session
, content
);
892 priv
->media_type
= g_strdup("video");
893 jingle_rtp_init_media(content
);
894 g_object_notify_by_pspec(G_OBJECT(content
), properties
[PROP_MEDIA_TYPE
]);
897 if (jingle_rtp_get_media(session
) == NULL
) {
911 jingle_rtp_terminate_session(JabberStream
*js
, const gchar
*who
)
913 JingleSession
*session
;
914 /* XXX: This may cause file transfers and xml sessions to stop as well */
915 session
= jingle_session_find_by_jid(js
, who
);
918 PurpleMedia
*media
= jingle_rtp_get_media(session
);
920 purple_debug_info("jingle-rtp", "hanging up media\n");
921 purple_media_stream_info(media
,
922 PURPLE_MEDIA_INFO_HANGUP
,