6 * Copyright (C) 2010 Jakub Adam <jakub.adam@tieto.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include <libpurple/mediamanager.h>
26 #include "sipe-utils.h"
28 struct _sipe_media_session
{
31 struct sipmsg
*invitation
;
33 typedef struct _sipe_media_session sipe_media_session
;
36 sipe_media_session_free(sipe_media_session
* session
)
39 g_free(session
->with
);
40 sipe_utils_nameval_free(session
->sdp_attrs
);
41 if (session
->invitation
)
42 sipmsg_free(session
->invitation
);
48 sipe_media_parse_remote_codecs(const sipe_media_session
*session
)
54 while ((attr
= sipe_utils_nameval_find_instance(session
->sdp_attrs
, "a", i
++))) {
59 PurpleMediaCodec
*codec
;
61 if (!g_str_has_prefix(attr
, "rtpmap:"))
64 tokens
= g_strsplit_set(attr
+ 7, " /", 3);
67 codec_name
= tokens
[1];
68 clock_rate
= atoi(tokens
[2]);
70 codec
= purple_media_codec_new(id
, codec_name
, PURPLE_MEDIA_AUDIO
, clock_rate
);
71 codecs
= g_list_append(codecs
, codec
);
80 sipe_media_parse_remote_candidates(const sipe_media_session
*session
)
82 PurpleMediaCandidate
*candidate
;
83 GList
*candidates
= NULL
;
85 gchar
**tokens
= g_strsplit(sipe_utils_nameval_find(session
->sdp_attrs
, "o"), " ", 5);
86 gchar
*ip
= g_strdup(tokens
[4]);
91 tokens
= g_strsplit(sipe_utils_nameval_find(session
->sdp_attrs
, "m"), " ", 3);
92 port
= atoi(tokens
[1]);
95 candidate
= purple_media_candidate_new("foundation?",
96 PURPLE_MEDIA_COMPONENT_RTP
,
97 PURPLE_MEDIA_CANDIDATE_TYPE_HOST
,
98 PURPLE_MEDIA_NETWORK_PROTOCOL_UDP
, ip
, port
);
99 candidates
= g_list_append(candidates
, candidate
);
101 candidate
= purple_media_candidate_new("foundation?",
102 PURPLE_MEDIA_COMPONENT_RTCP
,
103 PURPLE_MEDIA_CANDIDATE_TYPE_HOST
,
104 PURPLE_MEDIA_NETWORK_PROTOCOL_UDP
, ip
, port
+ 1);
105 candidates
= g_list_append(candidates
, candidate
);
111 sipe_media_stream_info_cb(PurpleMedia
*media
, PurpleMediaInfoType type
,
112 SIPE_UNUSED_PARAMETER gchar
*sid
, SIPE_UNUSED_PARAMETER gchar
*name
, SIPE_UNUSED_PARAMETER gboolean local
, sipe_media_session
*session
)
114 PurpleAccount
*account
= purple_media_get_account(media
);
116 if (type
== PURPLE_MEDIA_INFO_ACCEPT
) {
117 GList
*codecs
= sipe_media_parse_remote_codecs(session
);
122 purple_media_set_remote_codecs(media
, "sipe-voice", session
->with
, codecs
);
125 purple_media_set_send_codec(media
, "sipe-voice", codecs
->data
);
127 for (; codecs
; codecs
= g_list_delete_link(codecs
, codecs
))
128 g_object_unref(codecs
->data
);
131 candidates
= sipe_media_parse_remote_candidates(session
);
133 purple_media_add_remote_candidates(media
, "sipe-voice", session
->with
, candidates
);
135 for (; candidates
; candidates
= g_list_delete_link(candidates
, candidates
))
136 g_object_unref(candidates
->data
);
139 body
= g_strdup_printf(
141 "o=- 0 0 IN IP4 %s\r\n"
146 "m=audio 6804 RTP/AVP 97 111 101\r\n"
147 "k=base64:oPI/otNCy6dGWwyVOIPzcIX2iSij5RISzLhSd1WZxG0\r\n"
148 "a=rtpmap:97 red/8000\r\n"
149 "a=rtpmap:111 SIREN/16000\r\n"
150 "a=fmtp:111 bitrate=16000\r\n"
151 "a=rtpmap:101 telephone-event/8000\r\n"
152 "a=fmtp:101 0-16\r\n"
153 "a=encryption:optional\r\n",
154 "192.168.1.2", "192.168.1.2");
156 send_sip_response(account
->gc
, session
->invitation
, 200, "OK", body
);
157 sipmsg_free(session
->invitation
);
158 session
->invitation
= NULL
;
161 } else if (type
== PURPLE_MEDIA_INFO_REJECT
) {
162 send_sip_response(account
->gc
, session
->invitation
, 603, "Decline", NULL
);
163 sipe_media_session_free(session
);
168 sipe_media_parse_sdp_frame(gchar
*frame
) {
169 gchar
**lines
= g_strsplit(frame
, "\r\n", 0);
170 GSList
*sdp_attrs
= NULL
;
172 gboolean result
= sipe_utils_parse_lines(&sdp_attrs
, lines
, "=");
175 if (result
== FALSE
) {
176 sipe_utils_nameval_free(sdp_attrs
);
183 void sipe_media_incoming_invite(PurpleAccount
*account
, struct sipmsg
*msg
)
185 struct sipe_account_data
*sip
= account
->gc
->proto_data
;
187 PurpleMediaManager
*manager
= purple_media_manager_get();
190 sipe_media_session
*session
;
192 session
= g_new0(sipe_media_session
, 1);
193 session
->with
= parse_from(sipmsg_find_header(msg
,"From"));
194 session
->sdp_attrs
= sipe_media_parse_sdp_frame(msg
->body
);
195 session
->invitation
= msg
;
197 msg
->dont_free
= TRUE
;
199 media
= purple_media_manager_create_media(manager
, sip
->account
,
200 "fsrtpconference", session
->with
, FALSE
);
202 g_signal_connect(G_OBJECT(media
), "stream-info",
203 G_CALLBACK(sipe_media_stream_info_cb
), session
);
205 purple_media_add_stream(media
, "sipe-voice", session
->with
, PURPLE_MEDIA_AUDIO
,
206 FALSE
, "nice", 0, NULL
);