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
29 #include "sipe-common.h"
31 #include "mediamanager.h"
35 #include "sipe-backend.h"
36 #include "sipe-core.h"
37 #include "sipe-media.h"
39 #include "purple-private.h"
41 typedef struct _sipe_purple_media
{
43 // Prevent infinite recursion in on_stream_info_cb
44 gboolean in_recursion
;
47 static PurpleMediaSessionType
sipe_media_to_purple(SipeMediaType type
);
48 static PurpleMediaCandidateType
sipe_candidate_type_to_purple(SipeCandidateType type
);
49 static PurpleMediaNetworkProtocol
sipe_network_protocol_to_purple(SipeNetworkProtocol proto
);
50 static SipeNetworkProtocol
purple_network_protocol_to_sipe(PurpleMediaNetworkProtocol proto
);
53 on_candidates_prepared_cb(SIPE_UNUSED_PARAMETER PurpleMedia
*media
,
54 SIPE_UNUSED_PARAMETER gchar
*sessionid
,
55 SIPE_UNUSED_PARAMETER gchar
*participant
,
56 sipe_media_call
*call
)
58 if (call
->candidates_prepared_cb
)
59 call
->candidates_prepared_cb(call
);
63 on_state_changed_cb(SIPE_UNUSED_PARAMETER PurpleMedia
*media
,
64 PurpleMediaState state
,
67 sipe_media_call
*call
)
69 printf("sipe_media_state_changed_cb: %d %s %s\n", state
, sessionid
, participant
);
70 if (state
== PURPLE_MEDIA_STATE_CONNECTED
&& call
->media_connected_cb
)
71 call
->media_connected_cb(call
);
75 on_stream_info_cb(SIPE_UNUSED_PARAMETER PurpleMedia
*media
,
76 PurpleMediaInfoType type
,
77 SIPE_UNUSED_PARAMETER gchar
*sessionid
,
78 SIPE_UNUSED_PARAMETER gchar
*participant
,
79 gboolean local
, sipe_media_call
*call
)
81 sipe_purple_media
*m
= call
->media
;
82 if (m
->in_recursion
) {
83 m
->in_recursion
= FALSE
;
87 if (type
== PURPLE_MEDIA_INFO_ACCEPT
&& call
->call_accept_cb
)
88 call
->call_accept_cb(call
, local
);
89 else if (type
== PURPLE_MEDIA_INFO_REJECT
&& call
->call_reject_cb
)
90 call
->call_reject_cb(call
, local
);
91 else if (type
== PURPLE_MEDIA_INFO_HOLD
&& call
->call_hold_cb
) {
92 call
->call_hold_cb(call
, local
, TRUE
);
94 m
->in_recursion
= TRUE
;
95 purple_media_stream_info(m
->m
, PURPLE_MEDIA_INFO_HOLD
, NULL
, NULL
, TRUE
);
97 } else if (type
== PURPLE_MEDIA_INFO_UNHOLD
&& call
->call_hold_cb
) {
98 call
->call_hold_cb(call
, local
, FALSE
);
99 m
->in_recursion
= TRUE
;
100 if (!call
->local_on_hold
&& !call
->remote_on_hold
) {
101 purple_media_stream_info(m
->m
, PURPLE_MEDIA_INFO_UNHOLD
, NULL
, NULL
, TRUE
);
103 /* Remote side is still on hold, keep local also held to prevent sending
104 * unnecessary media over network */
105 purple_media_stream_info(m
->m
, PURPLE_MEDIA_INFO_HOLD
, NULL
, NULL
, TRUE
);
107 } else if (type
== PURPLE_MEDIA_INFO_HANGUP
&& call
->call_hangup_cb
)
108 call
->call_hangup_cb(call
, local
);
112 sipe_backend_media_new(struct sipe_core_public
*sipe_public
,
113 struct sipe_media_call
*call
,
114 const gchar
*participant
,
117 sipe_purple_media
*m
= g_new0(sipe_purple_media
, 1);
118 struct sipe_backend_private
*purple_private
= sipe_public
->backend_private
;
119 PurpleMediaManager
*manager
= purple_media_manager_get();
121 m
->m
= purple_media_manager_create_media(manager
,
122 purple_private
->account
,
124 participant
, initiator
);
126 g_signal_connect(G_OBJECT(m
->m
), "candidates-prepared",
127 G_CALLBACK(on_candidates_prepared_cb
), call
);
128 g_signal_connect(G_OBJECT(m
->m
), "stream-info",
129 G_CALLBACK(on_stream_info_cb
), call
);
130 g_signal_connect(G_OBJECT(m
->m
), "state-changed",
131 G_CALLBACK(on_state_changed_cb
), call
);
133 return (struct sipe_media
*)m
;
137 sipe_backend_media_free(sipe_media
*media
)
139 sipe_purple_media
*m
= (sipe_purple_media
*)media
;
140 purple_media_manager_remove_media(purple_media_manager_get(), m
->m
);
145 sipe_backend_media_add_stream(sipe_media
*media
, const gchar
* participant
,
146 SipeMediaType type
, gboolean use_nice
,
149 sipe_purple_media
*m
= (sipe_purple_media
*)media
;
150 PurpleMediaSessionType prpl_type
= sipe_media_to_purple(type
);
151 GParameter
*params
= NULL
;
152 guint params_cnt
= 0;
156 transmitter
= "nice";
159 params
= g_new0(GParameter
, params_cnt
);
160 params
[0].name
= "controlling-mode";
161 g_value_init(¶ms
[0].value
, G_TYPE_BOOLEAN
);
162 g_value_set_boolean(¶ms
[0].value
, initiator
);
163 params
[1].name
= "compatibility-mode";
164 g_value_init(¶ms
[1].value
, G_TYPE_UINT
);
166 * !!!TEMPORARY HACK!!!
168 * This enables successful compilation with libnice < 0.0.12
170 * This DOES NOT mean that the resulting code will work!!!
172 #ifdef NICE_HAS_COMPATIBILITY
173 g_value_set_uint(¶ms
[1].value
, NICE_COMPATIBILITY_OC2007R2
);
176 transmitter
= "rawudp";
179 return purple_media_add_stream(m
->m
, "sipe-voice", participant
, prpl_type
,
180 initiator
, transmitter
, params_cnt
, params
);
184 sipe_backend_media_add_remote_candidates(sipe_media
*media
, gchar
* participant
, GList
*candidates
)
186 sipe_purple_media
*m
= (sipe_purple_media
*)media
;
187 purple_media_add_remote_candidates(m
->m
, "sipe-voice", participant
, candidates
);
190 gboolean
sipe_backend_media_is_initiator(sipe_media
*media
, gchar
*participant
)
192 sipe_purple_media
*m
= (sipe_purple_media
*)media
;
193 return purple_media_is_initiator(m
->m
, "sipe-voice", participant
);
197 sipe_backend_codec_new(int id
, const char *name
, SipeMediaType type
, guint clock_rate
)
199 return (sipe_codec
*)purple_media_codec_new(id
, name
,
200 sipe_media_to_purple(type
), clock_rate
);
204 sipe_backend_codec_free(sipe_codec
*codec
)
207 g_object_unref(codec
);
211 sipe_backend_codec_get_id(sipe_codec
*codec
)
213 return purple_media_codec_get_id((PurpleMediaCodec
*)codec
);
217 sipe_backend_codec_get_name(sipe_codec
*codec
)
219 return purple_media_codec_get_encoding_name((PurpleMediaCodec
*)codec
);
223 sipe_backend_codec_get_clock_rate(sipe_codec
*codec
)
225 return purple_media_codec_get_clock_rate((PurpleMediaCodec
*)codec
);
229 sipe_backend_codec_add_optional_parameter(sipe_codec
*codec
,
230 const gchar
*name
, const gchar
*value
)
232 purple_media_codec_add_optional_parameter((PurpleMediaCodec
*)codec
, name
, value
);
236 sipe_backend_codec_get_optional_parameters(sipe_codec
*codec
)
238 return purple_media_codec_get_optional_parameters((PurpleMediaCodec
*)codec
);
242 sipe_backend_set_remote_codecs(sipe_media_call
* call
, gchar
* participant
)
244 sipe_purple_media
*m
= (sipe_purple_media
*)call
->media
;
245 GList
*codecs
= call
->remote_codecs
;
247 return purple_media_set_remote_codecs(m
->m
, "sipe-voice", participant
, codecs
);
251 sipe_backend_get_local_codecs(sipe_media_call
* call
)
253 sipe_purple_media
*m
= (sipe_purple_media
*)call
->media
;
254 return purple_media_get_codecs(m
->m
, "sipe-voice");
258 sipe_backend_candidate_new(const gchar
*foundation
, SipeComponentType component
,
259 SipeCandidateType type
, SipeNetworkProtocol proto
,
260 const gchar
*ip
, guint port
)
262 return (sipe_candidate
*)purple_media_candidate_new(
265 sipe_candidate_type_to_purple(type
),
266 sipe_network_protocol_to_purple(proto
),
272 sipe_backend_candidate_free(sipe_candidate
*candidate
)
275 g_object_unref(candidate
);
279 sipe_backend_candidate_get_username(sipe_candidate
*candidate
)
281 return purple_media_candidate_get_username((PurpleMediaCandidate
*)candidate
);
285 sipe_backend_candidate_get_password(sipe_candidate
*candidate
)
287 return purple_media_candidate_get_password((PurpleMediaCandidate
*)candidate
);
291 sipe_backend_candidate_get_foundation(sipe_candidate
*candidate
)
293 return purple_media_candidate_get_foundation((PurpleMediaCandidate
*)candidate
);
297 sipe_backend_candidate_get_ip(sipe_candidate
*candidate
)
299 return purple_media_candidate_get_ip((PurpleMediaCandidate
*)candidate
);
303 sipe_backend_candidate_get_port(sipe_candidate
*candidate
)
305 return purple_media_candidate_get_port((PurpleMediaCandidate
*)candidate
);
309 sipe_backend_candidate_get_priority(sipe_candidate
*candidate
)
311 return purple_media_candidate_get_priority((PurpleMediaCandidate
*)candidate
);
315 sipe_backend_candidate_set_priority(sipe_candidate
*candidate
, guint32 priority
)
317 g_object_set(candidate
, "priority", priority
, NULL
);
321 sipe_backend_candidate_get_component_type(sipe_candidate
*candidate
)
323 return purple_media_candidate_get_component_id((PurpleMediaCandidate
*)candidate
);
327 sipe_backend_candidate_get_type(sipe_candidate
*candidate
)
329 return purple_media_candidate_get_candidate_type((PurpleMediaCandidate
*)candidate
);
333 sipe_backend_candidate_get_protocol(sipe_candidate
*candidate
)
335 PurpleMediaNetworkProtocol proto
=
336 purple_media_candidate_get_protocol((PurpleMediaCandidate
*)candidate
);
337 return purple_network_protocol_to_sipe(proto
);
341 sipe_backend_candidate_set_username_and_pwd(sipe_candidate
*candidate
,
342 const gchar
*username
,
343 const gchar
*password
)
345 g_object_set(candidate
, "username", username
, "password", password
, NULL
);
349 sipe_backend_get_local_candidates(sipe_media_call
* call
, gchar
* participant
)
351 sipe_purple_media
*m
= (sipe_purple_media
*)call
->media
;
352 return purple_media_get_local_candidates(m
->m
, "sipe-voice", participant
);
356 sipe_backend_media_hold(sipe_media
* media
, gboolean local
)
358 sipe_purple_media
*m
= (sipe_purple_media
*)media
;
359 purple_media_stream_info(m
->m
, PURPLE_MEDIA_INFO_HOLD
, NULL
, NULL
, local
);
363 sipe_backend_media_unhold(sipe_media
* media
, gboolean local
)
365 sipe_purple_media
*m
= (sipe_purple_media
*)media
;
366 purple_media_stream_info(m
->m
, PURPLE_MEDIA_INFO_UNHOLD
, NULL
, NULL
, local
);
370 sipe_backend_media_hangup(sipe_media
* media
, gboolean local
)
372 sipe_purple_media
*m
= (sipe_purple_media
*)media
;
373 purple_media_stream_info(m
->m
, PURPLE_MEDIA_INFO_HANGUP
, NULL
, NULL
, local
);
377 sipe_backend_media_reject(sipe_media
* media
, gboolean local
)
379 sipe_purple_media
*m
= (sipe_purple_media
*)media
;
380 purple_media_stream_info(m
->m
, PURPLE_MEDIA_INFO_REJECT
, NULL
, NULL
, local
);
383 PurpleMediaSessionType
sipe_media_to_purple(SipeMediaType type
)
386 case SIPE_MEDIA_AUDIO
: return PURPLE_MEDIA_AUDIO
;
387 case SIPE_MEDIA_VIDEO
: return PURPLE_MEDIA_VIDEO
;
388 default: return PURPLE_MEDIA_NONE
;
392 /*SipeMediaType purple_media_to_sipe(PurpleMediaSessionType type)
395 case PURPLE_MEDIA_AUDIO: return SIPE_MEDIA_AUDIO;
396 case PURPLE_MEDIA_VIDEO: return SIPE_MEDIA_VIDEO;
397 default: return SIPE_MEDIA_AUDIO;
401 static PurpleMediaCandidateType
402 sipe_candidate_type_to_purple(SipeCandidateType type
)
405 case SIPE_CANDIDATE_TYPE_HOST
: return PURPLE_MEDIA_CANDIDATE_TYPE_HOST
;
406 case SIPE_CANDIDATE_TYPE_RELAY
: return PURPLE_MEDIA_CANDIDATE_TYPE_RELAY
;
407 case SIPE_CANDIDATE_TYPE_SRFLX
: return PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX
;
408 default: return PURPLE_MEDIA_CANDIDATE_TYPE_HOST
;
412 static PurpleMediaNetworkProtocol
413 sipe_network_protocol_to_purple(SipeNetworkProtocol proto
)
416 case SIPE_NETWORK_PROTOCOL_TCP
: return PURPLE_MEDIA_NETWORK_PROTOCOL_TCP
;
417 case SIPE_NETWORK_PROTOCOL_UDP
: return PURPLE_MEDIA_NETWORK_PROTOCOL_UDP
;
418 default: return PURPLE_MEDIA_NETWORK_PROTOCOL_TCP
;
422 static SipeNetworkProtocol
423 purple_network_protocol_to_sipe(PurpleMediaNetworkProtocol proto
)
426 case PURPLE_MEDIA_NETWORK_PROTOCOL_TCP
: return SIPE_NETWORK_PROTOCOL_TCP
;
427 case PURPLE_MEDIA_NETWORK_PROTOCOL_UDP
: return SIPE_NETWORK_PROTOCOL_UDP
;
428 default: return SIPE_NETWORK_PROTOCOL_UDP
;
433 void sipe_media_error_cb(SIPE_UNUSED_PARAMETER PurpleMedia *media, gchar* error, SIPE_UNUSED_PARAMETER struct sipe_account_data *sip)
435 printf("sipe_media_error_cb: %s\n", error);
438 void sipe_media_codecs_changed_cb(SIPE_UNUSED_PARAMETER PurpleMedia *media, gchar* codec, SIPE_UNUSED_PARAMETER struct sipe_account_data *sip)
440 printf("sipe_media_codecs_changed_cb: %s\n", codec);
443 void sipe_media_level_cb(SIPE_UNUSED_PARAMETER PurpleMedia *media, gchar* sessionid, gchar* participant, gdouble percent, SIPE_UNUSED_PARAMETER struct sipe_account_data *sip)
445 printf("sipe_media_level_cb: %s %s %f\n", sessionid, participant, percent);
448 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)
450 printf("sipe_media_new_candidate_cb: %s cname: %s %s %d\n", sessionid, cname,
451 purple_media_candidate_get_ip(candidate),
452 purple_media_candidate_get_port(candidate));
455 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)
457 printf("sipe_media_state_changed_cb: %d %s %s\n", state, sessionid, participant);
460 g_signal_connect(G_OBJECT(media), "error", G_CALLBACK(sipe_media_error_cb), call);
461 g_signal_connect(G_OBJECT(media), "codecs-changed", G_CALLBACK(sipe_media_codecs_changed_cb), call);
462 g_signal_connect(G_OBJECT(media), "level", G_CALLBACK(sipe_media_level_cb), call);
463 g_signal_connect(G_OBJECT(media), "new-candidate", G_CALLBACK(sipe_media_new_candidate_cb), call);
464 g_signal_connect(G_OBJECT(media), "state-changed", G_CALLBACK(sipe_media_state_changed_cb), call);