| 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 |