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
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>
37 #include "core-depurple.h"
39 typedef struct _sipe_purple_media
{
41 // Prevent infinite recursion in on_stream_info_cb
42 gboolean in_recursion
;
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
);
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
);
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
);
75 on_state_changed_cb(SIPE_UNUSED_PARAMETER PurpleMedia
*media
,
76 PurpleMediaState state
,
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
);
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
;
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
);
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
);
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
);
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
;
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
);
152 sipe_backend_media_add_stream(sipe_media
*media
, const gchar
* participant
,
153 SipeMediaType type
, gboolean use_nice
,
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;
163 transmitter
= "nice";
166 params
= g_new0(GParameter
, params_cnt
);
167 params
[0].name
= "controlling-mode";
168 g_value_init(¶ms
[0].value
, G_TYPE_BOOLEAN
);
169 g_value_set_boolean(¶ms
[0].value
, initiator
);
170 params
[1].name
= "compatibility-mode";
171 g_value_init(¶ms
[1].value
, G_TYPE_UINT
);
172 g_value_set_uint(¶ms
[1].value
, NICE_COMPATIBILITY_OC2007R2
);
174 transmitter
= "rawudp";
177 return purple_media_add_stream(m
->m
, "sipe-voice", participant
, prpl_type
,
178 initiator
, transmitter
, params_cnt
, params
);
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
);
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
);
202 sipe_backend_codec_free(sipe_codec
*codec
)
205 g_object_unref(codec
);
209 sipe_backend_codec_get_id(sipe_codec
*codec
)
211 return purple_media_codec_get_id((PurpleMediaCodec
*)codec
);
215 sipe_backend_codec_get_name(sipe_codec
*codec
)
217 return purple_media_codec_get_encoding_name((PurpleMediaCodec
*)codec
);
221 sipe_backend_codec_get_clock_rate(sipe_codec
*codec
)
223 return purple_media_codec_get_clock_rate((PurpleMediaCodec
*)codec
);
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
);
234 sipe_backend_codec_get_optional_parameters(sipe_codec
*codec
)
236 return purple_media_codec_get_optional_parameters((PurpleMediaCodec
*)codec
);
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
);
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");
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(
263 sipe_candidate_type_to_purple(type
),
264 sipe_network_protocol_to_purple(proto
),
270 sipe_backend_candidate_free(sipe_candidate
*candidate
)
273 g_object_unref(candidate
);
277 sipe_backend_candidate_get_username(sipe_candidate
*candidate
)
279 return purple_media_candidate_get_username((PurpleMediaCandidate
*)candidate
);
283 sipe_backend_candidate_get_password(sipe_candidate
*candidate
)
285 return purple_media_candidate_get_password((PurpleMediaCandidate
*)candidate
);
289 sipe_backend_candidate_get_foundation(sipe_candidate
*candidate
)
291 return purple_media_candidate_get_foundation((PurpleMediaCandidate
*)candidate
);
295 sipe_backend_candidate_get_ip(sipe_candidate
*candidate
)
297 return purple_media_candidate_get_ip((PurpleMediaCandidate
*)candidate
);
301 sipe_backend_candidate_get_port(sipe_candidate
*candidate
)
303 return purple_media_candidate_get_port((PurpleMediaCandidate
*)candidate
);
307 sipe_backend_candidate_get_priority(sipe_candidate
*candidate
)
309 return purple_media_candidate_get_priority((PurpleMediaCandidate
*)candidate
);
313 sipe_backend_candidate_set_priority(sipe_candidate
*candidate
, guint32 priority
)
315 g_object_set(candidate
, "priority", priority
, NULL
);
319 sipe_backend_candidate_get_component_type(sipe_candidate
*candidate
)
321 return purple_media_candidate_get_component_id((PurpleMediaCandidate
*)candidate
);
325 sipe_backend_candidate_get_type(sipe_candidate
*candidate
)
327 return purple_media_candidate_get_candidate_type((PurpleMediaCandidate
*)candidate
);
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
);
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
);
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
);
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
);
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
);
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
)
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)
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
)
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
)
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
)
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);