2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2012, Digium, Inc.
6 * Joshua Colp <jcolp@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
21 * \author Joshua Colp <jcolp@digium.com>
23 * \brief Motif Jingle Channel Driver
25 * Iksemel http://iksemel.jabberstudio.org/
27 * \ingroup channel_drivers
30 /*! \li \ref chan_motif.c uses the configuration file \ref motif.conf
31 * \addtogroup configuration_file
34 /*! \page motif.conf motif.conf
35 * \verbinclude motif.conf.sample
39 <depend>iksemel</depend>
40 <depend>res_xmpp</depend>
41 <use type="external">openssl</use>
42 <support_level>core</support_level>
47 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
49 #include <sys/socket.h>
52 #include <netinet/in.h>
53 #include <arpa/inet.h>
54 #include <sys/signal.h>
58 #include "asterisk/lock.h"
59 #include "asterisk/channel.h"
60 #include "asterisk/config_options.h"
61 #include "asterisk/module.h"
62 #include "asterisk/pbx.h"
63 #include "asterisk/sched.h"
64 #include "asterisk/io.h"
65 #include "asterisk/rtp_engine.h"
66 #include "asterisk/acl.h"
67 #include "asterisk/callerid.h"
68 #include "asterisk/file.h"
69 #include "asterisk/cli.h"
70 #include "asterisk/app.h"
71 #include "asterisk/musiconhold.h"
72 #include "asterisk/manager.h"
73 #include "asterisk/stringfields.h"
74 #include "asterisk/utils.h"
75 #include "asterisk/causes.h"
76 #include "asterisk/astobj.h"
77 #include "asterisk/abstract_jb.h"
78 #include "asterisk/xmpp.h"
80 /*! \brief Default maximum number of ICE candidates we will offer */
81 #define DEFAULT_MAX_ICE_CANDIDATES "10"
83 /*! \brief Default maximum number of payloads we will offer */
84 #define DEFAULT_MAX_PAYLOADS "30"
86 /*! \brief Number of buckets for endpoints */
87 #define ENDPOINT_BUCKETS 37
89 /*! \brief Number of buckets for sessions, on a per-endpoint basis */
90 #define SESSION_BUCKETS 37
92 /*! \brief Namespace for Jingle itself */
93 #define JINGLE_NS "urn:xmpp:jingle:1"
95 /*! \brief Namespace for Jingle RTP sessions */
96 #define JINGLE_RTP_NS "urn:xmpp:jingle:apps:rtp:1"
98 /*! \brief Namespace for Jingle RTP info */
99 #define JINGLE_RTP_INFO_NS "urn:xmpp:jingle:apps:rtp:info:1"
101 /*! \brief Namespace for Jingle ICE-UDP */
102 #define JINGLE_ICE_UDP_NS "urn:xmpp:jingle:transports:ice-udp:1"
104 /*! \brief Namespace for Google Talk ICE-UDP */
105 #define GOOGLE_TRANSPORT_NS "http://www.google.com/transport/p2p"
107 /*! \brief Namespace for Google Talk Raw UDP */
108 #define GOOGLE_TRANSPORT_RAW_NS "http://www.google.com/transport/raw-udp"
110 /*! \brief Namespace for Google Session */
111 #define GOOGLE_SESSION_NS "http://www.google.com/session"
113 /*! \brief Namespace for Google Phone description */
114 #define GOOGLE_PHONE_NS "http://www.google.com/session/phone"
116 /*! \brief Namespace for Google Video description */
117 #define GOOGLE_VIDEO_NS "http://www.google.com/session/video"
119 /*! \brief Namespace for XMPP stanzas */
120 #define XMPP_STANZAS_NS "urn:ietf:params:xml:ns:xmpp-stanzas"
122 /*! \brief The various transport methods supported, from highest priority to lowest priority when doing fallback */
123 enum jingle_transport {
124 JINGLE_TRANSPORT_ICE_UDP = 3, /*!< XEP-0176 */
125 JINGLE_TRANSPORT_GOOGLE_V2 = 2, /*!< https://developers.google.com/talk/call_signaling */
126 JINGLE_TRANSPORT_GOOGLE_V1 = 1, /*!< Undocumented initial Google specification */
127 JINGLE_TRANSPORT_NONE = 0, /*!< No transport specified */
130 /*! \brief Endpoint state information */
131 struct jingle_endpoint_state {
132 struct ao2_container *sessions; /*!< Active sessions to or from the endpoint */
135 /*! \brief Endpoint which contains configuration information and active sessions */
136 struct jingle_endpoint {
137 AST_DECLARE_STRING_FIELDS(
138 AST_STRING_FIELD(name); /*!< Name of the endpoint */
139 AST_STRING_FIELD(context); /*!< Context to place incoming calls into */
140 AST_STRING_FIELD(accountcode); /*!< Account code */
141 AST_STRING_FIELD(language); /*!< Default language for prompts */
142 AST_STRING_FIELD(musicclass); /*!< Configured music on hold class */
143 AST_STRING_FIELD(parkinglot); /*!< Configured parking lot */
145 struct ast_xmpp_client *connection; /*!< Connection to use for traffic */
146 iksrule *rule; /*!< Active matching rule */
147 unsigned int maxicecandidates; /*!< Maximum number of ICE candidates we will offer */
148 unsigned int maxpayloads; /*!< Maximum number of payloads we will offer */
149 struct ast_codec_pref prefs; /*!< Codec preferences */
150 struct ast_format_cap *cap; /*!< Formats to use */
151 ast_group_t callgroup; /*!< Call group */
152 ast_group_t pickupgroup; /*!< Pickup group */
153 enum jingle_transport transport; /*!< Default transport to use on outgoing sessions */
154 struct jingle_endpoint_state *state; /*!< Endpoint state information */
157 /*! \brief Session which contains information about an active session */
158 struct jingle_session {
159 AST_DECLARE_STRING_FIELDS(
160 AST_STRING_FIELD(sid); /*!< Session identifier */
161 AST_STRING_FIELD(audio_name); /*!< Name of the audio content */
162 AST_STRING_FIELD(video_name); /*!< Name of the video content */
164 struct jingle_endpoint_state *state; /*!< Endpoint we are associated with */
165 struct ast_xmpp_client *connection; /*!< Connection to use for traffic */
166 enum jingle_transport transport; /*!< Transport type to use for this session */
167 unsigned int maxicecandidates; /*!< Maximum number of ICE candidates we will offer */
168 unsigned int maxpayloads; /*!< Maximum number of payloads we will offer */
169 char remote_original[XMPP_MAX_JIDLEN];/*!< Identifier of the original remote party (remote may have changed due to redirect) */
170 char remote[XMPP_MAX_JIDLEN]; /*!< Identifier of the remote party */
171 iksrule *rule; /*!< Session matching rule */
172 struct ast_codec_pref prefs; /*!< Codec preferences */
173 struct ast_channel *owner; /*!< Master Channel */
174 struct ast_rtp_instance *rtp; /*!< RTP audio session */
175 struct ast_rtp_instance *vrtp; /*!< RTP video session */
176 struct ast_format_cap *cap; /*!< Local codec capabilities */
177 struct ast_format_cap *jointcap; /*!< Joint codec capabilities */
178 struct ast_format_cap *peercap; /*!< Peer codec capabilities */
179 unsigned int outgoing:1; /*!< Whether this is an outgoing leg or not */
180 unsigned int gone:1; /*!< In the eyes of Jingle this session is already gone */
181 struct ast_callid *callid; /*!< Bound session call-id */
184 static const char desc[] = "Motif Jingle Channel";
185 static const char channel_type[] = "Motif";
187 struct jingle_config {
188 struct ao2_container *endpoints; /*!< Configured endpoints */
191 static AO2_GLOBAL_OBJ_STATIC(globals);
193 static struct ast_sched_context *sched; /*!< Scheduling context for RTCP */
195 /* \brief Asterisk core interaction functions */
196 static struct ast_channel *jingle_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause);
197 static int jingle_sendtext(struct ast_channel *ast, const char *text);
198 static int jingle_digit_begin(struct ast_channel *ast, char digit);
199 static int jingle_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
200 static int jingle_call(struct ast_channel *ast, const char *dest, int timeout);
201 static int jingle_hangup(struct ast_channel *ast);
202 static int jingle_answer(struct ast_channel *ast);
203 static struct ast_frame *jingle_read(struct ast_channel *ast);
204 static int jingle_write(struct ast_channel *ast, struct ast_frame *f);
205 static int jingle_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
206 static int jingle_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
207 static struct jingle_session *jingle_alloc(struct jingle_endpoint *endpoint, const char *from, const char *sid);
209 /*! \brief Action handlers */
210 static void jingle_action_session_initiate(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
211 static void jingle_action_transport_info(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
212 static void jingle_action_session_accept(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
213 static void jingle_action_session_info(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
214 static void jingle_action_session_terminate(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
216 /*! \brief PBX interface structure for channel registration */
217 static struct ast_channel_tech jingle_tech = {
219 .description = "Motif Jingle Channel Driver",
220 .requester = jingle_request,
221 .send_text = jingle_sendtext,
222 .send_digit_begin = jingle_digit_begin,
223 .send_digit_end = jingle_digit_end,
224 .bridge = ast_rtp_instance_bridge,
226 .hangup = jingle_hangup,
227 .answer = jingle_answer,
229 .write = jingle_write,
230 .write_video = jingle_write,
231 .exception = jingle_read,
232 .indicate = jingle_indicate,
233 .fixup = jingle_fixup,
234 .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER
237 /*! \brief Defined handlers for different Jingle actions */
238 static const struct jingle_action_handler {
240 void (*handler)(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak);
241 } jingle_action_handlers[] = {
243 { "session-initiate", jingle_action_session_initiate, },
244 { "transport-info", jingle_action_transport_info, },
245 { "session-accept", jingle_action_session_accept, },
246 { "session-info", jingle_action_session_info, },
247 { "session-terminate", jingle_action_session_terminate, },
248 /* Google-V1 actions */
249 { "initiate", jingle_action_session_initiate, },
250 { "candidates", jingle_action_transport_info, },
251 { "accept", jingle_action_session_accept, },
252 { "terminate", jingle_action_session_terminate, },
253 { "reject", jingle_action_session_terminate, },
256 /*! \brief Reason text <-> cause code mapping */
257 static const struct jingle_reason_mapping {
260 } jingle_reason_mappings[] = {
261 { "busy", AST_CAUSE_BUSY, },
262 { "cancel", AST_CAUSE_CALL_REJECTED, },
263 { "connectivity-error", AST_CAUSE_INTERWORKING, },
264 { "decline", AST_CAUSE_CALL_REJECTED, },
265 { "expired", AST_CAUSE_NO_USER_RESPONSE, },
266 { "failed-transport", AST_CAUSE_PROTOCOL_ERROR, },
267 { "failed-application", AST_CAUSE_SWITCH_CONGESTION, },
268 { "general-error", AST_CAUSE_CONGESTION, },
269 { "gone", AST_CAUSE_NORMAL_CLEARING, },
270 { "incompatible-parameters", AST_CAUSE_BEARERCAPABILITY_NOTAVAIL, },
271 { "media-error", AST_CAUSE_BEARERCAPABILITY_NOTAVAIL, },
272 { "security-error", AST_CAUSE_PROTOCOL_ERROR, },
273 { "success", AST_CAUSE_NORMAL_CLEARING, },
274 { "timeout", AST_CAUSE_RECOVERY_ON_TIMER_EXPIRE, },
275 { "unsupported-applications", AST_CAUSE_BEARERCAPABILITY_NOTAVAIL, },
276 { "unsupported-transports", AST_CAUSE_FACILITY_NOT_IMPLEMENTED, },
279 /*! \brief Hashing function for Jingle sessions */
280 static int jingle_session_hash(const void *obj, const int flags)
282 const struct jingle_session *session = obj;
283 const char *sid = obj;
285 return ast_str_hash(flags & OBJ_KEY ? sid : session->sid);
288 /*! \brief Comparator function for Jingle sessions */
289 static int jingle_session_cmp(void *obj, void *arg, int flags)
291 struct jingle_session *session1 = obj, *session2 = arg;
292 const char *sid = arg;
294 return !strcmp(session1->sid, flags & OBJ_KEY ? sid : session2->sid) ? CMP_MATCH | CMP_STOP : 0;
297 /*! \brief Destructor for Jingle endpoint state */
298 static void jingle_endpoint_state_destructor(void *obj)
300 struct jingle_endpoint_state *state = obj;
302 ao2_ref(state->sessions, -1);
305 /*! \brief Destructor for Jingle endpoints */
306 static void jingle_endpoint_destructor(void *obj)
308 struct jingle_endpoint *endpoint = obj;
310 if (endpoint->rule) {
311 iks_filter_remove_rule(endpoint->connection->filter, endpoint->rule);
314 if (endpoint->connection) {
315 ast_xmpp_client_unref(endpoint->connection);
318 ast_format_cap_destroy(endpoint->cap);
320 ao2_ref(endpoint->state, -1);
322 ast_string_field_free_memory(endpoint);
325 /*! \brief Find function for Jingle endpoints */
326 static void *jingle_endpoint_find(struct ao2_container *tmp_container, const char *category)
328 return ao2_find(tmp_container, category, OBJ_KEY);
331 /*! \brief Allocator function for Jingle endpoint state */
332 static struct jingle_endpoint_state *jingle_endpoint_state_create(void)
334 struct jingle_endpoint_state *state;
336 if (!(state = ao2_alloc(sizeof(*state), jingle_endpoint_state_destructor))) {
340 if (!(state->sessions = ao2_container_alloc(SESSION_BUCKETS, jingle_session_hash, jingle_session_cmp))) {
348 /*! \brief State find/create function */
349 static struct jingle_endpoint_state *jingle_endpoint_state_find_or_create(const char *category)
351 RAII_VAR(struct jingle_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
352 RAII_VAR(struct jingle_endpoint *, endpoint, NULL, ao2_cleanup);
354 if (!cfg || !cfg->endpoints || !(endpoint = jingle_endpoint_find(cfg->endpoints, category))) {
355 return jingle_endpoint_state_create();
358 ao2_ref(endpoint->state, +1);
359 return endpoint->state;
362 /*! \brief Allocator function for Jingle endpoints */
363 static void *jingle_endpoint_alloc(const char *cat)
365 struct jingle_endpoint *endpoint;
367 if (!(endpoint = ao2_alloc(sizeof(*endpoint), jingle_endpoint_destructor))) {
371 if (ast_string_field_init(endpoint, 512)) {
372 ao2_ref(endpoint, -1);
376 if (!(endpoint->state = jingle_endpoint_state_find_or_create(cat))) {
377 ao2_ref(endpoint, -1);
381 ast_string_field_set(endpoint, name, cat);
383 endpoint->cap = ast_format_cap_alloc_nolock();
384 endpoint->transport = JINGLE_TRANSPORT_ICE_UDP;
389 /*! \brief Hashing function for Jingle endpoints */
390 static int jingle_endpoint_hash(const void *obj, const int flags)
392 const struct jingle_endpoint *endpoint = obj;
393 const char *name = obj;
395 return ast_str_hash(flags & OBJ_KEY ? name : endpoint->name);
398 /*! \brief Comparator function for Jingle endpoints */
399 static int jingle_endpoint_cmp(void *obj, void *arg, int flags)
401 struct jingle_endpoint *endpoint1 = obj, *endpoint2 = arg;
402 const char *name = arg;
404 return !strcmp(endpoint1->name, flags & OBJ_KEY ? name : endpoint2->name) ? CMP_MATCH | CMP_STOP : 0;
407 static struct aco_type endpoint_option = {
409 .category_match = ACO_BLACKLIST,
410 .category = "^general$",
411 .item_alloc = jingle_endpoint_alloc,
412 .item_find = jingle_endpoint_find,
413 .item_offset = offsetof(struct jingle_config, endpoints),
416 struct aco_type *endpoint_options[] = ACO_TYPES(&endpoint_option);
418 struct aco_file jingle_conf = {
419 .filename = "motif.conf",
420 .types = ACO_TYPES(&endpoint_option),
423 /*! \brief Destructor for Jingle sessions */
424 static void jingle_session_destructor(void *obj)
426 struct jingle_session *session = obj;
429 iks_filter_remove_rule(session->connection->filter, session->rule);
432 if (session->connection) {
433 ast_xmpp_client_unref(session->connection);
437 ast_rtp_instance_destroy(session->rtp);
441 ast_rtp_instance_destroy(session->vrtp);
444 ast_format_cap_destroy(session->cap);
445 ast_format_cap_destroy(session->jointcap);
446 ast_format_cap_destroy(session->peercap);
448 if (session->callid) {
449 ast_callid_unref(session->callid);
452 ast_string_field_free_memory(session);
455 /*! \brief Destructor called when module configuration goes away */
456 static void jingle_config_destructor(void *obj)
458 struct jingle_config *cfg = obj;
459 ao2_cleanup(cfg->endpoints);
462 /*! \brief Allocator called when module configuration should appear */
463 static void *jingle_config_alloc(void)
465 struct jingle_config *cfg;
467 if (!(cfg = ao2_alloc(sizeof(*cfg), jingle_config_destructor))) {
471 if (!(cfg->endpoints = ao2_container_alloc(ENDPOINT_BUCKETS, jingle_endpoint_hash, jingle_endpoint_cmp))) {
479 CONFIG_INFO_STANDARD(cfg_info, globals, jingle_config_alloc,
480 .files = ACO_FILES(&jingle_conf),
483 /*! \brief Function called by RTP engine to get local RTP peer */
484 static enum ast_rtp_glue_result jingle_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
486 struct jingle_session *session = ast_channel_tech_pvt(chan);
487 enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_LOCAL;
490 return AST_RTP_GLUE_RESULT_FORBID;
493 ao2_ref(session->rtp, +1);
494 *instance = session->rtp;
499 /*! \brief Function called by RTP engine to get peer capabilities */
500 static void jingle_get_codec(struct ast_channel *chan, struct ast_format_cap *result)
504 /*! \brief Function called by RTP engine to change where the remote party should send media */
505 static int jingle_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *rtp, struct ast_rtp_instance *vrtp, struct ast_rtp_instance *tpeer, const struct ast_format_cap *cap, int nat_active)
510 /*! \brief Local glue for interacting with the RTP engine core */
511 static struct ast_rtp_glue jingle_rtp_glue = {
513 .get_rtp_info = jingle_get_rtp_peer,
514 .get_codec = jingle_get_codec,
515 .update_peer = jingle_set_rtp_peer,
518 /*! \brief Internal helper function which enables video support on a sesson if possible */
519 static void jingle_enable_video(struct jingle_session *session)
521 struct ast_sockaddr tmp;
522 struct ast_rtp_engine_ice *ice;
524 /* If video is already present don't do anything */
529 /* If there are no configured video codecs do not turn video support on, it just won't work */
530 if (!ast_format_cap_has_type(session->cap, AST_FORMAT_TYPE_VIDEO)) {
534 ast_sockaddr_parse(&tmp, "0.0.0.0", 0);
536 if (!(session->vrtp = ast_rtp_instance_new("asterisk", sched, &tmp, NULL))) {
540 ast_rtp_instance_set_prop(session->vrtp, AST_RTP_PROPERTY_RTCP, 1);
542 ast_channel_set_fd(session->owner, 2, ast_rtp_instance_fd(session->vrtp, 0));
543 ast_channel_set_fd(session->owner, 3, ast_rtp_instance_fd(session->vrtp, 1));
544 ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(session->vrtp), session->vrtp, &session->prefs);
546 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V2 && (ice = ast_rtp_instance_get_ice(session->vrtp))) {
547 ice->stop(session->vrtp);
551 /*! \brief Internal helper function used to allocate Jingle session on an endpoint */
552 static struct jingle_session *jingle_alloc(struct jingle_endpoint *endpoint, const char *from, const char *sid)
554 struct jingle_session *session;
555 struct ast_callid *callid;
556 struct ast_sockaddr tmp;
558 if (!(session = ao2_alloc(sizeof(*session), jingle_session_destructor))) {
562 callid = ast_read_threadstorage_callid();
563 session->callid = (callid ? callid : ast_create_callid());
565 if (ast_string_field_init(session, 512)) {
566 ao2_ref(session, -1);
570 if (!ast_strlen_zero(from)) {
571 ast_copy_string(session->remote_original, from, sizeof(session->remote_original));
572 ast_copy_string(session->remote, from, sizeof(session->remote));
575 if (ast_strlen_zero(sid)) {
576 ast_string_field_build(session, sid, "%08lx%08lx", ast_random(), ast_random());
577 session->outgoing = 1;
578 ast_string_field_set(session, audio_name, "audio");
579 ast_string_field_set(session, video_name, "video");
581 ast_string_field_set(session, sid, sid);
584 ao2_ref(endpoint->state, +1);
585 session->state = endpoint->state;
586 ao2_ref(endpoint->connection, +1);
587 session->connection = endpoint->connection;
588 session->transport = endpoint->transport;
590 if (!(session->cap = ast_format_cap_alloc_nolock()) ||
591 !(session->jointcap = ast_format_cap_alloc_nolock()) ||
592 !(session->peercap = ast_format_cap_alloc_nolock()) ||
594 ao2_ref(session, -1);
598 ast_format_cap_copy(session->cap, endpoint->cap);
600 /* While we rely on res_xmpp for communication we still need a temporary ast_sockaddr to tell the RTP engine
601 * that we want IPv4 */
602 ast_sockaddr_parse(&tmp, "0.0.0.0", 0);
604 /* Sessions always carry audio, but video is optional so don't enable it here */
605 if (!(session->rtp = ast_rtp_instance_new("asterisk", sched, &tmp, NULL))) {
606 ao2_ref(session, -1);
609 ast_rtp_instance_set_prop(session->rtp, AST_RTP_PROPERTY_RTCP, 1);
610 ast_rtp_instance_set_prop(session->rtp, AST_RTP_PROPERTY_DTMF, 1);
612 memcpy(&session->prefs, &endpoint->prefs, sizeof(session->prefs));
614 session->maxicecandidates = endpoint->maxicecandidates;
615 session->maxpayloads = endpoint->maxpayloads;
620 /*! \brief Function called to create a new Jingle Asterisk channel */
621 static struct ast_channel *jingle_new(struct jingle_endpoint *endpoint, struct jingle_session *session, int state, const char *title, const char *linkedid, const char *cid_name)
623 struct ast_channel *chan;
624 const char *str = S_OR(title, session->remote);
625 struct ast_format tmpfmt;
627 if (ast_format_cap_is_empty(session->cap)) {
631 if (!(chan = ast_channel_alloc(1, state, S_OR(title, ""), S_OR(cid_name, ""), "", "", "", linkedid, 0, "Motif/%s-%04lx", str, ast_random() & 0xffff))) {
635 ast_channel_tech_set(chan, &jingle_tech);
636 ast_channel_tech_pvt_set(chan, session);
637 session->owner = chan;
639 ast_channel_callid_set(chan, session->callid);
641 ast_format_cap_copy(ast_channel_nativeformats(chan), session->cap);
642 ast_codec_choose(&session->prefs, session->cap, 1, &tmpfmt);
645 struct ast_rtp_engine_ice *ice;
647 ast_channel_set_fd(chan, 0, ast_rtp_instance_fd(session->rtp, 0));
648 ast_channel_set_fd(chan, 1, ast_rtp_instance_fd(session->rtp, 1));
649 ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(session->rtp), session->rtp, &session->prefs);
651 if (((session->transport == JINGLE_TRANSPORT_GOOGLE_V2) ||
652 (session->transport == JINGLE_TRANSPORT_GOOGLE_V1)) &&
653 (ice = ast_rtp_instance_get_ice(session->rtp))) {
654 /* We stop built in ICE support because we need to fall back to old old old STUN support */
655 ice->stop(session->rtp);
659 if (state == AST_STATE_RING) {
660 ast_channel_rings_set(chan, 1);
663 ast_channel_adsicpe_set(chan, AST_ADSI_UNAVAILABLE);
665 ast_best_codec(ast_channel_nativeformats(chan), &tmpfmt);
666 ast_format_copy(ast_channel_writeformat(chan), &tmpfmt);
667 ast_format_copy(ast_channel_rawwriteformat(chan), &tmpfmt);
668 ast_format_copy(ast_channel_readformat(chan), &tmpfmt);
669 ast_format_copy(ast_channel_rawreadformat(chan), &tmpfmt);
673 ast_channel_callgroup_set(chan, endpoint->callgroup);
674 ast_channel_pickupgroup_set(chan, endpoint->pickupgroup);
676 if (!ast_strlen_zero(endpoint->accountcode)) {
677 ast_channel_accountcode_set(chan, endpoint->accountcode);
680 if (!ast_strlen_zero(endpoint->language)) {
681 ast_channel_language_set(chan, endpoint->language);
684 if (!ast_strlen_zero(endpoint->musicclass)) {
685 ast_channel_musicclass_set(chan, endpoint->musicclass);
688 ast_channel_context_set(chan, endpoint->context);
689 if (ast_exists_extension(NULL, endpoint->context, endpoint->name, 1, NULL)) {
690 ast_channel_exten_set(chan, endpoint->name);
692 ast_channel_exten_set(chan, "s");
694 ast_channel_priority_set(chan, 1);
696 ao2_unlock(endpoint);
701 /*! \brief Internal helper function which sends a response */
702 static void jingle_send_response(struct ast_xmpp_client *connection, ikspak *pak)
706 if (!(response = iks_new("iq"))) {
707 ast_log(LOG_ERROR, "Unable to allocate an IKS response stanza\n");
711 iks_insert_attrib(response, "type", "result");
712 iks_insert_attrib(response, "from", connection->jid->full);
713 iks_insert_attrib(response, "to", iks_find_attrib(pak->x, "from"));
714 iks_insert_attrib(response, "id", iks_find_attrib(pak->x, "id"));
716 ast_xmpp_client_send(connection, response);
718 iks_delete(response);
721 /*! \brief Internal helper function which sends an error response */
722 static void jingle_send_error_response(struct ast_xmpp_client *connection, ikspak *pak, const char *type, const char *reasonstr, const char *reasonstr2)
724 iks *response, *error = NULL, *reason = NULL, *reason2 = NULL;
726 if (!(response = iks_new("iq")) ||
727 !(error = iks_new("error")) ||
728 !(reason = iks_new(reasonstr))) {
729 ast_log(LOG_ERROR, "Unable to allocate IKS error response stanzas\n");
733 iks_insert_attrib(response, "type", "error");
734 iks_insert_attrib(response, "from", connection->jid->full);
735 iks_insert_attrib(response, "to", iks_find_attrib(pak->x, "from"));
736 iks_insert_attrib(response, "id", iks_find_attrib(pak->x, "id"));
738 iks_insert_attrib(error, "type", type);
739 iks_insert_node(error, reason);
741 if (!ast_strlen_zero(reasonstr2) && (reason2 = iks_new(reasonstr2))) {
742 iks_insert_node(error, reason2);
745 iks_insert_node(response, error);
747 ast_xmpp_client_send(connection, response);
752 iks_delete(response);
755 /*! \brief Internal helper function which adds ICE-UDP candidates to a transport node */
756 static int jingle_add_ice_udp_candidates_to_transport(struct ast_rtp_instance *rtp, iks *transport, iks **candidates, unsigned int maximum)
758 struct ast_rtp_engine_ice *ice;
759 struct ao2_container *local_candidates;
760 struct ao2_iterator it;
761 struct ast_rtp_engine_ice_candidate *candidate;
764 if (!(ice = ast_rtp_instance_get_ice(rtp)) || !(local_candidates = ice->get_local_candidates(rtp))) {
765 ast_log(LOG_ERROR, "Unable to add ICE-UDP candidates as ICE support not available or no candidates available\n");
769 iks_insert_attrib(transport, "xmlns", JINGLE_ICE_UDP_NS);
770 iks_insert_attrib(transport, "pwd", ice->get_password(rtp));
771 iks_insert_attrib(transport, "ufrag", ice->get_ufrag(rtp));
773 it = ao2_iterator_init(local_candidates, 0);
775 while ((candidate = ao2_iterator_next(&it)) && (i < maximum)) {
776 iks *local_candidate;
779 if (!(local_candidate = iks_new("candidate"))) {
781 ast_log(LOG_ERROR, "Unable to allocate IKS candidate stanza for ICE-UDP transport\n");
785 snprintf(tmp, sizeof(tmp), "%d", candidate->id);
786 iks_insert_attrib(local_candidate, "component", tmp);
787 snprintf(tmp, sizeof(tmp), "%d", ast_str_hash(candidate->foundation));
788 iks_insert_attrib(local_candidate, "foundation", tmp);
789 iks_insert_attrib(local_candidate, "generation", "0");
790 iks_insert_attrib(local_candidate, "network", "0");
791 snprintf(tmp, sizeof(tmp), "%04lx", ast_random() & 0xffff);
792 iks_insert_attrib(local_candidate, "id", tmp);
793 iks_insert_attrib(local_candidate, "ip", ast_sockaddr_stringify_host(&candidate->address));
794 iks_insert_attrib(local_candidate, "port", ast_sockaddr_stringify_port(&candidate->address));
795 snprintf(tmp, sizeof(tmp), "%d", candidate->priority);
796 iks_insert_attrib(local_candidate, "priority", tmp);
797 iks_insert_attrib(local_candidate, "protocol", "udp");
799 if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_HOST) {
800 iks_insert_attrib(local_candidate, "type", "host");
801 } else if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_SRFLX) {
802 iks_insert_attrib(local_candidate, "type", "srflx");
803 } else if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_RELAYED) {
804 iks_insert_attrib(local_candidate, "type", "relay");
807 iks_insert_node(transport, local_candidate);
808 candidates[i++] = local_candidate;
811 ao2_iterator_destroy(&it);
812 ao2_ref(local_candidates, -1);
817 /*! \brief Internal helper function which adds Google candidates to a transport node */
818 static int jingle_add_google_candidates_to_transport(struct ast_rtp_instance *rtp, iks *transport, iks **candidates, unsigned int video, enum jingle_transport transport_type, unsigned int maximum)
820 struct ast_rtp_engine_ice *ice;
821 struct ao2_container *local_candidates;
822 struct ao2_iterator it;
823 struct ast_rtp_engine_ice_candidate *candidate;
826 if (!(ice = ast_rtp_instance_get_ice(rtp)) || !(local_candidates = ice->get_local_candidates(rtp))) {
827 ast_log(LOG_ERROR, "Unable to add Google ICE candidates as ICE support not available or no candidates available\n");
831 if (transport_type != JINGLE_TRANSPORT_GOOGLE_V1) {
832 iks_insert_attrib(transport, "xmlns", GOOGLE_TRANSPORT_NS);
835 it = ao2_iterator_init(local_candidates, 0);
837 while ((candidate = ao2_iterator_next(&it)) && (i < maximum)) {
838 iks *local_candidate;
839 /* In Google land a username is 16 bytes, explicitly */
842 if (!(local_candidate = iks_new("candidate"))) {
844 ast_log(LOG_ERROR, "Unable to allocate IKS candidate stanza for Google ICE transport\n");
848 if (candidate->id == 1) {
849 iks_insert_attrib(local_candidate, "name", !video ? "rtp" : "video_rtp");
850 } else if (candidate->id == 2) {
851 iks_insert_attrib(local_candidate, "name", !video ? "rtcp" : "video_rtcp");
853 iks_delete(local_candidate);
857 iks_insert_attrib(local_candidate, "address", ast_sockaddr_stringify_host(&candidate->address));
858 iks_insert_attrib(local_candidate, "port", ast_sockaddr_stringify_port(&candidate->address));
860 if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_HOST) {
861 iks_insert_attrib(local_candidate, "preference", "0.95");
862 iks_insert_attrib(local_candidate, "type", "local");
863 } else if (candidate->type == AST_RTP_ICE_CANDIDATE_TYPE_SRFLX) {
864 iks_insert_attrib(local_candidate, "preference", "0.9");
865 iks_insert_attrib(local_candidate, "type", "stun");
868 iks_insert_attrib(local_candidate, "protocol", "udp");
869 iks_insert_attrib(local_candidate, "network", "0");
870 snprintf(ufrag, sizeof(ufrag), "%s", ice->get_ufrag(rtp));
871 iks_insert_attrib(local_candidate, "username", ufrag);
872 iks_insert_attrib(local_candidate, "generation", "0");
874 if (transport_type == JINGLE_TRANSPORT_GOOGLE_V1) {
875 iks_insert_attrib(local_candidate, "password", "");
876 iks_insert_attrib(local_candidate, "foundation", "0");
877 iks_insert_attrib(local_candidate, "component", "1");
879 iks_insert_attrib(local_candidate, "password", ice->get_password(rtp));
882 /* You may notice a lack of relay support up above - this is because we don't support it for use with
883 * the Google talk transport due to their arcane support. */
885 iks_insert_node(transport, local_candidate);
886 candidates[i++] = local_candidate;
889 ao2_iterator_destroy(&it);
890 ao2_ref(local_candidates, -1);
895 /*! \brief Internal function which sends a session-terminate message */
896 static void jingle_send_session_terminate(struct jingle_session *session, const char *reasontext)
898 iks *iq = NULL, *jingle = NULL, *reason = NULL, *text = NULL;
900 if (!(iq = iks_new("iq")) || !(jingle = iks_new(session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "session" : "jingle")) ||
901 !(reason = iks_new("reason")) || !(text = iks_new(reasontext))) {
902 ast_log(LOG_ERROR, "Failed to allocate stanzas for session-terminate message on session '%s'\n", session->sid);
906 iks_insert_attrib(iq, "to", session->remote);
907 iks_insert_attrib(iq, "type", "set");
908 iks_insert_attrib(iq, "id", session->connection->mid);
909 ast_xmpp_increment_mid(session->connection->mid);
911 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
912 iks_insert_attrib(jingle, "type", "terminate");
913 iks_insert_attrib(jingle, "id", session->sid);
914 iks_insert_attrib(jingle, "xmlns", GOOGLE_SESSION_NS);
915 iks_insert_attrib(jingle, "initiator", session->outgoing ? session->connection->jid->full : session->remote);
917 iks_insert_attrib(jingle, "action", "session-terminate");
918 iks_insert_attrib(jingle, "sid", session->sid);
919 iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
922 iks_insert_node(iq, jingle);
923 iks_insert_node(jingle, reason);
924 iks_insert_node(reason, text);
926 ast_xmpp_client_send(session->connection, iq);
935 /*! \brief Internal function which sends a session-info message */
936 static void jingle_send_session_info(struct jingle_session *session, const char *info)
938 iks *iq = NULL, *jingle = NULL, *text = NULL;
940 /* Google-V1 has no way to send informational messages so don't even bother trying */
941 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
945 if (!(iq = iks_new("iq")) || !(jingle = iks_new("jingle")) || !(text = iks_new(info))) {
946 ast_log(LOG_ERROR, "Failed to allocate stanzas for session-info message on session '%s'\n", session->sid);
950 iks_insert_attrib(iq, "to", session->remote);
951 iks_insert_attrib(iq, "type", "set");
952 iks_insert_attrib(iq, "id", session->connection->mid);
953 ast_xmpp_increment_mid(session->connection->mid);
955 iks_insert_attrib(jingle, "action", "session-info");
956 iks_insert_attrib(jingle, "sid", session->sid);
957 iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
958 iks_insert_node(iq, jingle);
959 iks_insert_node(jingle, text);
961 ast_xmpp_client_send(session->connection, iq);
971 * \brief Locks both pvt and pvt owner if owner is present.
973 * \note This function gives a ref to pvt->owner if it is present and locked.
974 * This reference must be decremented after pvt->owner is unlocked.
976 * \note This function will never give you up,
977 * \note This function will never let you down.
978 * \note This function will run around and desert you.
980 * \pre pvt is not locked
981 * \post pvt is locked
982 * \post pvt->owner is locked and its reference count is increased (if pvt->owner is not NULL)
984 * \returns a pointer to the locked and reffed pvt->owner channel if it exists.
986 static struct ast_channel *jingle_session_lock_full(struct jingle_session *pvt)
988 struct ast_channel *chan;
990 /* Locking is simple when it is done right. If you see a deadlock resulting
991 * in this function, it is not this function's fault, Your problem exists elsewhere.
992 * This function is perfect... seriously. */
994 /* First, get the channel and grab a reference to it */
998 /* The channel can not go away while we hold the pvt lock.
999 * Give the channel a ref so it will not go away after we let
1000 * the pvt lock go. */
1001 ast_channel_ref(chan);
1003 /* no channel, return pvt locked */
1007 /* We had to hold the pvt lock while getting a ref to the owner channel
1008 * but now we have to let this lock go in order to preserve proper
1009 * locking order when grabbing the channel lock */
1012 /* Look, no deadlock avoidance, hooray! */
1013 ast_channel_lock(chan);
1015 if (pvt->owner == chan) {
1020 /* If the owner changed while everything was unlocked, no problem,
1021 * just start over and everthing will work. This is rare, do not be
1022 * confused by this loop and think this it is an expensive operation.
1023 * The majority of the calls to this function will never involve multiple
1024 * executions of this loop. */
1025 ast_channel_unlock(chan);
1026 ast_channel_unref(chan);
1030 /* If owner exists, it is locked and reffed */
1034 /*! \brief Helper function which queues a hangup frame with cause code */
1035 static void jingle_queue_hangup_with_cause(struct jingle_session *session, int cause)
1037 struct ast_channel *chan;
1039 if ((chan = jingle_session_lock_full(session))) {
1040 ast_debug(3, "Hanging up channel '%s' with cause '%d'\n", ast_channel_name(chan), cause);
1041 ast_queue_hangup_with_cause(chan, cause);
1042 ast_channel_unlock(chan);
1043 ast_channel_unref(chan);
1045 ao2_unlock(session);
1048 /*! \brief Internal function which sends a transport-info message */
1049 static void jingle_send_transport_info(struct jingle_session *session, const char *from)
1051 iks *iq, *jingle = NULL, *audio = NULL, *audio_transport = NULL, *video = NULL, *video_transport = NULL;
1052 iks *audio_candidates[session->maxicecandidates], *video_candidates[session->maxicecandidates];
1055 if (!(iq = iks_new("iq")) ||
1056 !(jingle = iks_new(session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "session" : "jingle"))) {
1058 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
1059 ast_log(LOG_ERROR, "Failed to allocate stanzas for transport-info message, hanging up session '%s'\n", session->sid);
1063 memset(audio_candidates, 0, sizeof(audio_candidates));
1064 memset(video_candidates, 0, sizeof(video_candidates));
1066 iks_insert_attrib(iq, "from", session->connection->jid->full);
1067 iks_insert_attrib(iq, "to", from);
1068 iks_insert_attrib(iq, "type", "set");
1069 iks_insert_attrib(iq, "id", session->connection->mid);
1070 ast_xmpp_increment_mid(session->connection->mid);
1072 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
1073 iks_insert_attrib(jingle, "type", "candidates");
1074 iks_insert_attrib(jingle, "id", session->sid);
1075 iks_insert_attrib(jingle, "xmlns", GOOGLE_SESSION_NS);
1076 iks_insert_attrib(jingle, "initiator", session->outgoing ? session->connection->jid->full : from);
1078 iks_insert_attrib(jingle, "action", "transport-info");
1079 iks_insert_attrib(jingle, "sid", session->sid);
1080 iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
1082 iks_insert_node(iq, jingle);
1085 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
1086 /* V1 protocol has the candidates directly in the session */
1087 res = jingle_add_google_candidates_to_transport(session->rtp, jingle, audio_candidates, 0, session->transport, session->maxicecandidates);
1088 } else if ((audio = iks_new("content")) && (audio_transport = iks_new("transport"))) {
1089 iks_insert_attrib(audio, "creator", session->outgoing ? "initiator" : "responder");
1090 iks_insert_attrib(audio, "name", session->audio_name);
1091 iks_insert_node(jingle, audio);
1092 iks_insert_node(audio, audio_transport);
1094 if (session->transport == JINGLE_TRANSPORT_ICE_UDP) {
1095 res = jingle_add_ice_udp_candidates_to_transport(session->rtp, audio_transport, audio_candidates, session->maxicecandidates);
1096 } else if (session->transport == JINGLE_TRANSPORT_GOOGLE_V2) {
1097 res = jingle_add_google_candidates_to_transport(session->rtp, audio_transport, audio_candidates, 0, session->transport,
1098 session->maxicecandidates);
1105 if ((session->transport != JINGLE_TRANSPORT_GOOGLE_V1) && !res && session->vrtp) {
1106 if ((video = iks_new("content")) && (video_transport = iks_new("transport"))) {
1107 iks_insert_attrib(video, "creator", session->outgoing ? "initiator" : "responder");
1108 iks_insert_attrib(video, "name", session->video_name);
1109 iks_insert_node(jingle, video);
1110 iks_insert_node(video, video_transport);
1112 if (session->transport == JINGLE_TRANSPORT_ICE_UDP) {
1113 res = jingle_add_ice_udp_candidates_to_transport(session->vrtp, video_transport, video_candidates, session->maxicecandidates);
1114 } else if (session->transport == JINGLE_TRANSPORT_GOOGLE_V2) {
1115 res = jingle_add_google_candidates_to_transport(session->vrtp, video_transport, video_candidates, 1, session->transport,
1116 session->maxicecandidates);
1124 ast_xmpp_client_send(session->connection, iq);
1126 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
1129 /* Clean up after ourselves */
1130 for (i = 0; i < session->maxicecandidates; i++) {
1131 iks_delete(video_candidates[i]);
1132 iks_delete(audio_candidates[i]);
1135 iks_delete(video_transport);
1137 iks_delete(audio_transport);
1143 /*! \brief Internal helper function which adds payloads to a description */
1144 static int jingle_add_payloads_to_description(struct jingle_session *session, struct ast_rtp_instance *rtp, iks *description, iks **payloads, enum ast_format_type type)
1146 struct ast_format format;
1147 int x = 0, i = 0, res = 0;
1149 for (x = 0; (x < AST_CODEC_PREF_SIZE) && (i < (session->maxpayloads - 2)); x++) {
1154 if (!ast_codec_pref_index(&session->prefs, x, &format)) {
1158 if (AST_FORMAT_GET_TYPE(format.id) != type) {
1162 if (!ast_format_cap_iscompatible(session->jointcap, &format)) {
1166 if (((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(rtp), 1, &format, 0)) == -1) ||
1167 (!(payload = iks_new("payload-type")))) {
1171 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
1172 iks_insert_attrib(payload, "xmlns", GOOGLE_PHONE_NS);
1175 snprintf(tmp, sizeof(tmp), "%d", rtp_code);
1176 iks_insert_attrib(payload, "id", tmp);
1177 iks_insert_attrib(payload, "name", ast_rtp_lookup_mime_subtype2(1, &format, 0, 0));
1178 iks_insert_attrib(payload, "channels", "1");
1180 if ((format.id == AST_FORMAT_G722) && ((session->transport == JINGLE_TRANSPORT_GOOGLE_V1) || (session->transport == JINGLE_TRANSPORT_GOOGLE_V2))) {
1181 iks_insert_attrib(payload, "clockrate", "16000");
1183 snprintf(tmp, sizeof(tmp), "%d", ast_rtp_lookup_sample_rate2(1, &format, 0));
1184 iks_insert_attrib(payload, "clockrate", tmp);
1187 if ((type == AST_FORMAT_TYPE_VIDEO) && (session->transport == JINGLE_TRANSPORT_GOOGLE_V2)) {
1190 /* Google requires these parameters to be set, but alas we can not give accurate values so use some safe defaults */
1191 if ((parameter = iks_new("parameter"))) {
1192 iks_insert_attrib(parameter, "name", "width");
1193 iks_insert_attrib(parameter, "value", "640");
1194 iks_insert_node(payload, parameter);
1196 if ((parameter = iks_new("parameter"))) {
1197 iks_insert_attrib(parameter, "name", "height");
1198 iks_insert_attrib(parameter, "value", "480");
1199 iks_insert_node(payload, parameter);
1201 if ((parameter = iks_new("parameter"))) {
1202 iks_insert_attrib(parameter, "name", "framerate");
1203 iks_insert_attrib(parameter, "value", "30");
1204 iks_insert_node(payload, parameter);
1208 iks_insert_node(description, payload);
1209 payloads[i++] = payload;
1211 /* If this is for audio and there is room for RFC2833 add it in */
1212 if ((type == AST_FORMAT_TYPE_AUDIO) && (i < session->maxpayloads)) {
1215 if ((payload = iks_new("payload-type"))) {
1216 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
1217 iks_insert_attrib(payload, "xmlns", GOOGLE_PHONE_NS);
1220 iks_insert_attrib(payload, "id", "101");
1221 iks_insert_attrib(payload, "name", "telephone-event");
1222 iks_insert_attrib(payload, "channels", "1");
1223 iks_insert_attrib(payload, "clockrate", "8000");
1224 iks_insert_node(description, payload);
1225 payloads[i++] = payload;
1232 /*! \brief Helper function which adds content to a description */
1233 static int jingle_add_content(struct jingle_session *session, iks *jingle, iks *content, iks *description, iks *transport,
1234 const char *name, enum ast_format_type type, struct ast_rtp_instance *rtp, iks **payloads)
1238 if (session->transport != JINGLE_TRANSPORT_GOOGLE_V1) {
1239 iks_insert_attrib(content, "creator", session->outgoing ? "initiator" : "responder");
1240 iks_insert_attrib(content, "name", name);
1241 iks_insert_node(jingle, content);
1243 iks_insert_attrib(description, "xmlns", JINGLE_RTP_NS);
1244 if (type == AST_FORMAT_TYPE_AUDIO) {
1245 iks_insert_attrib(description, "media", "audio");
1246 } else if (type == AST_FORMAT_TYPE_VIDEO) {
1247 iks_insert_attrib(description, "media", "video");
1251 iks_insert_node(content, description);
1253 iks_insert_attrib(description, "xmlns", GOOGLE_PHONE_NS);
1254 iks_insert_node(jingle, description);
1257 if (!(res = jingle_add_payloads_to_description(session, rtp, description, payloads, type))) {
1258 if (session->transport == JINGLE_TRANSPORT_ICE_UDP) {
1259 iks_insert_attrib(transport, "xmlns", JINGLE_ICE_UDP_NS);
1260 iks_insert_node(content, transport);
1261 } else if (session->transport == JINGLE_TRANSPORT_GOOGLE_V2) {
1262 iks_insert_attrib(transport, "xmlns", GOOGLE_TRANSPORT_NS);
1263 iks_insert_node(content, transport);
1270 /*! \brief Internal function which sends a complete session message */
1271 static void jingle_send_session_action(struct jingle_session *session, const char *action)
1273 iks *iq, *jingle, *audio = NULL, *audio_description = NULL, *video = NULL, *video_description = NULL;
1274 iks *audio_payloads[session->maxpayloads], *video_payloads[session->maxpayloads];
1275 iks *audio_transport = NULL, *video_transport = NULL;
1278 if (!(iq = iks_new("iq")) ||
1279 !(jingle = iks_new(session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "session" : "jingle"))) {
1280 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
1285 memset(audio_payloads, 0, sizeof(audio_payloads));
1286 memset(video_payloads, 0, sizeof(video_payloads));
1288 iks_insert_attrib(iq, "from", session->connection->jid->full);
1289 iks_insert_attrib(iq, "to", session->remote);
1290 iks_insert_attrib(iq, "type", "set");
1291 iks_insert_attrib(iq, "id", session->connection->mid);
1292 ast_xmpp_increment_mid(session->connection->mid);
1294 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
1295 iks_insert_attrib(jingle, "type", action);
1296 iks_insert_attrib(jingle, "id", session->sid);
1297 iks_insert_attrib(jingle, "xmlns", GOOGLE_SESSION_NS);
1299 iks_insert_attrib(jingle, "action", action);
1300 iks_insert_attrib(jingle, "sid", session->sid);
1301 iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
1304 if (!strcasecmp(action, "session-initiate") || !strcasecmp(action, "initiate") || !strcasecmp(action, "accept")) {
1305 iks_insert_attrib(jingle, "initiator", session->outgoing ? session->connection->jid->full : session->remote);
1308 iks_insert_node(iq, jingle);
1310 if (session->rtp && (audio = iks_new("content")) && (audio_description = iks_new("description")) &&
1311 (audio_transport = iks_new("transport"))) {
1312 res = jingle_add_content(session, jingle, audio, audio_description, audio_transport, session->audio_name,
1313 AST_FORMAT_TYPE_AUDIO, session->rtp, audio_payloads);
1315 ast_log(LOG_ERROR, "Failed to allocate audio content stanzas for session '%s', hanging up\n", session->sid);
1319 if ((session->transport != JINGLE_TRANSPORT_GOOGLE_V1) && !res && session->vrtp) {
1320 if ((video = iks_new("content")) && (video_description = iks_new("description")) &&
1321 (video_transport = iks_new("transport"))) {
1322 res = jingle_add_content(session, jingle, video, video_description, video_transport, session->video_name,
1323 AST_FORMAT_TYPE_VIDEO, session->vrtp, video_payloads);
1325 ast_log(LOG_ERROR, "Failed to allocate video content stanzas for session '%s', hanging up\n", session->sid);
1331 ast_xmpp_client_send(session->connection, iq);
1333 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
1336 iks_delete(video_transport);
1337 iks_delete(audio_transport);
1339 for (i = 0; i < session->maxpayloads; i++) {
1340 iks_delete(video_payloads[i]);
1341 iks_delete(audio_payloads[i]);
1344 iks_delete(video_description);
1346 iks_delete(audio_description);
1352 /*! \brief Internal function which sends a session-inititate message */
1353 static void jingle_send_session_initiate(struct jingle_session *session)
1355 jingle_send_session_action(session, session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "initiate" : "session-initiate");
1358 /*! \brief Internal function which sends a session-accept message */
1359 static void jingle_send_session_accept(struct jingle_session *session)
1361 jingle_send_session_action(session, session->transport == JINGLE_TRANSPORT_GOOGLE_V1 ? "accept" : "session-accept");
1364 /*! \brief Callback for when a response is received for an outgoing session-initiate message */
1365 static int jingle_outgoing_hook(void *data, ikspak *pak)
1367 struct jingle_session *session = data;
1368 iks *error = iks_find(pak->x, "error"), *redirect;
1370 /* In all cases this hook is done with */
1371 iks_filter_remove_rule(session->connection->filter, session->rule);
1372 session->rule = NULL;
1374 ast_callid_threadassoc_add(session->callid);
1376 /* If no error occurred they accepted our session-initiate message happily */
1378 struct ast_channel *chan;
1380 if ((chan = jingle_session_lock_full(session))) {
1381 ast_queue_control(chan, AST_CONTROL_PROCEEDING);
1382 ast_channel_unlock(chan);
1383 ast_channel_unref(chan);
1385 ao2_unlock(session);
1387 jingle_send_transport_info(session, iks_find_attrib(pak->x, "from"));
1392 /* Assume that because this is an error the session is gone, there is only one case where this is incorrect - a redirect */
1395 /* Map the error we received to an appropriate cause code and hang up the channel */
1396 if ((redirect = iks_find_with_attrib(error, "redirect", "xmlns", XMPP_STANZAS_NS))) {
1397 iks *to = iks_child(redirect);
1400 if (to && (target = iks_name(to)) && !ast_strlen_zero(target)) {
1401 /* Make the xmpp: go away if it is present */
1402 if (!strncmp(target, "xmpp:", 5)) {
1406 /* This is actually a fairly simple operation - we update the remote and send another session-initiate */
1407 ast_copy_string(session->remote, target, sizeof(session->remote));
1409 /* Add a new hook so we can get the status of redirected session */
1410 session->rule = iks_filter_add_rule(session->connection->filter, jingle_outgoing_hook, session,
1411 IKS_RULE_ID, session->connection->mid, IKS_RULE_DONE);
1413 jingle_send_session_initiate(session);
1417 jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
1419 } else if (iks_find_with_attrib(error, "service-unavailable", "xmlns", XMPP_STANZAS_NS)) {
1420 jingle_queue_hangup_with_cause(session, AST_CAUSE_CONGESTION);
1421 } else if (iks_find_with_attrib(error, "resource-constraint", "xmlns", XMPP_STANZAS_NS)) {
1422 jingle_queue_hangup_with_cause(session, AST_CAUSE_REQUESTED_CHAN_UNAVAIL);
1423 } else if (iks_find_with_attrib(error, "bad-request", "xmlns", XMPP_STANZAS_NS)) {
1424 jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
1425 } else if (iks_find_with_attrib(error, "remote-server-not-found", "xmlns", XMPP_STANZAS_NS)) {
1426 jingle_queue_hangup_with_cause(session, AST_CAUSE_NO_ROUTE_DESTINATION);
1427 } else if (iks_find_with_attrib(error, "feature-not-implemented", "xmlns", XMPP_STANZAS_NS)) {
1428 /* Assume that this occurred because the remote side does not support our transport, so drop it down one and try again */
1429 session->transport--;
1431 /* If we still have a viable transport mechanism re-send the session-initiate */
1432 if (session->transport != JINGLE_TRANSPORT_NONE) {
1433 struct ast_rtp_engine_ice *ice;
1435 if (((session->transport == JINGLE_TRANSPORT_GOOGLE_V2) ||
1436 (session->transport == JINGLE_TRANSPORT_GOOGLE_V1)) &&
1437 (ice = ast_rtp_instance_get_ice(session->rtp))) {
1438 /* We stop built in ICE support because we need to fall back to old old old STUN support */
1439 ice->stop(session->rtp);
1442 /* Re-send the message to the *original* target and not a redirected one */
1443 ast_copy_string(session->remote, session->remote_original, sizeof(session->remote));
1445 session->rule = iks_filter_add_rule(session->connection->filter, jingle_outgoing_hook, session,
1446 IKS_RULE_ID, session->connection->mid, IKS_RULE_DONE);
1448 jingle_send_session_initiate(session);
1452 /* Otherwise we have exhausted all transports */
1453 jingle_queue_hangup_with_cause(session, AST_CAUSE_FACILITY_NOT_IMPLEMENTED);
1456 jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
1460 ast_callid_threadassoc_remove();
1462 return IKS_FILTER_EAT;
1465 /*! \brief Function called by core when we should answer a Jingle session */
1466 static int jingle_answer(struct ast_channel *ast)
1468 struct jingle_session *session = ast_channel_tech_pvt(ast);
1470 /* The channel has already been answered so we don't need to do anything */
1471 if (ast_channel_state(ast) == AST_STATE_UP) {
1475 jingle_send_session_accept(session);
1480 /*! \brief Function called by core to read any waiting frames */
1481 static struct ast_frame *jingle_read(struct ast_channel *ast)
1483 struct jingle_session *session = ast_channel_tech_pvt(ast);
1484 struct ast_frame *frame = &ast_null_frame;
1486 switch (ast_channel_fdno(ast)) {
1489 frame = ast_rtp_instance_read(session->rtp, 0);
1494 frame = ast_rtp_instance_read(session->rtp, 1);
1498 if (session->vrtp) {
1499 frame = ast_rtp_instance_read(session->vrtp, 0);
1503 if (session->vrtp) {
1504 frame = ast_rtp_instance_read(session->vrtp, 1);
1511 if (frame && frame->frametype == AST_FRAME_VOICE &&
1512 !ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &frame->subclass.format)) {
1513 if (!ast_format_cap_iscompatible(session->jointcap, &frame->subclass.format)) {
1514 ast_debug(1, "Bogus frame of format '%s' received from '%s'!\n",
1515 ast_getformatname(&frame->subclass.format), ast_channel_name(ast));
1517 frame = &ast_null_frame;
1519 ast_debug(1, "Oooh, format changed to %s\n",
1520 ast_getformatname(&frame->subclass.format));
1521 ast_format_cap_remove_bytype(ast_channel_nativeformats(ast), AST_FORMAT_TYPE_AUDIO);
1522 ast_format_cap_add(ast_channel_nativeformats(ast), &frame->subclass.format);
1523 ast_set_read_format(ast, ast_channel_readformat(ast));
1524 ast_set_write_format(ast, ast_channel_writeformat(ast));
1531 /*! \brief Function called by core to write frames */
1532 static int jingle_write(struct ast_channel *ast, struct ast_frame *frame)
1534 struct jingle_session *session = ast_channel_tech_pvt(ast);
1538 switch (frame->frametype) {
1539 case AST_FRAME_VOICE:
1540 if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &frame->subclass.format))) {
1541 ast_log(LOG_WARNING,
1542 "Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n",
1543 ast_getformatname(&frame->subclass.format),
1544 ast_getformatname_multiple(buf, sizeof(buf), ast_channel_nativeformats(ast)),
1545 ast_getformatname(ast_channel_readformat(ast)),
1546 ast_getformatname(ast_channel_writeformat(ast)));
1549 if (session && session->rtp) {
1550 res = ast_rtp_instance_write(session->rtp, frame);
1553 case AST_FRAME_VIDEO:
1554 if (session && session->vrtp) {
1555 res = ast_rtp_instance_write(session->vrtp, frame);
1559 ast_log(LOG_WARNING, "Can't send %d type frames with Jingle write\n",
1567 /*! \brief Function called by core to change the underlying owner channel */
1568 static int jingle_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
1570 struct jingle_session *session = ast_channel_tech_pvt(newchan);
1574 session->owner = newchan;
1576 ao2_unlock(session);
1581 /*! \brief Function called by core to ask the channel to indicate some sort of condition */
1582 static int jingle_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
1584 struct jingle_session *session = ast_channel_tech_pvt(ast);
1587 switch (condition) {
1588 case AST_CONTROL_RINGING:
1589 if (ast_channel_state(ast) == AST_STATE_RING) {
1590 jingle_send_session_info(session, "ringing xmlns='urn:xmpp:jingle:apps:rtp:info:1'");
1595 case AST_CONTROL_BUSY:
1596 if (ast_channel_state(ast) != AST_STATE_UP) {
1597 ast_channel_hangupcause_set(ast, AST_CAUSE_BUSY);
1598 ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
1603 case AST_CONTROL_CONGESTION:
1604 if (ast_channel_state(ast) != AST_STATE_UP) {
1605 ast_channel_hangupcause_set(ast, AST_CAUSE_CONGESTION);
1606 ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
1611 case AST_CONTROL_INCOMPLETE:
1612 if (ast_channel_state(ast) != AST_STATE_UP) {
1613 ast_channel_hangupcause_set(ast, AST_CAUSE_CONGESTION);
1614 ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
1617 case AST_CONTROL_HOLD:
1618 ast_moh_start(ast, data, NULL);
1620 case AST_CONTROL_UNHOLD:
1623 case AST_CONTROL_SRCUPDATE:
1625 ast_rtp_instance_update_source(session->rtp);
1628 case AST_CONTROL_SRCCHANGE:
1630 ast_rtp_instance_change_source(session->rtp);
1633 case AST_CONTROL_VIDUPDATE:
1634 case AST_CONTROL_UPDATE_RTP_PEER:
1635 case AST_CONTROL_CONNECTED_LINE:
1637 case AST_CONTROL_PVT_CAUSE_CODE:
1642 ast_log(LOG_NOTICE, "Don't know how to indicate condition '%d'\n", condition);
1649 /*! \brief Function called by core to send text to the remote party of the Jingle session */
1650 static int jingle_sendtext(struct ast_channel *chan, const char *text)
1652 struct jingle_session *session = ast_channel_tech_pvt(chan);
1654 return ast_xmpp_client_send_message(session->connection, session->remote, text);
1657 /*! \brief Function called by core to start a DTMF digit */
1658 static int jingle_digit_begin(struct ast_channel *chan, char digit)
1660 struct jingle_session *session = ast_channel_tech_pvt(chan);
1663 ast_rtp_instance_dtmf_begin(session->rtp, digit);
1669 /*! \brief Function called by core to stop a DTMF digit */
1670 static int jingle_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
1672 struct jingle_session *session = ast_channel_tech_pvt(ast);
1675 ast_rtp_instance_dtmf_end_with_duration(session->rtp, digit, duration);
1681 /*! \brief Function called by core to actually start calling a remote party */
1682 static int jingle_call(struct ast_channel *ast, const char *dest, int timeout)
1684 struct jingle_session *session = ast_channel_tech_pvt(ast);
1686 ast_setstate(ast, AST_STATE_RING);
1688 /* Since we have no idea of the remote capabilities use ours for now */
1689 ast_format_cap_copy(session->jointcap, session->cap);
1691 /* We set up a hook so we can know when our session-initiate message was accepted or rejected */
1692 session->rule = iks_filter_add_rule(session->connection->filter, jingle_outgoing_hook, session,
1693 IKS_RULE_ID, session->connection->mid, IKS_RULE_DONE);
1695 jingle_send_session_initiate(session);
1700 /*! \brief Function called by core to hang up a Jingle session */
1701 static int jingle_hangup(struct ast_channel *ast)
1703 struct jingle_session *session = ast_channel_tech_pvt(ast);
1707 if ((ast_channel_state(ast) != AST_STATE_DOWN) && !session->gone) {
1708 int cause = (session->owner ? ast_channel_hangupcause(session->owner) : AST_CAUSE_CONGESTION);
1709 const char *reason = "success";
1712 /* Get the appropriate reason and send a session-terminate */
1713 for (i = 0; i < ARRAY_LEN(jingle_reason_mappings); i++) {
1714 if (jingle_reason_mappings[i].cause == cause) {
1715 reason = jingle_reason_mappings[i].reason;
1720 jingle_send_session_terminate(session, reason);
1723 ast_channel_tech_pvt_set(ast, NULL);
1724 session->owner = NULL;
1726 ao2_unlink(session->state->sessions, session);
1727 ao2_ref(session->state, -1);
1729 ao2_unlock(session);
1730 ao2_ref(session, -1);
1735 /*! \brief Function called by core to create a new outgoing Jingle session */
1736 static struct ast_channel *jingle_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
1738 RAII_VAR(struct jingle_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
1739 RAII_VAR(struct jingle_endpoint *, endpoint, NULL, ao2_cleanup);
1740 char *dialed, target[200] = "";
1741 struct ast_xmpp_buddy *buddy;
1742 struct jingle_session *session;
1743 struct ast_channel *chan;
1744 enum jingle_transport transport = JINGLE_TRANSPORT_NONE;
1745 struct ast_rtp_engine_ice *ice;
1746 AST_DECLARE_APP_ARGS(args,
1748 AST_APP_ARG(target);
1751 /* We require at a minimum one audio format to be requested */
1752 if (!ast_format_cap_has_type(cap, AST_FORMAT_TYPE_AUDIO)) {
1753 ast_log(LOG_ERROR, "Motif channel driver requires an audio format when dialing a destination\n");
1754 *cause = AST_CAUSE_BEARERCAPABILITY_NOTAVAIL;
1758 if (ast_strlen_zero(data) || !(dialed = ast_strdupa(data))) {
1759 ast_log(LOG_ERROR, "Unable to create channel with empty destination.\n");
1760 *cause = AST_CAUSE_CHANNEL_UNACCEPTABLE;
1764 /* Parse the given dial string and validate the results */
1765 AST_NONSTANDARD_APP_ARGS(args, dialed, '/');
1767 if (ast_strlen_zero(args.name) || ast_strlen_zero(args.target)) {
1768 ast_log(LOG_ERROR, "Unable to determine endpoint name and target.\n");
1769 *cause = AST_CAUSE_CHANNEL_UNACCEPTABLE;
1773 if (!(endpoint = jingle_endpoint_find(cfg->endpoints, args.name))) {
1774 ast_log(LOG_ERROR, "Endpoint '%s' does not exist.\n", args.name);
1775 *cause = AST_CAUSE_CHANNEL_UNACCEPTABLE;
1779 ao2_lock(endpoint->state);
1781 /* If we don't have a connection for the endpoint we can't exactly start a session on it */
1782 if (!endpoint->connection) {
1783 ast_log(LOG_ERROR, "Unable to create Jingle session on endpoint '%s' as no valid connection exists\n", args.name);
1784 *cause = AST_CAUSE_SWITCH_CONGESTION;
1785 ao2_unlock(endpoint->state);
1789 /* Find the target in the roster so we can choose a resource */
1790 if ((buddy = ao2_find(endpoint->connection->buddies, args.target, OBJ_KEY))) {
1791 struct ao2_iterator res;
1792 struct ast_xmpp_resource *resource;
1794 /* Iterate through finding the first viable Jingle capable resource */
1795 res = ao2_iterator_init(buddy->resources, 0);
1796 while ((resource = ao2_iterator_next(&res))) {
1797 if (resource->caps.jingle) {
1798 snprintf(target, sizeof(target), "%s/%s", args.target, resource->resource);
1799 transport = JINGLE_TRANSPORT_ICE_UDP;
1801 } else if (resource->caps.google) {
1802 snprintf(target, sizeof(target), "%s/%s", args.target, resource->resource);
1803 transport = JINGLE_TRANSPORT_GOOGLE_V2;
1806 ao2_ref(resource, -1);
1808 ao2_iterator_destroy(&res);
1812 /* If the target is NOT in the roster use the provided target as-is */
1813 ast_copy_string(target, args.target, sizeof(target));
1816 ao2_unlock(endpoint->state);
1818 /* If no target was found we can't set up a session */
1819 if (ast_strlen_zero(target)) {
1820 ast_log(LOG_ERROR, "Unable to create Jingle session on endpoint '%s' as no capable resource for target '%s' was found\n", args.name, args.target);
1821 *cause = AST_CAUSE_SWITCH_CONGESTION;
1825 if (!(session = jingle_alloc(endpoint, target, NULL))) {
1826 ast_log(LOG_ERROR, "Unable to create Jingle session on endpoint '%s'\n", args.name);
1827 *cause = AST_CAUSE_SWITCH_CONGESTION;
1831 /* Update the transport if we learned what we should actually use */
1832 if (transport != JINGLE_TRANSPORT_NONE) {
1833 session->transport = transport;
1834 /* Note that for Google-V1 and Google-V2 we don't stop built-in ICE support, this will happen in jingle_new */
1837 if (!(chan = jingle_new(endpoint, session, AST_STATE_DOWN, target, requestor ? ast_channel_linkedid(requestor) : NULL, NULL))) {
1838 ast_log(LOG_ERROR, "Unable to create Jingle channel on endpoint '%s'\n", args.name);
1839 *cause = AST_CAUSE_SWITCH_CONGESTION;
1840 ao2_ref(session, -1);
1844 /* If video was requested try to enable it on the session */
1845 if (ast_format_cap_has_type(cap, AST_FORMAT_TYPE_VIDEO)) {
1846 jingle_enable_video(session);
1849 /* As this is outgoing set ourselves as controlling */
1850 if (session->rtp && (ice = ast_rtp_instance_get_ice(session->rtp))) {
1851 ice->ice_lite(session->rtp);
1854 if (session->vrtp && (ice = ast_rtp_instance_get_ice(session->vrtp))) {
1855 ice->ice_lite(session->vrtp);
1858 /* We purposely don't decrement the session here as there is a reference on the channel */
1859 ao2_link(endpoint->state->sessions, session);
1864 /*! \brief Helper function which handles content descriptions */
1865 static int jingle_interpret_description(struct jingle_session *session, iks *description, const char *name, struct ast_rtp_instance **rtp)
1867 char *media = iks_find_attrib(description, "media");
1868 struct ast_rtp_codecs codecs;
1870 int othercapability = 0;
1872 /* Google-V1 is always carrying audio, but just doesn't tell us so */
1873 if (session->transport == JINGLE_TRANSPORT_GOOGLE_V1) {
1875 } else if (ast_strlen_zero(media)) {
1876 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
1877 ast_log(LOG_ERROR, "Received a content description on session '%s' without a name\n", session->sid);
1881 /* Determine the type of media that is being carried and update the RTP instance, as well as the name */
1882 if (!strcasecmp(media, "audio")) {
1883 if (!ast_strlen_zero(name)) {
1884 ast_string_field_set(session, audio_name, name);
1886 *rtp = session->rtp;
1887 ast_format_cap_remove_bytype(session->peercap, AST_FORMAT_TYPE_AUDIO);
1888 ast_format_cap_remove_bytype(session->jointcap, AST_FORMAT_TYPE_AUDIO);
1889 } else if (!strcasecmp(media, "video")) {
1890 if (!ast_strlen_zero(name)) {
1891 ast_string_field_set(session, video_name, name);
1894 jingle_enable_video(session);
1895 *rtp = session->vrtp;
1897 /* If video is not present cancel this session */
1898 if (!session->vrtp) {
1899 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
1900 ast_log(LOG_ERROR, "Received a video content description on session '%s' but could not enable video\n", session->sid);
1904 ast_format_cap_remove_bytype(session->peercap, AST_FORMAT_TYPE_VIDEO);
1905 ast_format_cap_remove_bytype(session->jointcap, AST_FORMAT_TYPE_VIDEO);
1907 /* Unknown media type */
1908 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
1909 ast_log(LOG_ERROR, "Unsupported media type '%s' received in content description on session '%s'\n", media, session->sid);
1913 if (ast_rtp_codecs_payloads_initialize(&codecs)) {
1914 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
1915 ast_log(LOG_ERROR, "Could not initialize codecs for negotiation on session '%s'\n", session->sid);
1919 /* Iterate the codecs updating the relevant RTP instance as we go */
1920 for (codec = iks_child(description); codec; codec = iks_next(codec)) {
1921 char *id = iks_find_attrib(codec, "id"), *name = iks_find_attrib(codec, "name");
1922 char *clockrate = iks_find_attrib(codec, "clockrate");
1923 int rtp_id, rtp_clockrate;
1925 if (!ast_strlen_zero(id) && !ast_strlen_zero(name) && (sscanf(id, "%30d", &rtp_id) == 1)) {
1926 ast_rtp_codecs_payloads_set_m_type(&codecs, NULL, rtp_id);
1928 if (!ast_strlen_zero(clockrate) && (sscanf(clockrate, "%30d", &rtp_clockrate) == 1)) {
1929 ast_rtp_codecs_payloads_set_rtpmap_type_rate(&codecs, NULL, rtp_id, media, name, 0, rtp_clockrate);
1931 ast_rtp_codecs_payloads_set_rtpmap_type(&codecs, NULL, rtp_id, media, name, 0);
1936 ast_rtp_codecs_payload_formats(&codecs, session->peercap, &othercapability);
1937 ast_format_cap_joint_append(session->cap, session->peercap, session->jointcap);
1939 if (ast_format_cap_is_empty(session->jointcap)) {
1940 /* We have no compatible codecs, so terminate the session appropriately */
1941 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
1942 ast_rtp_codecs_payloads_destroy(&codecs);
1946 ast_rtp_codecs_payloads_copy(&codecs, ast_rtp_instance_get_codecs(*rtp), *rtp);
1947 ast_rtp_codecs_payloads_destroy(&codecs);
1952 /*! \brief Helper function which handles ICE-UDP transport information */
1953 static int jingle_interpret_ice_udp_transport(struct jingle_session *session, iks *transport, struct ast_rtp_instance *rtp)
1955 struct ast_rtp_engine_ice *ice = ast_rtp_instance_get_ice(rtp);
1956 char *ufrag = iks_find_attrib(transport, "ufrag"), *pwd = iks_find_attrib(transport, "pwd");
1960 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
1961 ast_log(LOG_ERROR, "Received ICE-UDP transport information on session '%s' but ICE support not available\n", session->sid);
1965 if (!ast_strlen_zero(ufrag) && !ast_strlen_zero(pwd)) {
1966 ice->set_authentication(rtp, ufrag, pwd);
1969 for (candidate = iks_child(transport); candidate; candidate = iks_next(candidate)) {
1970 char *component = iks_find_attrib(candidate, "component"), *foundation = iks_find_attrib(candidate, "foundation");
1971 char *generation = iks_find_attrib(candidate, "generation"), *id = iks_find_attrib(candidate, "id");
1972 char *ip = iks_find_attrib(candidate, "ip"), *port = iks_find_attrib(candidate, "port");
1973 char *priority = iks_find_attrib(candidate, "priority"), *protocol = iks_find_attrib(candidate, "protocol");
1974 char *type = iks_find_attrib(candidate, "type");
1975 struct ast_rtp_engine_ice_candidate local_candidate = { 0, };
1977 struct ast_sockaddr remote_address = { { 0, } };
1979 /* If this candidate is incomplete skip it */
1980 if (ast_strlen_zero(component) || ast_strlen_zero(foundation) || ast_strlen_zero(generation) || ast_strlen_zero(id) ||
1981 ast_strlen_zero(ip) || ast_strlen_zero(port) || ast_strlen_zero(priority) ||
1982 ast_strlen_zero(protocol) || ast_strlen_zero(type)) {
1983 jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
1984 ast_log(LOG_ERROR, "Incomplete ICE-UDP candidate received on session '%s'\n", session->sid);
1988 if ((sscanf(component, "%30u", &local_candidate.id) != 1) ||
1989 (sscanf(priority, "%30u", &local_candidate.priority) != 1) ||
1990 (sscanf(port, "%30d", &real_port) != 1)) {
1991 jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
1992 ast_log(LOG_ERROR, "Invalid ICE-UDP candidate information received on session '%s'\n", session->sid);
1996 local_candidate.foundation = foundation;
1997 local_candidate.transport = protocol;
1999 ast_sockaddr_parse(&local_candidate.address, ip, PARSE_PORT_FORBID);
2001 /* We only support IPv4 right now */
2002 if (!ast_sockaddr_is_ipv4(&local_candidate.address)) {
2006 ast_sockaddr_set_port(&local_candidate.address, real_port);
2008 if (!strcasecmp(type, "host")) {
2009 local_candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_HOST;
2010 } else if (!strcasecmp(type, "srflx")) {
2011 local_candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_SRFLX;
2012 } else if (!strcasecmp(type, "relay")) {
2013 local_candidate.type = AST_RTP_ICE_CANDIDATE_TYPE_RELAYED;
2018 /* Worst case use the first viable address */
2019 ast_rtp_instance_get_remote_address(rtp, &remote_address);
2021 if (ast_sockaddr_is_ipv4(&local_candidate.address) && ast_sockaddr_isnull(&remote_address)) {
2022 ast_rtp_instance_set_remote_address(rtp, &local_candidate.address);
2025 ice->add_remote_candidate(rtp, &local_candidate);
2033 /*! \brief Helper function which handles Google transport information */
2034 static int jingle_interpret_google_transport(struct jingle_session *session, iks *transport, struct ast_rtp_instance *rtp)
2036 struct ast_rtp_engine_ice *ice = ast_rtp_instance_get_ice(rtp);
2040 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
2041 ast_log(LOG_ERROR, "Received Google transport information on session '%s' but ICE support not available\n", session->sid);
2045 /* If this session has not transitioned to the Google transport do so now */
2046 if ((session->transport != JINGLE_TRANSPORT_GOOGLE_V2) &&
2047 (session->transport != JINGLE_TRANSPORT_GOOGLE_V1)) {
2048 /* Stop built-in ICE support... we need to fall back to the old old old STUN */
2051 session->transport = JINGLE_TRANSPORT_GOOGLE_V2;
2054 for (candidate = iks_child(transport); candidate; candidate = iks_next(candidate)) {
2055 char *address = iks_find_attrib(candidate, "address"), *port = iks_find_attrib(candidate, "port");
2056 char *username = iks_find_attrib(candidate, "username"), *name = iks_find_attrib(candidate, "name");
2057 char *protocol = iks_find_attrib(candidate, "protocol");
2059 struct ast_sockaddr target = { { 0, } };
2060 /* In Google land the combined value is 32 bytes */
2061 char combined[33] = "";
2063 /* If this is NOT actually a candidate just skip it */
2064 if (strcasecmp(iks_name(candidate), "candidate") &&
2065 strcasecmp(iks_name(candidate), "p:candidate") &&
2066 strcasecmp(iks_name(candidate), "ses:candidate")) {
2070 /* If this candidate is incomplete skip it */
2071 if (ast_strlen_zero(address) || ast_strlen_zero(port) || ast_strlen_zero(username) ||
2072 ast_strlen_zero(name)) {
2073 jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
2074 ast_log(LOG_ERROR, "Incomplete Google candidate received on session '%s'\n", session->sid);
2078 /* We only support UDP so skip any other protocols */
2079 if (!ast_strlen_zero(protocol) && strcasecmp(protocol, "udp")) {
2083 /* We only permit audio and video, not RTCP */
2084 if (strcasecmp(name, "rtp") && strcasecmp(name, "video_rtp")) {
2088 /* Parse the target information so we can send a STUN request to the candidate */
2089 if (sscanf(port, "%30d", &real_port) != 1) {
2090 jingle_queue_hangup_with_cause(session, AST_CAUSE_PROTOCOL_ERROR);
2091 ast_log(LOG_ERROR, "Invalid Google candidate port '%s' received on session '%s'\n", port, session->sid);
2094 ast_sockaddr_parse(&target, address, PARSE_PORT_FORBID);
2095 ast_sockaddr_set_port(&target, real_port);
2097 /* Per the STUN support Google talk uses combine the two usernames */
2098 snprintf(combined, sizeof(combined), "%s%s", username, ice->get_ufrag(rtp));
2100 /* This should appease the masses... we will actually change the remote address when we get their STUN packet */
2101 ast_rtp_instance_stun_request(rtp, &target, combined);
2108 * \brief Helper function which locates content stanzas and interprets them
2110 * \note The session *must not* be locked before calling this
2112 static int jingle_interpret_content(struct jingle_session *session, ikspak *pak)
2115 unsigned int changed = 0;
2116 struct ast_channel *chan;
2118 /* Look at the content in the session initiation */
2119 for (content = iks_child(iks_child(pak->x)); content; content = iks_next(content)) {
2121 struct ast_rtp_instance *rtp = NULL;
2122 iks *description, *transport;
2124 /* Ignore specific parts if they are known not to be useful */
2125 if (!strcmp(iks_name(content), "conference-info")) {
2129 name = iks_find_attrib(content, "name");
2131 if (session->transport != JINGLE_TRANSPORT_GOOGLE_V1) {
2132 /* If this content stanza has no name consider it invalid and move on */
2133 if (ast_strlen_zero(name) && !(name = iks_find_attrib(content, "jin:name"))) {
2134 jingle_queue_hangup_with_cause(session, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
2135 ast_log(LOG_ERROR, "Received content without a name on session '%s'\n", session->sid);
2139 /* Try to pre-populate which RTP instance this content is relevant to */
2140 if (!strcmp(session->audio_name, name)) {
2142 } else if (!strcmp(session->video_name, name)) {
2143 rtp = session->vrtp;
2146 /* Google-V1 has no concept of assocating things like the above does, so since we only support audio over it assume they want audio */
2150 /* If description information is available use it */
2151 if ((description = iks_find_with_attrib(content, "description", "xmlns", JINGLE_RTP_NS)) ||
2152 (description = iks_find_with_attrib(content, "rtp:description", "xmlns:rtp", JINGLE_RTP_NS)) ||
2153 (description = iks_find_with_attrib(content, "pho:description", "xmlns:pho", GOOGLE_PHONE_NS)) ||
2154 (description = iks_find_with_attrib(pak->query, "description", "xmlns", GOOGLE_PHONE_NS)) ||
2155 (description = iks_find_with_attrib(pak->query, "pho:description", "xmlns:pho", GOOGLE_PHONE_NS)) ||
2156 (description = iks_find_with_attrib(pak->query, "vid:description", "xmlns", GOOGLE_VIDEO_NS))) {
2157 /* If we failed to do something with the content description abort immediately */
2158 if (jingle_interpret_description(session, description, name, &rtp)) {
2162 /* If we successfully interpret the description then the codecs need updating */
2166 /* If we get past the description handling and we still don't know what RTP instance this is for... it is unknown content */
2168 ast_log(LOG_ERROR, "Received a content stanza but have no RTP instance for it on session '%s'\n", session->sid);
2169 jingle_queue_hangup_with_cause(session, AST_CAUSE_SWITCH_CONGESTION);
2173 /* If ICE UDP transport information is available use it */
2174 if ((transport = iks_find_with_attrib(content, "transport", "xmlns", JINGLE_ICE_UDP_NS))) {
2175 if (jingle_interpret_ice_udp_transport(session, transport, rtp)) {
2178 } else if ((transport = iks_find_with_attrib(content, "transport", "xmlns", GOOGLE_TRANSPORT_NS)) ||
2179 (transport = iks_find_with_attrib(content, "p:transport", "xmlns:p", GOOGLE_TRANSPORT_NS)) ||
2180 (transport = iks_find_with_attrib(pak->x, "session", "xmlns", GOOGLE_SESSION_NS)) ||
2181 (transport = iks_find_with_attrib(pak->x, "ses:session", "xmlns:ses", GOOGLE_SESSION_NS))) {
2182 /* If Google transport support is available use it */
2183 if (jingle_interpret_google_transport(session, transport, rtp)) {
2186 } else if (iks_find(content, "transport")) {
2187 /* If this is a transport we do not support terminate the session as it probably won't work out in the end */
2188 jingle_queue_hangup_with_cause(session, AST_CAUSE_FACILITY_NOT_IMPLEMENTED);
2189 ast_log(LOG_ERROR, "Unsupported transport type received on session '%s'\n", session->sid);
2198 if ((chan = jingle_session_lock_full(session))) {
2199 struct ast_format fmt;
2201 ast_format_cap_copy(ast_channel_nativeformats(chan), session->jointcap);
2202 ast_codec_choose(&session->prefs, session->jointcap, 1, &fmt);
2203 ast_set_read_format(chan, &fmt);
2204 ast_set_write_format(chan, &fmt);
2206 ast_channel_unlock(chan);
2207 ast_channel_unref(chan);
2209 ao2_unlock(session);
2214 /*! \brief Handler function for the 'session-initiate' action */
2215 static void jingle_action_session_initiate(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2218 enum jingle_transport transport = JINGLE_TRANSPORT_NONE;
2219 struct ast_channel *chan;
2223 /* This is a duplicate session setup, so respond accordingly */
2224 jingle_send_error_response(endpoint->connection, pak, "result", "out-of-order", NULL);
2228 /* Retrieve the session identifier from the message, note that this may alter the transport */
2229 if ((sid = iks_find_attrib(pak->query, "id"))) {
2230 /* The presence of the session identifier in the 'id' attribute tells us that this is Google-V1 as everything else uses 'sid' */
2231 transport = JINGLE_TRANSPORT_GOOGLE_V1;
2232 } else if (!(sid = iks_find_attrib(pak->query, "sid"))) {
2233 jingle_send_error_response(endpoint->connection, pak, "bad-request", NULL, NULL);
2237 /* Create a new local session */
2238 if (!(session = jingle_alloc(endpoint, pak->from->full, sid))) {
2239 jingle_send_error_response(endpoint->connection, pak, "cancel", "service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
2243 /* If we determined that the transport should change as a result of how we got the SID change it */
2244 if (transport != JINGLE_TRANSPORT_NONE) {
2245 session->transport = transport;
2248 /* Create a new Asterisk channel using the above local session */
2249 if (!(chan = jingle_new(endpoint, session, AST_STATE_DOWN, pak->from->user, NULL, pak->from->full))) {
2250 ao2_ref(session, -1);
2251 jingle_send_error_response(endpoint->connection, pak, "cancel", "service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
2255 ao2_link(endpoint->state->sessions, session);
2257 ast_setstate(chan, AST_STATE_RING);
2258 res = ast_pbx_start(chan);
2261 case AST_PBX_FAILED:
2262 ast_log(LOG_WARNING, "Failed to start PBX :(\n");
2263 jingle_send_error_response(endpoint->connection, pak, "cancel", "service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
2267 case AST_PBX_CALL_LIMIT:
2268 ast_log(LOG_WARNING, "Failed to start PBX (call limit reached) \n");
2269 jingle_send_error_response(endpoint->connection, pak, "wait", "resource-constraint xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'", NULL);
2272 case AST_PBX_SUCCESS:
2273 jingle_send_response(endpoint->connection, pak);
2275 /* Only send a transport-info message if we successfully interpreted the available content */
2276 if (!jingle_interpret_content(session, pak)) {
2277 jingle_send_transport_info(session, iks_find_attrib(pak->x, "from"));
2283 /*! \brief Handler function for the 'transport-info' action */
2284 static void jingle_action_transport_info(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2287 jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
2288 "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
2292 jingle_interpret_content(session, pak);
2293 jingle_send_response(endpoint->connection, pak);
2296 /*! \brief Handler function for the 'session-accept' action */
2297 static void jingle_action_session_accept(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2299 struct ast_channel *chan;
2302 jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
2303 "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
2308 jingle_interpret_content(session, pak);
2310 if ((chan = jingle_session_lock_full(session))) {
2311 ast_queue_control(chan, AST_CONTROL_ANSWER);
2312 ast_channel_unlock(chan);
2313 ast_channel_unref(chan);
2315 ao2_unlock(session);
2317 jingle_send_response(endpoint->connection, pak);
2320 /*! \brief Handler function for the 'session-info' action */
2321 static void jingle_action_session_info(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2323 struct ast_channel *chan;
2326 jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
2327 "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
2331 if (!(chan = jingle_session_lock_full(session))) {
2332 ao2_unlock(session);
2333 jingle_send_response(endpoint->connection, pak);
2337 if (iks_find_with_attrib(pak->query, "ringing", "xmlns", JINGLE_RTP_INFO_NS)) {
2338 ast_queue_control(chan, AST_CONTROL_RINGING);
2339 if (ast_channel_state(chan) != AST_STATE_UP) {
2340 ast_setstate(chan, AST_STATE_RINGING);
2342 } else if (iks_find_with_attrib(pak->query, "hold", "xmlns", JINGLE_RTP_INFO_NS)) {
2343 ast_queue_control(chan, AST_CONTROL_HOLD);
2344 } else if (iks_find_with_attrib(pak->query, "unhold", "xmlns", JINGLE_RTP_INFO_NS)) {
2345 ast_queue_control(chan, AST_CONTROL_UNHOLD);
2348 ast_channel_unlock(chan);
2349 ast_channel_unref(chan);
2350 ao2_unlock(session);
2352 jingle_send_response(endpoint->connection, pak);
2355 /*! \brief Handler function for the 'session-terminate' action */
2356 static void jingle_action_session_terminate(struct jingle_endpoint *endpoint, struct jingle_session *session, ikspak *pak)
2358 struct ast_channel *chan;
2360 int cause = AST_CAUSE_NORMAL;
2363 jingle_send_error_response(endpoint->connection, pak, "cancel", "item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
2364 "unknown-session xmlns='urn:xmpp:jingle:errors:1'");
2368 if (!(chan = jingle_session_lock_full(session))) {
2369 ao2_unlock(session);
2370 jingle_send_response(endpoint->connection, pak);
2374 /* Pull the reason text from the session-terminate message and translate it into a cause code */
2375 if ((reason = iks_find(pak->query, "reason")) && (text = iks_child(reason))) {
2378 /* Get the appropriate cause code mapping for this reason */
2379 for (i = 0; i < ARRAY_LEN(jingle_reason_mappings); i++) {
2380 if (!strcasecmp(jingle_reason_mappings[i].reason, iks_name(text))) {
2381 cause = jingle_reason_mappings[i].cause;
2387 ast_debug(3, "Hanging up channel '%s' due to session terminate message with cause '%d'\n", ast_channel_name(chan), cause);
2388 ast_queue_hangup_with_cause(chan, cause);
2391 ast_channel_unlock(chan);
2392 ast_channel_unref(chan);
2393 ao2_unlock(session);
2395 jingle_send_response(endpoint->connection, pak);
2398 /*! \brief Callback for when a Jingle action is received from an endpoint */
2399 static int jingle_action_hook(void *data, ikspak *pak)
2402 const char *sid = NULL;
2403 struct jingle_session *session = NULL;
2404 struct jingle_endpoint *endpoint = data;
2407 /* We accept both Jingle and Google-V1 */
2408 if (!(action = iks_find_attrib(pak->query, "action")) &&
2409 !(action = iks_find_attrib(pak->query, "type"))) {
2410 /* This occurs if either receive a packet masquerading as Jingle or Google-V1 that is actually not OR we receive a response
2411 * to a message that has no response hook. */
2412 return IKS_FILTER_EAT;
2415 /* Bump the endpoint reference count up in case a reload occurs. Unfortunately the available synchronization between iksemel and us
2416 * does not permit us to make this completely safe. */
2417 ao2_ref(endpoint, +1);
2419 /* If a Jingle session identifier is present use it */
2420 if (!(sid = iks_find_attrib(pak->query, "sid"))) {
2421 /* If a Google-V1 session identifier is present use it */
2422 sid = iks_find_attrib(pak->query, "id");
2425 /* If a session identifier was present in the message attempt to find the session, it is up to the action handler whether
2426 * this is required or not */
2427 if (!ast_strlen_zero(sid)) {
2428 session = ao2_find(endpoint->state->sessions, sid, OBJ_KEY);
2431 /* If a session is present associate the callid with this thread */
2433 ast_callid_threadassoc_add(session->callid);
2436 /* Iterate through supported action handlers looking for one that is able to handle this */
2437 for (i = 0; i < ARRAY_LEN(jingle_action_handlers); i++) {
2438 if (!strcasecmp(jingle_action_handlers[i].action, action)) {
2439 jingle_action_handlers[i].handler(endpoint, session, pak);
2445 /* If no action handler is present for the action they sent us make it evident */
2447 ast_log(LOG_NOTICE, "Received action '%s' for session '%s' that has no handler\n", action, sid);
2450 /* If a session was successfully found for this message deref it now since the handler is done */
2452 ast_callid_threadassoc_remove();
2453 ao2_ref(session, -1);
2456 ao2_ref(endpoint, -1);
2458 return IKS_FILTER_EAT;
2461 /*! \brief Custom handler for groups */
2462 static int custom_group_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2464 struct jingle_endpoint *endpoint = obj;
2466 if (!strcasecmp(var->name, "callgroup")) {
2467 endpoint->callgroup = ast_get_group(var->value);
2468 } else if (!strcasecmp(var->name, "pickupgroup")) {
2469 endpoint->pickupgroup = ast_get_group(var->value);
2477 /*! \brief Custom handler for connection */
2478 static int custom_connection_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2480 struct jingle_endpoint *endpoint = obj;
2482 /* You might think... but Josh, shouldn't you do this in a prelink callback? Well I *could* but until the original is destroyed
2483 * this will not actually get called, so even if the config turns out to be bogus this is harmless.
2485 if (!(endpoint->connection = ast_xmpp_client_find(var->value))) {
2486 ast_log(LOG_ERROR, "Connection '%s' configured on endpoint '%s' could not be found\n", var->value, endpoint->name);
2490 if (!(endpoint->rule = iks_filter_add_rule(endpoint->connection->filter, jingle_action_hook, endpoint,
2491 IKS_RULE_TYPE, IKS_PAK_IQ,
2492 IKS_RULE_NS, JINGLE_NS,
2493 IKS_RULE_NS, GOOGLE_SESSION_NS,
2495 ast_log(LOG_ERROR, "Action hook could not be added to connection '%s' on endpoint '%s'\n", var->value, endpoint->name);
2502 /*! \brief Custom handler for transport */
2503 static int custom_transport_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
2505 struct jingle_endpoint *endpoint = obj;
2507 if (!strcasecmp(var->value, "ice-udp")) {
2508 endpoint->transport = JINGLE_TRANSPORT_ICE_UDP;
2509 } else if (!strcasecmp(var->value, "google")) {
2510 endpoint->transport = JINGLE_TRANSPORT_GOOGLE_V2;
2511 } else if (!strcasecmp(var->value, "google-v1")) {
2512 endpoint->transport = JINGLE_TRANSPORT_GOOGLE_V1;
2514 ast_log(LOG_WARNING, "Unknown transport type '%s' on endpoint '%s', defaulting to 'ice-udp'\n", var->value, endpoint->name);
2515 endpoint->transport = JINGLE_TRANSPORT_ICE_UDP;
2522 * \brief Load the module
2524 * Module loading including tests for configuration or dependencies.
2525 * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
2526 * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
2527 * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
2528 * configuration file or other non-critical problem return
2529 * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
2531 static int load_module(void)
2533 if (!(jingle_tech.capabilities = ast_format_cap_alloc())) {
2534 return AST_MODULE_LOAD_DECLINE;
2537 if (aco_info_init(&cfg_info)) {
2538 ast_log(LOG_ERROR, "Unable to intialize configuration for chan_motif.\n");
2542 aco_option_register(&cfg_info, "context", ACO_EXACT, endpoint_options, "default", OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, context));
2543 aco_option_register_custom(&cfg_info, "callgroup", ACO_EXACT, endpoint_options, NULL, custom_group_handler, 0);
2544 aco_option_register_custom(&cfg_info, "pickupgroup", ACO_EXACT, endpoint_options, NULL, custom_group_handler, 0);
2545 aco_option_register(&cfg_info, "language", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, language));
2546 aco_option_register(&cfg_info, "musicclass", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, musicclass));
2547 aco_option_register(&cfg_info, "parkinglot", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, parkinglot));
2548 aco_option_register(&cfg_info, "accountcode", ACO_EXACT, endpoint_options, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct jingle_endpoint, accountcode));
2549 aco_option_register(&cfg_info, "allow", ACO_EXACT, endpoint_options, "ulaw,alaw", OPT_CODEC_T, 1, FLDSET(struct jingle_endpoint, prefs, cap));
2550 aco_option_register(&cfg_info, "disallow", ACO_EXACT, endpoint_options, "all", OPT_CODEC_T, 0, FLDSET(struct jingle_endpoint, prefs, cap));
2551 aco_option_register_custom(&cfg_info, "connection", ACO_EXACT, endpoint_options, NULL, custom_connection_handler, 0);
2552 aco_option_register_custom(&cfg_info, "transport", ACO_EXACT, endpoint_options, NULL, custom_transport_handler, 0);
2553 aco_option_register(&cfg_info, "maxicecandidates", ACO_EXACT, endpoint_options, DEFAULT_MAX_ICE_CANDIDATES, OPT_UINT_T, PARSE_DEFAULT,
2554 FLDSET(struct jingle_endpoint, maxicecandidates));
2555 aco_option_register(&cfg_info, "maxpayloads", ACO_EXACT, endpoint_options, DEFAULT_MAX_PAYLOADS, OPT_UINT_T, PARSE_DEFAULT,
2556 FLDSET(struct jingle_endpoint, maxpayloads));
2558 ast_format_cap_add_all_by_type(jingle_tech.capabilities, AST_FORMAT_TYPE_AUDIO);
2560 if (aco_process_config(&cfg_info, 0)) {
2561 ast_log(LOG_ERROR, "Unable to read config file motif.conf. Not loading module.\n");
2562 aco_info_destroy(&cfg_info);
2563 return AST_MODULE_LOAD_DECLINE;
2566 if (!(sched = ast_sched_context_create())) {
2567 ast_log(LOG_ERROR, "Unable to create scheduler context.\n");
2571 if (ast_sched_start_thread(sched)) {
2572 ast_log(LOG_ERROR, "Unable to create scheduler context thread.\n");
2576 ast_rtp_glue_register(&jingle_rtp_glue);
2578 if (ast_channel_register(&jingle_tech)) {
2579 ast_log(LOG_ERROR, "Unable to register channel class %s\n", channel_type);
2586 ast_rtp_glue_unregister(&jingle_rtp_glue);
2589 ast_sched_context_destroy(sched);
2592 aco_info_destroy(&cfg_info);
2594 return AST_MODULE_LOAD_FAILURE;
2597 /*! \brief Reload module */
2598 static int reload(void)
2600 return aco_process_config(&cfg_info, 1);
2603 /*! \brief Unload the jingle channel from Asterisk */
2604 static int unload_module(void)
2606 ast_channel_unregister(&jingle_tech);
2607 ast_rtp_glue_unregister(&jingle_rtp_glue);
2608 ast_sched_context_destroy(sched);
2609 aco_info_destroy(&cfg_info);
2610 ao2_global_obj_release(globals);
2615 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Motif Jingle Channel Driver",
2616 .load = load_module,
2617 .unload = unload_module,
2619 .load_pri = AST_MODPRI_CHANNEL_DRIVER,