audio: fixes for call hangup/resume on both local and remote sides
[siplcs.git] / src / purple / purple-media.c
blob659c495f21e010551e6787bf4d6a4cfa5b503f94
1 /**
2 * @file purple-media.c
4 * pidgin-sipe
6 * Copyright (C) 2010 SIPE Project <http://sipe.sourceforge.net/>
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 "glib.h"
25 #include "sipe-core.h"
27 //TODO: these two includes should be eliminated
28 #include "../core/sipe.h"
29 #include "../core/sipe-core-private.h"
31 #include "sipe-common.h"
32 #include "sipe-media.h"
33 #include "mediamanager.h"
34 #include <nice/agent.h>
36 #include "request.h"
37 #include "core-depurple.h"
39 typedef struct _sipe_purple_media {
40 PurpleMedia *m;
41 // Prevent infinite recursion in on_stream_info_cb
42 gboolean in_recursion;
43 } sipe_purple_media;
45 gboolean sipe_initiate_media(PurpleAccount *account, const char *who,
46 SIPE_UNUSED_PARAMETER PurpleMediaSessionType type)
48 struct sipe_account_data *sip = PURPLE_ACCOUNT_TO_SIPE_ACCOUNT_DATA;
49 sipe_media_initiate_call(sip, who);
50 return TRUE;
53 PurpleMediaCaps sipe_get_media_caps(SIPE_UNUSED_PARAMETER PurpleAccount *account,
54 SIPE_UNUSED_PARAMETER const char *who)
56 return PURPLE_MEDIA_CAPS_AUDIO;
59 static PurpleMediaSessionType sipe_media_to_purple(SipeMediaType type);
60 static PurpleMediaCandidateType sipe_candidate_type_to_purple(SipeCandidateType type);
61 static PurpleMediaNetworkProtocol sipe_network_protocol_to_purple(SipeNetworkProtocol proto);
62 static SipeNetworkProtocol purple_network_protocol_to_sipe(PurpleMediaNetworkProtocol proto);
64 static void
65 on_candidates_prepared_cb(SIPE_UNUSED_PARAMETER PurpleMedia *media,
66 SIPE_UNUSED_PARAMETER gchar *sessionid,
67 SIPE_UNUSED_PARAMETER gchar *participant,
68 sipe_media_call *call)
70 if (call->candidates_prepared_cb)
71 call->candidates_prepared_cb(call);
74 static void
75 on_state_changed_cb(SIPE_UNUSED_PARAMETER PurpleMedia *media,
76 PurpleMediaState state,
77 gchar *sessionid,
78 gchar *participant,
79 sipe_media_call *call)
81 printf("sipe_media_state_changed_cb: %d %s %s\n", state, sessionid, participant);
82 if (state == PURPLE_MEDIA_STATE_CONNECTED && call->media_connected_cb)
83 call->media_connected_cb(call);
86 static void
87 on_stream_info_cb(SIPE_UNUSED_PARAMETER PurpleMedia *media,
88 PurpleMediaInfoType type,
89 SIPE_UNUSED_PARAMETER gchar *sessionid,
90 SIPE_UNUSED_PARAMETER gchar *participant,
91 gboolean local, sipe_media_call *call)
93 sipe_purple_media *m = call->media;
94 if (m->in_recursion) {
95 m->in_recursion = FALSE;
96 return;
99 if (type == PURPLE_MEDIA_INFO_ACCEPT && call->call_accept_cb)
100 call->call_accept_cb(call, local);
101 else if (type == PURPLE_MEDIA_INFO_REJECT && call->call_reject_cb)
102 call->call_reject_cb(call, local);
103 else if (type == PURPLE_MEDIA_INFO_HOLD && call->call_hold_cb) {
104 call->call_hold_cb(call, local, TRUE);
105 if (!local) {
106 m->in_recursion = TRUE;
107 purple_media_stream_info(m->m, PURPLE_MEDIA_INFO_HOLD, NULL, NULL, TRUE);
109 } else if (type == PURPLE_MEDIA_INFO_UNHOLD && call->call_hold_cb) {
110 call->call_hold_cb(call, local, FALSE);
111 m->in_recursion = TRUE;
112 if (!call->local_on_hold && !call->remote_on_hold) {
113 purple_media_stream_info(m->m, PURPLE_MEDIA_INFO_UNHOLD, NULL, NULL, TRUE);
114 } else {
115 /* Remote side is still on hold, keep local also held to prevent sending
116 * unnecessary media over network */
117 purple_media_stream_info(m->m, PURPLE_MEDIA_INFO_HOLD, NULL, NULL, TRUE);
119 } else if (type == PURPLE_MEDIA_INFO_HANGUP && call->call_hangup_cb)
120 call->call_hangup_cb(call, local);
123 sipe_media *
124 sipe_backend_media_new(sipe_media_call *call, const gchar* participant, gboolean initiator)
126 sipe_purple_media *m = g_new0(sipe_purple_media, 1);
127 PurpleAccount *acc = call->sip->account;
128 PurpleMediaManager *manager = purple_media_manager_get();
130 m->m = purple_media_manager_create_media(manager, acc, "fsrtpconference",
131 participant, initiator);
133 g_signal_connect(G_OBJECT(m->m), "candidates-prepared",
134 G_CALLBACK(on_candidates_prepared_cb), call);
135 g_signal_connect(G_OBJECT(m->m), "stream-info",
136 G_CALLBACK(on_stream_info_cb), call);
137 g_signal_connect(G_OBJECT(m->m), "state-changed",
138 G_CALLBACK(on_state_changed_cb), call);
140 return (sipe_media *)m;
143 void
144 sipe_backend_media_free(sipe_media *media)
146 sipe_purple_media *m = (sipe_purple_media *)media;
147 purple_media_manager_remove_media(purple_media_manager_get(), m->m);
148 g_free(m);
151 gboolean
152 sipe_backend_media_add_stream(sipe_media *media, const gchar* participant,
153 SipeMediaType type, gboolean use_nice,
154 gboolean initiator)
156 sipe_purple_media *m = (sipe_purple_media *)media;
157 PurpleMediaSessionType prpl_type = sipe_media_to_purple(type);
158 GParameter *params = NULL;
159 guint params_cnt = 0;
160 gchar *transmitter;
162 if (use_nice) {
163 transmitter = "nice";
164 params_cnt = 2;
166 params = g_new0(GParameter, params_cnt);
167 params[0].name = "controlling-mode";
168 g_value_init(&params[0].value, G_TYPE_BOOLEAN);
169 g_value_set_boolean(&params[0].value, initiator);
170 params[1].name = "compatibility-mode";
171 g_value_init(&params[1].value, G_TYPE_UINT);
172 g_value_set_uint(&params[1].value, NICE_COMPATIBILITY_OC2007R2);
173 } else {
174 transmitter = "rawudp";
177 return purple_media_add_stream(m->m, "sipe-voice", participant, prpl_type,
178 initiator, transmitter, params_cnt, params);
181 void
182 sipe_backend_media_add_remote_candidates(sipe_media *media, gchar* participant, GList *candidates)
184 sipe_purple_media *m = (sipe_purple_media *)media;
185 purple_media_add_remote_candidates(m->m, "sipe-voice", participant, candidates);
188 gboolean sipe_backend_media_is_initiator(sipe_media *media, gchar *participant)
190 sipe_purple_media *m = (sipe_purple_media *)media;
191 return purple_media_is_initiator(m->m, "sipe-voice", participant);
194 sipe_codec *
195 sipe_backend_codec_new(int id, const char *name, SipeMediaType type, guint clock_rate)
197 return (sipe_codec *)purple_media_codec_new(id, name,
198 sipe_media_to_purple(type), clock_rate);
201 void
202 sipe_backend_codec_free(sipe_codec *codec)
204 if (codec)
205 g_object_unref(codec);
209 sipe_backend_codec_get_id(sipe_codec *codec)
211 return purple_media_codec_get_id((PurpleMediaCodec *)codec);
214 gchar *
215 sipe_backend_codec_get_name(sipe_codec *codec)
217 return purple_media_codec_get_encoding_name((PurpleMediaCodec *)codec);
220 guint
221 sipe_backend_codec_get_clock_rate(sipe_codec *codec)
223 return purple_media_codec_get_clock_rate((PurpleMediaCodec *)codec);
226 void
227 sipe_backend_codec_add_optional_parameter(sipe_codec *codec,
228 const gchar *name, const gchar *value)
230 purple_media_codec_add_optional_parameter((PurpleMediaCodec *)codec, name, value);
233 GList *
234 sipe_backend_codec_get_optional_parameters(sipe_codec *codec)
236 return purple_media_codec_get_optional_parameters((PurpleMediaCodec *)codec);
239 gboolean
240 sipe_backend_set_remote_codecs(sipe_media_call* call, gchar* participant)
242 sipe_purple_media *m = (sipe_purple_media *)call->media;
243 GList *codecs = call->remote_codecs;
245 return purple_media_set_remote_codecs(m->m, "sipe-voice", participant, codecs);
248 GList*
249 sipe_backend_get_local_codecs(struct _sipe_media_call* call)
251 sipe_purple_media *m = (sipe_purple_media *)call->media;
252 return purple_media_get_codecs(m->m, "sipe-voice");
255 sipe_candidate *
256 sipe_backend_candidate_new(const gchar *foundation, SipeComponentType component,
257 SipeCandidateType type, SipeNetworkProtocol proto,
258 const gchar *ip, guint port)
260 return (sipe_candidate *)purple_media_candidate_new(
261 foundation,
262 component,
263 sipe_candidate_type_to_purple(type),
264 sipe_network_protocol_to_purple(proto),
266 port);
269 void
270 sipe_backend_candidate_free(sipe_candidate *candidate)
272 if (candidate)
273 g_object_unref(candidate);
276 gchar *
277 sipe_backend_candidate_get_username(sipe_candidate *candidate)
279 return purple_media_candidate_get_username((PurpleMediaCandidate*)candidate);
282 gchar *
283 sipe_backend_candidate_get_password(sipe_candidate *candidate)
285 return purple_media_candidate_get_password((PurpleMediaCandidate*)candidate);
288 gchar *
289 sipe_backend_candidate_get_foundation(sipe_candidate *candidate)
291 return purple_media_candidate_get_foundation((PurpleMediaCandidate*)candidate);
294 gchar *
295 sipe_backend_candidate_get_ip(sipe_candidate *candidate)
297 return purple_media_candidate_get_ip((PurpleMediaCandidate*)candidate);
300 guint
301 sipe_backend_candidate_get_port(sipe_candidate *candidate)
303 return purple_media_candidate_get_port((PurpleMediaCandidate*)candidate);
306 guint32
307 sipe_backend_candidate_get_priority(sipe_candidate *candidate)
309 return purple_media_candidate_get_priority((PurpleMediaCandidate*)candidate);
312 void
313 sipe_backend_candidate_set_priority(sipe_candidate *candidate, guint32 priority)
315 g_object_set(candidate, "priority", priority, NULL);
318 SipeComponentType
319 sipe_backend_candidate_get_component_type(sipe_candidate *candidate)
321 return purple_media_candidate_get_component_id((PurpleMediaCandidate*)candidate);
324 SipeCandidateType
325 sipe_backend_candidate_get_type(sipe_candidate *candidate)
327 return purple_media_candidate_get_candidate_type((PurpleMediaCandidate*)candidate);
330 SipeNetworkProtocol
331 sipe_backend_candidate_get_protocol(sipe_candidate *candidate)
333 PurpleMediaNetworkProtocol proto =
334 purple_media_candidate_get_protocol((PurpleMediaCandidate*)candidate);
335 return purple_network_protocol_to_sipe(proto);
338 void
339 sipe_backend_candidate_set_username_and_pwd(sipe_candidate *candidate,
340 const gchar *username,
341 const gchar *password)
343 g_object_set(candidate, "username", username, "password", password, NULL);
346 GList*
347 sipe_backend_get_local_candidates(sipe_media_call* call, gchar* participant)
349 sipe_purple_media *m = (sipe_purple_media *)call->media;
350 return purple_media_get_local_candidates(m->m, "sipe-voice", participant);
353 void
354 sipe_backend_media_hold(sipe_media* media, gboolean local)
356 sipe_purple_media *m = (sipe_purple_media *)media;
357 purple_media_stream_info(m->m, PURPLE_MEDIA_INFO_HOLD, NULL, NULL, local);
360 void
361 sipe_backend_media_unhold(sipe_media* media, gboolean local)
363 sipe_purple_media *m = (sipe_purple_media *)media;
364 purple_media_stream_info(m->m, PURPLE_MEDIA_INFO_UNHOLD, NULL, NULL, local);
367 void
368 sipe_backend_media_hangup(sipe_media* media, gboolean local)
370 sipe_purple_media *m = (sipe_purple_media *)media;
371 purple_media_stream_info(m->m, PURPLE_MEDIA_INFO_HANGUP, NULL, NULL, local);
374 PurpleMediaSessionType sipe_media_to_purple(SipeMediaType type)
376 switch (type) {
377 case SIPE_MEDIA_AUDIO: return PURPLE_MEDIA_AUDIO;
378 case SIPE_MEDIA_VIDEO: return PURPLE_MEDIA_VIDEO;
379 default: return PURPLE_MEDIA_NONE;
383 /*SipeMediaType purple_media_to_sipe(PurpleMediaSessionType type)
385 switch (type) {
386 case PURPLE_MEDIA_AUDIO: return SIPE_MEDIA_AUDIO;
387 case PURPLE_MEDIA_VIDEO: return SIPE_MEDIA_VIDEO;
388 default: return SIPE_MEDIA_AUDIO;
392 static PurpleMediaCandidateType
393 sipe_candidate_type_to_purple(SipeCandidateType type)
395 switch (type) {
396 case SIPE_CANDIDATE_TYPE_HOST: return PURPLE_MEDIA_CANDIDATE_TYPE_HOST;
397 case SIPE_CANDIDATE_TYPE_RELAY: return PURPLE_MEDIA_CANDIDATE_TYPE_RELAY;
398 case SIPE_CANDIDATE_TYPE_SRFLX: return PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX;
399 default: return PURPLE_MEDIA_CANDIDATE_TYPE_HOST;
403 static PurpleMediaNetworkProtocol
404 sipe_network_protocol_to_purple(SipeNetworkProtocol proto)
406 switch (proto) {
407 case SIPE_NETWORK_PROTOCOL_TCP: return PURPLE_MEDIA_NETWORK_PROTOCOL_TCP;
408 case SIPE_NETWORK_PROTOCOL_UDP: return PURPLE_MEDIA_NETWORK_PROTOCOL_UDP;
409 default: return PURPLE_MEDIA_NETWORK_PROTOCOL_TCP;
413 static SipeNetworkProtocol
414 purple_network_protocol_to_sipe(PurpleMediaNetworkProtocol proto)
416 switch (proto) {
417 case PURPLE_MEDIA_NETWORK_PROTOCOL_TCP: return SIPE_NETWORK_PROTOCOL_TCP;
418 case PURPLE_MEDIA_NETWORK_PROTOCOL_UDP: return SIPE_NETWORK_PROTOCOL_UDP;
419 default: return SIPE_NETWORK_PROTOCOL_UDP;
424 void sipe_media_error_cb(SIPE_UNUSED_PARAMETER PurpleMedia *media, gchar* error, SIPE_UNUSED_PARAMETER struct sipe_account_data *sip)
426 printf("sipe_media_error_cb: %s\n", error);
429 void sipe_media_codecs_changed_cb(SIPE_UNUSED_PARAMETER PurpleMedia *media, gchar* codec, SIPE_UNUSED_PARAMETER struct sipe_account_data *sip)
431 printf("sipe_media_codecs_changed_cb: %s\n", codec);
434 void sipe_media_level_cb(SIPE_UNUSED_PARAMETER PurpleMedia *media, gchar* sessionid, gchar* participant, gdouble percent, SIPE_UNUSED_PARAMETER struct sipe_account_data *sip)
436 printf("sipe_media_level_cb: %s %s %f\n", sessionid, participant, percent);
439 void sipe_media_new_candidate_cb(SIPE_UNUSED_PARAMETER PurpleMedia *media, gchar* sessionid, gchar* cname, PurpleMediaCandidate *candidate, SIPE_UNUSED_PARAMETER struct sipe_account_data *sip)
441 printf("sipe_media_new_candidate_cb: %s cname: %s %s %d\n", sessionid, cname,
442 purple_media_candidate_get_ip(candidate),
443 purple_media_candidate_get_port(candidate));
446 void sipe_media_state_changed_cb(SIPE_UNUSED_PARAMETER PurpleMedia *media, PurpleMediaState state, gchar* sessionid, gchar* participant, SIPE_UNUSED_PARAMETER struct sipe_account_data *sip)
448 printf("sipe_media_state_changed_cb: %d %s %s\n", state, sessionid, participant);
451 g_signal_connect(G_OBJECT(media), "error", G_CALLBACK(sipe_media_error_cb), call);
452 g_signal_connect(G_OBJECT(media), "codecs-changed", G_CALLBACK(sipe_media_codecs_changed_cb), call);
453 g_signal_connect(G_OBJECT(media), "level", G_CALLBACK(sipe_media_level_cb), call);
454 g_signal_connect(G_OBJECT(media), "new-candidate", G_CALLBACK(sipe_media_new_candidate_cb), call);
455 g_signal_connect(G_OBJECT(media), "state-changed", G_CALLBACK(sipe_media_state_changed_cb), call);
460 Local Variables:
461 mode: c
462 c-file-style: "bsd"
463 indent-tabs-mode: t
464 tab-width: 8
465 End: