2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2005, Digium, Inc.
6 * Matt O'Gorman <mogorman@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 Matt O'Gorman <mogorman@digium.com>
23 * \brief Jingle Channel Driver
25 * Iksemel http://iksemel.jabberstudio.org/
27 * \ingroup channel_drivers
30 /*! \li \ref chan_jingle.c uses the configuration file \ref jingle.conf
31 * \addtogroup configuration_file
34 /*! \page jingle.conf jingle.conf
35 * \verbinclude jingle.conf.sample
39 <depend>iksemel</depend>
40 <depend>res_jabber</depend>
41 <use type="external">openssl</use>
42 <defaultenabled>no</defaultenabled>
43 <support_level>deprecated</support_level>
44 <replacement>chan_motif</replacement>
49 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
51 #include <sys/socket.h>
54 #include <netinet/in.h>
55 #include <arpa/inet.h>
56 #include <sys/signal.h>
60 #include "asterisk/lock.h"
61 #include "asterisk/channel.h"
62 #include "asterisk/config.h"
63 #include "asterisk/module.h"
64 #include "asterisk/pbx.h"
65 #include "asterisk/sched.h"
66 #include "asterisk/io.h"
67 #include "asterisk/rtp_engine.h"
68 #include "asterisk/acl.h"
69 #include "asterisk/callerid.h"
70 #include "asterisk/file.h"
71 #include "asterisk/cli.h"
72 #include "asterisk/app.h"
73 #include "asterisk/musiconhold.h"
74 #include "asterisk/manager.h"
75 #include "asterisk/stringfields.h"
76 #include "asterisk/utils.h"
77 #include "asterisk/causes.h"
78 #include "asterisk/astobj.h"
79 #include "asterisk/abstract_jb.h"
80 #include "asterisk/jabber.h"
81 #include "asterisk/jingle.h"
83 #define JINGLE_CONFIG "jingle.conf"
85 /*! Global jitterbuffer configuration - by default, jb is disabled */
86 static struct ast_jb_conf default_jbconf =
90 .resync_threshold = -1,
94 static struct ast_jb_conf global_jbconf;
96 enum jingle_protocol {
101 enum jingle_connect_type {
109 ast_mutex_t lock; /*!< Channel private lock */
111 struct jingle *parent; /*!< Parent client */
113 char them[AJI_MAX_JIDLEN];
114 char ring[10]; /*!< Message ID of ring */
115 iksrule *ringrule; /*!< Rule for matching RING request */
116 int initiator; /*!< If we're the initiator */
118 struct ast_codec_pref prefs;
119 struct jingle_candidate *theircandidates;
120 struct jingle_candidate *ourcandidates;
121 char cid_num[80]; /*!< Caller ID num */
122 char cid_name[80]; /*!< Caller ID name */
123 char exten[80]; /*!< Called extension */
124 struct ast_channel *owner; /*!< Master Channel */
125 char audio_content_name[100]; /*!< name attribute of content tag */
126 struct ast_rtp_instance *rtp; /*!< RTP audio session */
127 char video_content_name[100]; /*!< name attribute of content tag */
128 struct ast_rtp_instance *vrtp; /*!< RTP video session */
129 struct ast_format_cap *cap;
130 struct ast_format_cap *jointcap; /*!< Supported capability at both ends (codecs ) */
131 struct ast_format_cap *peercap;
132 struct jingle_pvt *next; /* Next entity */
135 struct jingle_candidate {
136 unsigned int component; /*!< ex. : 1 for RTP, 2 for RTCP */
137 unsigned int foundation; /*!< Function of IP, protocol, type */
138 unsigned int generation;
140 unsigned int network;
142 unsigned int priority;
143 enum jingle_protocol protocol;
145 enum jingle_connect_type type;
147 unsigned int preference;
148 struct jingle_candidate *next;
152 ASTOBJ_COMPONENTS(struct jingle);
153 struct aji_client *connection;
154 struct aji_buddy *buddy;
155 struct jingle_pvt *p;
156 struct ast_codec_pref prefs;
157 int amaflags; /*!< AMA Flags */
160 char accountcode[AST_MAX_ACCOUNT_CODE]; /*!< Account code */
161 struct ast_format_cap *cap;
162 ast_group_t callgroup; /*!< Call group */
163 ast_group_t pickupgroup; /*!< Pickup group */
164 int callingpres; /*!< Calling presentation */
166 char language[MAX_LANGUAGE]; /*!< Default language for prompts */
167 char musicclass[MAX_MUSICCLASS]; /*!< Music on Hold class */
168 char parkinglot[AST_MAX_CONTEXT]; /*!< Parkinglot */
171 struct jingle_container {
172 ASTOBJ_CONTAINER_COMPONENTS(struct jingle);
175 static const char desc[] = "Jingle Channel";
176 static const char channel_type[] = "Jingle";
178 static struct ast_format_cap *global_capability;
180 AST_MUTEX_DEFINE_STATIC(jinglelock); /*!< Protect the interface list (of jingle_pvt's) */
182 /* Forward declarations */
183 static struct ast_channel *jingle_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause);
184 static int jingle_sendtext(struct ast_channel *ast, const char *text);
185 static int jingle_digit_begin(struct ast_channel *ast, char digit);
186 static int jingle_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
187 static int jingle_call(struct ast_channel *ast, const char *dest, int timeout);
188 static int jingle_hangup(struct ast_channel *ast);
189 static int jingle_answer(struct ast_channel *ast);
190 static int jingle_newcall(struct jingle *client, ikspak *pak);
191 static struct ast_frame *jingle_read(struct ast_channel *ast);
192 static int jingle_write(struct ast_channel *ast, struct ast_frame *f);
193 static int jingle_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
194 static int jingle_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
195 static int jingle_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
196 static struct jingle_pvt *jingle_alloc(struct jingle *client, const char *from, const char *sid);
197 static char *jingle_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
198 static char *jingle_do_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
200 /*! \brief PBX interface structure for channel registration */
201 static struct ast_channel_tech jingle_tech = {
203 .description = "Jingle Channel Driver",
204 .requester = jingle_request,
205 .send_text = jingle_sendtext,
206 .send_digit_begin = jingle_digit_begin,
207 .send_digit_end = jingle_digit_end,
208 .bridge = ast_rtp_instance_bridge,
210 .hangup = jingle_hangup,
211 .answer = jingle_answer,
213 .write = jingle_write,
214 .exception = jingle_read,
215 .indicate = jingle_indicate,
216 .fixup = jingle_fixup,
217 .send_html = jingle_sendhtml,
218 .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER
221 static struct sockaddr_in bindaddr = { 0, }; /*!< The address we bind to */
223 static struct ast_sched_context *sched; /*!< The scheduling context */
224 static struct io_context *io; /*!< The IO context */
225 static struct in_addr __ourip;
227 static struct ast_cli_entry jingle_cli[] = {
228 AST_CLI_DEFINE(jingle_do_reload, "Reload Jingle configuration"),
229 AST_CLI_DEFINE(jingle_show_channels, "Show Jingle channels"),
233 static char externip[16];
235 static struct jingle_container jingle_list;
237 static void jingle_member_destroy(struct jingle *obj)
239 obj->cap = ast_format_cap_destroy(obj->cap);
240 if (obj->connection) {
241 ASTOBJ_UNREF(obj->connection, ast_aji_client_destroy);
244 ASTOBJ_UNREF(obj->buddy, ast_aji_buddy_destroy);
249 /* XXX This could be a source of reference leaks given that the CONTAINER_FIND
250 * macros bump the refcount while the traversal does not. */
251 static struct jingle *find_jingle(char *name, char *connection)
253 struct jingle *jingle = NULL;
255 jingle = ASTOBJ_CONTAINER_FIND(&jingle_list, name);
256 if (!jingle && strchr(name, '@'))
257 jingle = ASTOBJ_CONTAINER_FIND_FULL(&jingle_list, name, user,,, strcasecmp);
261 ASTOBJ_CONTAINER_TRAVERSE(&jingle_list, 1, {
262 ASTOBJ_RDLOCK(iterator);
263 if (!strcasecmp(iterator->name, "guest")) {
266 ASTOBJ_UNLOCK(iterator);
277 static void add_codec_to_answer(const struct jingle_pvt *p, struct ast_format *codec, iks *dcodecs)
279 const char *format = ast_getformatname(codec);
281 if (!strcasecmp("ulaw", format)) {
282 iks *payload_eg711u, *payload_pcmu;
283 payload_pcmu = iks_new("payload-type");
284 iks_insert_attrib(payload_pcmu, "id", "0");
285 iks_insert_attrib(payload_pcmu, "name", "PCMU");
286 payload_eg711u = iks_new("payload-type");
287 iks_insert_attrib(payload_eg711u, "id", "100");
288 iks_insert_attrib(payload_eg711u, "name", "EG711U");
289 iks_insert_node(dcodecs, payload_pcmu);
290 iks_insert_node(dcodecs, payload_eg711u);
292 if (!strcasecmp("alaw", format)) {
294 iks *payload_pcma = iks_new("payload-type");
295 iks_insert_attrib(payload_pcma, "id", "8");
296 iks_insert_attrib(payload_pcma, "name", "PCMA");
297 payload_eg711a = iks_new("payload-type");
298 iks_insert_attrib(payload_eg711a, "id", "101");
299 iks_insert_attrib(payload_eg711a, "name", "EG711A");
300 iks_insert_node(dcodecs, payload_pcma);
301 iks_insert_node(dcodecs, payload_eg711a);
303 if (!strcasecmp("ilbc", format)) {
304 iks *payload_ilbc = iks_new("payload-type");
305 iks_insert_attrib(payload_ilbc, "id", "97");
306 iks_insert_attrib(payload_ilbc, "name", "iLBC");
307 iks_insert_node(dcodecs, payload_ilbc);
309 if (!strcasecmp("g723", format)) {
310 iks *payload_g723 = iks_new("payload-type");
311 iks_insert_attrib(payload_g723, "id", "4");
312 iks_insert_attrib(payload_g723, "name", "G723");
313 iks_insert_node(dcodecs, payload_g723);
317 static int jingle_accept_call(struct jingle *client, struct jingle_pvt *p)
319 struct jingle_pvt *tmp = client->p;
320 struct aji_client *c = client->connection;
321 iks *iq, *jingle, *dcodecs, *payload_red, *payload_audio, *payload_cn;
323 struct ast_format pref_codec;
324 struct ast_format_cap *alreadysent = ast_format_cap_alloc_nolock();
326 if (p->initiator || !alreadysent)
330 jingle = iks_new(JINGLE_NODE);
331 dcodecs = iks_new("description");
332 if (iq && jingle && dcodecs) {
333 iks_insert_attrib(dcodecs, "xmlns", JINGLE_AUDIO_RTP_NS);
335 for (x = 0; x < AST_CODEC_PREF_SIZE; x++) {
336 if (!(ast_codec_pref_index(&client->prefs, x, &pref_codec)))
338 if (!(ast_format_cap_iscompatible(client->cap, &pref_codec)))
340 if ((ast_format_cap_iscompatible(alreadysent, &pref_codec)))
342 add_codec_to_answer(p, &pref_codec, dcodecs);
343 ast_format_cap_add(alreadysent, &pref_codec);
345 payload_red = iks_new("payload-type");
346 iks_insert_attrib(payload_red, "id", "117");
347 iks_insert_attrib(payload_red, "name", "red");
348 payload_audio = iks_new("payload-type");
349 iks_insert_attrib(payload_audio, "id", "106");
350 iks_insert_attrib(payload_audio, "name", "audio/telephone-event");
351 payload_cn = iks_new("payload-type");
352 iks_insert_attrib(payload_cn, "id", "13");
353 iks_insert_attrib(payload_cn, "name", "CN");
356 iks_insert_attrib(iq, "type", "set");
357 iks_insert_attrib(iq, "to", (p->them) ? p->them : client->user);
358 iks_insert_attrib(iq, "id", client->connection->mid);
359 ast_aji_increment_mid(client->connection->mid);
361 iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
362 iks_insert_attrib(jingle, "action", JINGLE_ACCEPT);
363 iks_insert_attrib(jingle, "initiator", p->initiator ? client->connection->jid->full : p->them);
364 iks_insert_attrib(jingle, JINGLE_SID, tmp->sid);
365 iks_insert_node(iq, jingle);
366 iks_insert_node(jingle, dcodecs);
367 iks_insert_node(dcodecs, payload_red);
368 iks_insert_node(dcodecs, payload_audio);
369 iks_insert_node(dcodecs, payload_cn);
373 iks_delete(payload_red);
374 iks_delete(payload_audio);
375 iks_delete(payload_cn);
380 alreadysent = ast_format_cap_destroy(alreadysent);
384 static int jingle_ringing_ack(void *data, ikspak *pak)
386 struct jingle_pvt *p = data;
389 iks_filter_remove_rule(p->parent->connection->f, p->ringrule);
392 ast_queue_control(p->owner, AST_CONTROL_RINGING);
393 return IKS_FILTER_EAT;
396 static int jingle_answer(struct ast_channel *ast)
398 struct jingle_pvt *p = ast_channel_tech_pvt(ast);
399 struct jingle *client = p->parent;
402 ast_debug(1, "Answer!\n");
403 ast_mutex_lock(&p->lock);
404 jingle_accept_call(client, p);
405 ast_mutex_unlock(&p->lock);
409 static enum ast_rtp_glue_result jingle_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
411 struct jingle_pvt *p = ast_channel_tech_pvt(chan);
412 enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_FORBID;
417 ast_mutex_lock(&p->lock);
421 res = AST_RTP_GLUE_RESULT_LOCAL;
423 ast_mutex_unlock(&p->lock);
428 static void jingle_get_codec(struct ast_channel *chan, struct ast_format_cap *result)
430 struct jingle_pvt *p = ast_channel_tech_pvt(chan);
431 ast_mutex_lock(&p->lock);
432 ast_format_cap_copy(result, p->peercap);
433 ast_mutex_unlock(&p->lock);
436 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)
438 struct jingle_pvt *p;
440 p = ast_channel_tech_pvt(chan);
443 ast_mutex_lock(&p->lock);
446 ast_rtp_get_peer(rtp, &p->redirip);
448 memset(&p->redirip, 0, sizeof(p->redirip));
449 p->redircodecs = codecs; */
451 /* Reset lastrtprx timer */
452 ast_mutex_unlock(&p->lock);
456 static struct ast_rtp_glue jingle_rtp_glue = {
458 .get_rtp_info = jingle_get_rtp_peer,
459 .get_codec = jingle_get_codec,
460 .update_peer = jingle_set_rtp_peer,
463 static int jingle_response(struct jingle *client, ikspak *pak, const char *reasonstr, const char *reasonstr2)
465 iks *response = NULL, *error = NULL, *reason = NULL;
468 response = iks_new("iq");
470 iks_insert_attrib(response, "type", "result");
471 iks_insert_attrib(response, "from", client->connection->jid->full);
472 iks_insert_attrib(response, "to", iks_find_attrib(pak->x, "from"));
473 iks_insert_attrib(response, "id", iks_find_attrib(pak->x, "id"));
475 error = iks_new("error");
477 iks_insert_attrib(error, "type", "cancel");
478 reason = iks_new(reasonstr);
480 iks_insert_node(error, reason);
481 iks_insert_node(response, error);
484 ast_aji_send(client->connection, response);
490 iks_delete(response);
495 static int jingle_is_answered(struct jingle *client, ikspak *pak)
497 struct jingle_pvt *tmp;
499 ast_debug(1, "The client is %s\n", client->name);
500 /* Make sure our new call doesn't exist yet */
501 for (tmp = client->p; tmp; tmp = tmp->next) {
502 if (iks_find_with_attrib(pak->x, JINGLE_NODE, JINGLE_SID, tmp->sid))
508 ast_queue_control(tmp->owner, AST_CONTROL_ANSWER);
510 ast_log(LOG_NOTICE, "Whoa, didn't find call!\n");
511 jingle_response(client, pak, NULL, NULL);
515 static int jingle_handle_dtmf(struct jingle *client, ikspak *pak)
517 struct jingle_pvt *tmp;
518 iks *dtmfnode = NULL, *dtmfchild = NULL;
520 /* Make sure our new call doesn't exist yet */
521 for (tmp = client->p; tmp; tmp = tmp->next) {
522 if (iks_find_with_attrib(pak->x, JINGLE_NODE, JINGLE_SID, tmp->sid))
527 if(iks_find_with_attrib(pak->x, "dtmf-method", "method", "rtp")) {
528 jingle_response(client,pak,
529 "feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
530 "unsupported-dtmf-method xmlns='http://www.xmpp.org/extensions/xep-0181.html#ns-errors'");
533 if ((dtmfnode = iks_find(pak->x, "dtmf"))) {
534 if((dtmf = iks_find_attrib(dtmfnode, "code"))) {
535 if(iks_find_with_attrib(pak->x, "dtmf", "action", "button-up")) {
536 struct ast_frame f = {AST_FRAME_DTMF_BEGIN, };
537 f.subclass.integer = dtmf[0];
538 ast_queue_frame(tmp->owner, &f);
539 ast_verbose("JINGLE! DTMF-relay event received: %c\n", f.subclass.integer);
540 } else if(iks_find_with_attrib(pak->x, "dtmf", "action", "button-down")) {
541 struct ast_frame f = {AST_FRAME_DTMF_END, };
542 f.subclass.integer = dtmf[0];
543 ast_queue_frame(tmp->owner, &f);
544 ast_verbose("JINGLE! DTMF-relay event received: %c\n", f.subclass.integer);
545 } else if(iks_find_attrib(pak->x, "dtmf")) { /* 250 millasecond default */
546 struct ast_frame f = {AST_FRAME_DTMF, };
547 f.subclass.integer = dtmf[0];
548 ast_queue_frame(tmp->owner, &f);
549 ast_verbose("JINGLE! DTMF-relay event received: %c\n", f.subclass.integer);
552 } else if ((dtmfnode = iks_find_with_attrib(pak->x, JINGLE_NODE, "action", "session-info"))) {
553 if((dtmfchild = iks_find(dtmfnode, "dtmf"))) {
554 if((dtmf = iks_find_attrib(dtmfchild, "code"))) {
555 if(iks_find_with_attrib(dtmfnode, "dtmf", "action", "button-up")) {
556 struct ast_frame f = {AST_FRAME_DTMF_END, };
557 f.subclass.integer = dtmf[0];
558 ast_queue_frame(tmp->owner, &f);
559 ast_verbose("JINGLE! DTMF-relay event received: %c\n", f.subclass.integer);
560 } else if(iks_find_with_attrib(dtmfnode, "dtmf", "action", "button-down")) {
561 struct ast_frame f = {AST_FRAME_DTMF_BEGIN, };
562 f.subclass.integer = dtmf[0];
563 ast_queue_frame(tmp->owner, &f);
564 ast_verbose("JINGLE! DTMF-relay event received: %c\n", f.subclass.integer);
569 jingle_response(client, pak, NULL, NULL);
572 ast_log(LOG_NOTICE, "Whoa, didn't find call!\n");
574 jingle_response(client, pak, NULL, NULL);
579 static int jingle_hangup_farend(struct jingle *client, ikspak *pak)
581 struct jingle_pvt *tmp;
583 ast_debug(1, "The client is %s\n", client->name);
584 /* Make sure our new call doesn't exist yet */
585 for (tmp = client->p; tmp; tmp = tmp->next) {
586 if (iks_find_with_attrib(pak->x, JINGLE_NODE, JINGLE_SID, tmp->sid))
591 tmp->alreadygone = 1;
593 ast_queue_hangup(tmp->owner);
595 ast_log(LOG_NOTICE, "Whoa, didn't find call!\n");
596 jingle_response(client, pak, NULL, NULL);
600 static int jingle_create_candidates(struct jingle *client, struct jingle_pvt *p, char *sid, char *from)
602 struct jingle_candidate *tmp;
603 struct aji_client *c = client->connection;
604 struct jingle_candidate *ours1 = NULL, *ours2 = NULL;
605 struct sockaddr_in sin = { 0, };
606 struct ast_sockaddr sin_tmp;
607 struct ast_sockaddr us_tmp;
608 struct ast_sockaddr bindaddr_tmp;
610 struct in_addr externaddr;
611 iks *iq, *jingle, *content, *transport, *candidate;
612 char component[16], foundation[16], generation[16], network[16], pass[16], port[7], priority[16], user[16];
616 jingle = iks_new(JINGLE_NODE);
617 content = iks_new("content");
618 transport = iks_new("transport");
619 candidate = iks_new("candidate");
620 if (!iq || !jingle || !content || !transport || !candidate) {
621 ast_log(LOG_ERROR, "Memory allocation error\n");
624 ours1 = ast_calloc(1, sizeof(*ours1));
625 ours2 = ast_calloc(1, sizeof(*ours2));
626 if (!ours1 || !ours2)
629 iks_insert_node(iq, jingle);
630 iks_insert_node(jingle, content);
631 iks_insert_node(content, transport);
632 iks_insert_node(transport, candidate);
634 for (; p; p = p->next) {
635 if (!strcasecmp(p->sid, sid))
640 ast_log(LOG_NOTICE, "No matching jingle session - SID %s!\n", sid);
644 ast_rtp_instance_get_local_address(p->rtp, &sin_tmp);
645 ast_sockaddr_to_sin(&sin_tmp, &sin);
646 ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
647 ast_find_ourip(&us_tmp, &bindaddr_tmp, AF_INET);
648 us.s_addr = htonl(ast_sockaddr_ipv4(&us_tmp));
650 /* Setup our first jingle candidate */
651 ours1->component = 1;
652 ours1->foundation = (unsigned int)bindaddr.sin_addr.s_addr | AJI_CONNECT_HOST | AJI_PROTOCOL_UDP;
653 ours1->generation = 0;
654 ast_copy_string(ours1->ip, ast_inet_ntoa(us), sizeof(ours1->ip));
656 ours1->port = ntohs(sin.sin_port);
657 ours1->priority = 1678246398;
658 ours1->protocol = AJI_PROTOCOL_UDP;
659 snprintf(pass, sizeof(pass), "%08lx%08lx", ast_random(), ast_random());
660 ast_copy_string(ours1->password, pass, sizeof(ours1->password));
661 ours1->type = AJI_CONNECT_HOST;
662 snprintf(user, sizeof(user), "%08lx%08lx", ast_random(), ast_random());
663 ast_copy_string(ours1->ufrag, user, sizeof(ours1->ufrag));
664 p->ourcandidates = ours1;
666 if (!ast_strlen_zero(externip)) {
667 /* XXX We should really stun for this one not just go with externip XXX */
668 if (inet_aton(externip, &externaddr))
669 ast_log(LOG_WARNING, "Invalid extern IP : %s\n", externip);
671 ours2->component = 1;
672 ours2->foundation = (unsigned int)externaddr.s_addr | AJI_CONNECT_PRFLX | AJI_PROTOCOL_UDP;
673 ours2->generation = 0;
674 ast_copy_string(ours2->ip, externip, sizeof(ours2->ip));
676 ours2->port = ntohs(sin.sin_port);
677 ours2->priority = 1678246397;
678 ours2->protocol = AJI_PROTOCOL_UDP;
679 snprintf(pass, sizeof(pass), "%08lx%08lx", ast_random(), ast_random());
680 ast_copy_string(ours2->password, pass, sizeof(ours2->password));
681 ours2->type = AJI_CONNECT_PRFLX;
683 snprintf(user, sizeof(user), "%08lx%08lx", ast_random(), ast_random());
684 ast_copy_string(ours2->ufrag, user, sizeof(ours2->ufrag));
690 for (tmp = p->ourcandidates; tmp; tmp = tmp->next) {
691 snprintf(component, sizeof(component), "%u", tmp->component);
692 snprintf(foundation, sizeof(foundation), "%u", tmp->foundation);
693 snprintf(generation, sizeof(generation), "%u", tmp->generation);
694 snprintf(network, sizeof(network), "%u", tmp->network);
695 snprintf(port, sizeof(port), "%u", tmp->port);
696 snprintf(priority, sizeof(priority), "%u", tmp->priority);
698 iks_insert_attrib(iq, "from", c->jid->full);
699 iks_insert_attrib(iq, "to", from);
700 iks_insert_attrib(iq, "type", "set");
701 iks_insert_attrib(iq, "id", c->mid);
702 ast_aji_increment_mid(c->mid);
703 iks_insert_attrib(jingle, "action", JINGLE_NEGOTIATE);
704 iks_insert_attrib(jingle, JINGLE_SID, sid);
705 iks_insert_attrib(jingle, "initiator", (p->initiator) ? c->jid->full : from);
706 iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
707 iks_insert_attrib(content, "creator", p->initiator ? "initiator" : "responder");
708 iks_insert_attrib(content, "name", "asterisk-audio-content");
709 iks_insert_attrib(transport, "xmlns", JINGLE_ICE_UDP_NS);
710 iks_insert_attrib(candidate, "component", component);
711 iks_insert_attrib(candidate, "foundation", foundation);
712 iks_insert_attrib(candidate, "generation", generation);
713 iks_insert_attrib(candidate, "ip", tmp->ip);
714 iks_insert_attrib(candidate, "network", network);
715 iks_insert_attrib(candidate, "port", port);
716 iks_insert_attrib(candidate, "priority", priority);
717 switch (tmp->protocol) {
718 case AJI_PROTOCOL_UDP:
719 iks_insert_attrib(candidate, "protocol", "udp");
721 case AJI_PROTOCOL_SSLTCP:
722 iks_insert_attrib(candidate, "protocol", "ssltcp");
725 iks_insert_attrib(candidate, "pwd", tmp->password);
727 case AJI_CONNECT_HOST:
728 iks_insert_attrib(candidate, "type", "host");
730 case AJI_CONNECT_PRFLX:
731 iks_insert_attrib(candidate, "type", "prflx");
733 case AJI_CONNECT_RELAY:
734 iks_insert_attrib(candidate, "type", "relay");
736 case AJI_CONNECT_SRFLX:
737 iks_insert_attrib(candidate, "type", "srflx");
740 iks_insert_attrib(candidate, "ufrag", tmp->ufrag);
754 iks_delete(transport);
755 iks_delete(candidate);
760 static struct jingle_pvt *jingle_alloc(struct jingle *client, const char *from, const char *sid)
762 struct jingle_pvt *tmp = NULL;
763 struct aji_resource *resources = NULL;
764 struct aji_buddy *buddy = NULL;
766 struct ast_sockaddr bindaddr_tmp;
768 ast_debug(1, "The client is %s for alloc\n", client->name);
769 if (!sid && !strchr(from, '/')) { /* I started call! */
770 if (!strcasecmp(client->name, "guest")) {
771 buddy = ASTOBJ_CONTAINER_FIND(&client->connection->buddies, from);
773 resources = buddy->resources;
775 } else if (client->buddy)
776 resources = client->buddy->resources;
778 if (resources->cap->jingle) {
781 resources = resources->next;
784 snprintf(idroster, sizeof(idroster), "%s/%s", from, resources->resource);
786 ast_log(LOG_ERROR, "no jingle capable clients to talk to.\n");
788 ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
793 ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
796 if (!(tmp = ast_calloc(1, sizeof(*tmp)))) {
800 tmp->cap = ast_format_cap_alloc_nolock();
801 tmp->jointcap = ast_format_cap_alloc_nolock();
802 tmp->peercap = ast_format_cap_alloc_nolock();
803 if (!tmp->cap || !tmp->jointcap || !tmp->peercap) {
804 tmp->cap = ast_format_cap_destroy(tmp->cap);
805 tmp->jointcap = ast_format_cap_destroy(tmp->jointcap);
806 tmp->peercap = ast_format_cap_destroy(tmp->peercap);
810 memcpy(&tmp->prefs, &client->prefs, sizeof(tmp->prefs));
813 ast_copy_string(tmp->sid, sid, sizeof(tmp->sid));
814 ast_copy_string(tmp->them, from, sizeof(tmp->them));
816 snprintf(tmp->sid, sizeof(tmp->sid), "%08lx%08lx", ast_random(), ast_random());
817 ast_copy_string(tmp->them, idroster, sizeof(tmp->them));
820 ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
821 tmp->rtp = ast_rtp_instance_new("asterisk", sched, &bindaddr_tmp, NULL);
822 tmp->parent = client;
824 ast_log(LOG_WARNING, "Out of RTP sessions?\n");
828 ast_copy_string(tmp->exten, "s", sizeof(tmp->exten));
829 ast_mutex_init(&tmp->lock);
830 ast_mutex_lock(&jinglelock);
831 tmp->next = client->p;
833 ast_mutex_unlock(&jinglelock);
837 /*! \brief Start new jingle channel */
838 static struct ast_channel *jingle_new(struct jingle *client, struct jingle_pvt *i, int state, const char *title, const char *linkedid)
840 struct ast_channel *tmp;
841 struct ast_format_cap *what; /* SHALLOW COPY DO NOT DESTROY */
842 struct ast_format tmpfmt;
849 tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, "", "", "", linkedid, 0, "Jingle/%s-%04lx", str, ast_random() & 0xffff);
851 ast_log(LOG_WARNING, "Unable to allocate Jingle channel structure!\n");
854 ast_channel_tech_set(tmp, &jingle_tech);
856 /* Select our native format based on codec preference until we receive
857 something from another device to the contrary. */
858 if (!ast_format_cap_is_empty(i->jointcap))
860 else if (!(ast_format_cap_is_empty(i->cap)))
863 what = global_capability;
865 /* Set Frame packetization */
867 ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(i->rtp), i->rtp, &i->prefs);
869 ast_codec_choose(&i->prefs, what, 1, &tmpfmt);
870 ast_format_cap_add(ast_channel_nativeformats(tmp), &tmpfmt);
872 ast_format_cap_iter_start(i->jointcap);
873 while (!(ast_format_cap_iter_next(i->jointcap, &tmpfmt))) {
874 if (AST_FORMAT_GET_TYPE(tmpfmt.id) == AST_FORMAT_TYPE_VIDEO) {
875 ast_format_cap_add(ast_channel_nativeformats(tmp), &tmpfmt);
878 ast_format_cap_iter_end(i->jointcap);
881 ast_channel_set_fd(tmp, 0, ast_rtp_instance_fd(i->rtp, 0));
882 ast_channel_set_fd(tmp, 1, ast_rtp_instance_fd(i->rtp, 1));
885 ast_channel_set_fd(tmp, 2, ast_rtp_instance_fd(i->vrtp, 0));
886 ast_channel_set_fd(tmp, 3, ast_rtp_instance_fd(i->vrtp, 1));
888 if (state == AST_STATE_RING)
889 ast_channel_rings_set(tmp, 1);
890 ast_channel_adsicpe_set(tmp, AST_ADSI_UNAVAILABLE);
893 ast_best_codec(ast_channel_nativeformats(tmp), &tmpfmt);
894 ast_format_copy(ast_channel_writeformat(tmp), &tmpfmt);
895 ast_format_copy(ast_channel_rawwriteformat(tmp), &tmpfmt);
896 ast_format_copy(ast_channel_readformat(tmp), &tmpfmt);
897 ast_format_copy(ast_channel_rawreadformat(tmp), &tmpfmt);
898 ast_channel_tech_pvt_set(tmp, i);
900 ast_channel_callgroup_set(tmp, client->callgroup);
901 ast_channel_pickupgroup_set(tmp, client->pickupgroup);
902 ast_channel_caller(tmp)->id.name.presentation = client->callingpres;
903 ast_channel_caller(tmp)->id.number.presentation = client->callingpres;
904 if (!ast_strlen_zero(client->accountcode))
905 ast_channel_accountcode_set(tmp, client->accountcode);
906 if (client->amaflags)
907 ast_channel_amaflags_set(tmp, client->amaflags);
908 if (!ast_strlen_zero(client->language))
909 ast_channel_language_set(tmp, client->language);
910 if (!ast_strlen_zero(client->musicclass))
911 ast_channel_musicclass_set(tmp, client->musicclass);
913 ast_channel_context_set(tmp, client->context);
914 ast_channel_exten_set(tmp, i->exten);
915 /* Don't use ast_set_callerid() here because it will
916 * generate an unnecessary NewCallerID event */
917 if (!ast_strlen_zero(i->cid_num)) {
918 ast_channel_caller(tmp)->ani.number.valid = 1;
919 ast_channel_caller(tmp)->ani.number.str = ast_strdup(i->cid_num);
921 if (!ast_strlen_zero(i->exten) && strcmp(i->exten, "s")) {
922 ast_channel_dialed(tmp)->number.str = ast_strdup(i->exten);
924 ast_channel_priority_set(tmp, 1);
926 ast_jb_configure(tmp, &global_jbconf);
927 if (state != AST_STATE_DOWN && ast_pbx_start(tmp)) {
928 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
929 ast_channel_hangupcause_set(tmp, AST_CAUSE_SWITCH_CONGESTION);
937 static int jingle_action(struct jingle *client, struct jingle_pvt *p, const char *action)
939 iks *iq, *jingle = NULL;
943 jingle = iks_new("jingle");
946 iks_insert_attrib(iq, "type", "set");
947 iks_insert_attrib(iq, "from", client->connection->jid->full);
948 iks_insert_attrib(iq, "to", p->them);
949 iks_insert_attrib(iq, "id", client->connection->mid);
950 ast_aji_increment_mid(client->connection->mid);
952 iks_insert_attrib(jingle, "action", action);
953 iks_insert_attrib(jingle, JINGLE_SID, p->sid);
954 iks_insert_attrib(jingle, "initiator", p->initiator ? client->connection->jid->full : p->them);
955 iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
957 iks_insert_node(iq, jingle);
959 ast_aji_send(client->connection, iq);
970 static void jingle_free_candidates(struct jingle_candidate *candidate)
972 struct jingle_candidate *last;
975 candidate = candidate->next;
980 static void jingle_free_pvt(struct jingle *client, struct jingle_pvt *p)
982 struct jingle_pvt *cur, *prev = NULL;
987 prev->next = p->next;
996 iks_filter_remove_rule(p->parent->connection->f, p->ringrule);
998 ast_log(LOG_WARNING, "Uh oh, there's an owner, this is going to be messy.\n");
1000 ast_rtp_instance_destroy(p->rtp);
1002 ast_rtp_instance_destroy(p->vrtp);
1003 jingle_free_candidates(p->theircandidates);
1004 p->cap = ast_format_cap_destroy(p->cap);
1005 p->jointcap = ast_format_cap_destroy(p->jointcap);
1006 p->peercap = ast_format_cap_destroy(p->peercap);
1012 static int jingle_newcall(struct jingle *client, ikspak *pak)
1014 struct jingle_pvt *p, *tmp = client->p;
1015 struct ast_channel *chan;
1017 iks *codec, *content, *description;
1020 /* Make sure our new call doesn't exist yet */
1021 from = iks_find_attrib(pak->x,"to");
1023 from = client->connection->jid->full;
1026 if (iks_find_with_attrib(pak->x, JINGLE_NODE, JINGLE_SID, tmp->sid)) {
1027 ast_log(LOG_NOTICE, "Ignoring duplicate call setup on SID %s\n", tmp->sid);
1028 jingle_response(client, pak, "out-of-order", NULL);
1034 if (!strcasecmp(client->name, "guest")){
1035 /* the guest account is not tied to any configured XMPP client,
1037 if (client->connection) {
1038 ASTOBJ_UNREF(client->connection, ast_aji_client_destroy);
1040 client->connection = ast_aji_get_client(from);
1041 if (!client->connection) {
1042 ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", from);
1047 p = jingle_alloc(client, pak->from->partial, iks_find_attrib(pak->query, JINGLE_SID));
1049 ast_log(LOG_WARNING, "Unable to allocate jingle structure!\n");
1052 chan = jingle_new(client, p, AST_STATE_DOWN, pak->from->user, NULL);
1054 jingle_free_pvt(client, p);
1057 ast_mutex_lock(&p->lock);
1058 ast_copy_string(p->them, pak->from->full, sizeof(p->them));
1059 if (iks_find_attrib(pak->query, JINGLE_SID)) {
1060 ast_copy_string(p->sid, iks_find_attrib(pak->query, JINGLE_SID),
1064 /* content points to the first <content/> tag */
1065 content = iks_child(iks_child(pak->x));
1067 description = iks_find_with_attrib(content, "description", "xmlns", JINGLE_AUDIO_RTP_NS);
1069 /* audio content found */
1070 codec = iks_child(iks_child(content));
1071 ast_copy_string(p->audio_content_name, iks_find_attrib(content, "name"), sizeof(p->audio_content_name));
1074 ast_rtp_codecs_payloads_set_m_type(ast_rtp_instance_get_codecs(p->rtp), p->rtp, atoi(iks_find_attrib(codec, "id")));
1075 ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(p->rtp), p->rtp, atoi(iks_find_attrib(codec, "id")), "audio", iks_find_attrib(codec, "name"), 0);
1076 codec = iks_next(codec);
1083 description = iks_find_with_attrib(content, "description", "xmlns", JINGLE_VIDEO_RTP_NS);
1085 /* video content found */
1086 codec = iks_child(iks_child(content));
1087 ast_copy_string(p->video_content_name, iks_find_attrib(content, "name"), sizeof(p->video_content_name));
1090 ast_rtp_codecs_payloads_set_m_type(ast_rtp_instance_get_codecs(p->rtp), p->rtp, atoi(iks_find_attrib(codec, "id")));
1091 ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(p->rtp), p->rtp, atoi(iks_find_attrib(codec, "id")), "audio", iks_find_attrib(codec, "name"), 0);
1092 codec = iks_next(codec);
1096 content = iks_next(content);
1099 ast_mutex_unlock(&p->lock);
1100 ast_setstate(chan, AST_STATE_RING);
1101 res = ast_pbx_start(chan);
1104 case AST_PBX_FAILED:
1105 ast_log(LOG_WARNING, "Failed to start PBX :(\n");
1106 jingle_response(client, pak, "service-unavailable", NULL);
1108 case AST_PBX_CALL_LIMIT:
1109 ast_log(LOG_WARNING, "Failed to start PBX (call limit reached) \n");
1110 jingle_response(client, pak, "service-unavailable", NULL);
1112 case AST_PBX_SUCCESS:
1113 jingle_response(client, pak, NULL, NULL);
1114 jingle_create_candidates(client, p,
1115 iks_find_attrib(pak->query, JINGLE_SID),
1116 iks_find_attrib(pak->x, "from"));
1124 static int jingle_update_stun(struct jingle *client, struct jingle_pvt *p)
1126 struct jingle_candidate *tmp;
1128 struct ast_hostent ahp;
1129 struct sockaddr_in sin;
1130 struct ast_sockaddr sin_tmp;
1132 if (time(NULL) == p->laststun)
1135 tmp = p->theircandidates;
1136 p->laststun = time(NULL);
1139 hp = ast_gethostbyname(tmp->ip, &ahp);
1140 sin.sin_family = AF_INET;
1141 memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
1142 sin.sin_port = htons(tmp->port);
1143 snprintf(username, sizeof(username), "%s:%s", tmp->ufrag, p->ourcandidates->ufrag);
1145 ast_sockaddr_from_sin(&sin_tmp, &sin);
1146 ast_rtp_instance_stun_request(p->rtp, &sin_tmp, username);
1152 static int jingle_add_candidate(struct jingle *client, ikspak *pak)
1154 struct jingle_pvt *p = NULL, *tmp = NULL;
1155 struct aji_client *c = client->connection;
1156 struct jingle_candidate *newcandidate = NULL;
1157 iks *traversenodes = NULL, *receipt = NULL;
1159 for (tmp = client->p; tmp; tmp = tmp->next) {
1160 if (iks_find_with_attrib(pak->x, JINGLE_NODE, JINGLE_SID, tmp->sid)) {
1169 traversenodes = pak->query;
1170 while(traversenodes) {
1171 if(!strcasecmp(iks_name(traversenodes), "jingle")) {
1172 traversenodes = iks_child(traversenodes);
1175 if(!strcasecmp(iks_name(traversenodes), "content")) {
1176 traversenodes = iks_child(traversenodes);
1179 if(!strcasecmp(iks_name(traversenodes), "transport")) {
1180 traversenodes = iks_child(traversenodes);
1184 if(!strcasecmp(iks_name(traversenodes), "candidate")) {
1185 newcandidate = ast_calloc(1, sizeof(*newcandidate));
1188 ast_copy_string(newcandidate->ip, iks_find_attrib(traversenodes, "ip"), sizeof(newcandidate->ip));
1189 newcandidate->port = atoi(iks_find_attrib(traversenodes, "port"));
1190 ast_copy_string(newcandidate->password, iks_find_attrib(traversenodes, "pwd"), sizeof(newcandidate->password));
1191 if (!strcasecmp(iks_find_attrib(traversenodes, "protocol"), "udp"))
1192 newcandidate->protocol = AJI_PROTOCOL_UDP;
1193 else if (!strcasecmp(iks_find_attrib(traversenodes, "protocol"), "ssltcp"))
1194 newcandidate->protocol = AJI_PROTOCOL_SSLTCP;
1196 if (!strcasecmp(iks_find_attrib(traversenodes, "type"), "host"))
1197 newcandidate->type = AJI_CONNECT_HOST;
1198 else if (!strcasecmp(iks_find_attrib(traversenodes, "type"), "prflx"))
1199 newcandidate->type = AJI_CONNECT_PRFLX;
1200 else if (!strcasecmp(iks_find_attrib(traversenodes, "type"), "relay"))
1201 newcandidate->type = AJI_CONNECT_RELAY;
1202 else if (!strcasecmp(iks_find_attrib(traversenodes, "type"), "srflx"))
1203 newcandidate->type = AJI_CONNECT_SRFLX;
1205 newcandidate->network = atoi(iks_find_attrib(traversenodes, "network"));
1206 newcandidate->generation = atoi(iks_find_attrib(traversenodes, "generation"));
1207 newcandidate->next = NULL;
1209 newcandidate->next = p->theircandidates;
1210 p->theircandidates = newcandidate;
1212 jingle_update_stun(p->parent, p);
1213 newcandidate = NULL;
1215 traversenodes = iks_next(traversenodes);
1218 receipt = iks_new("iq");
1219 iks_insert_attrib(receipt, "type", "result");
1220 iks_insert_attrib(receipt, "from", c->jid->full);
1221 iks_insert_attrib(receipt, "to", iks_find_attrib(pak->x, "from"));
1222 iks_insert_attrib(receipt, "id", iks_find_attrib(pak->x, "id"));
1223 ast_aji_send(c, receipt);
1225 iks_delete(receipt);
1230 static struct ast_frame *jingle_rtp_read(struct ast_channel *ast, struct jingle_pvt *p)
1232 struct ast_frame *f;
1235 return &ast_null_frame;
1236 f = ast_rtp_instance_read(p->rtp, 0);
1237 jingle_update_stun(p->parent, p);
1239 /* We already hold the channel lock */
1240 if (f->frametype == AST_FRAME_VOICE) {
1241 if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(p->owner), &f->subclass.format))) {
1242 ast_debug(1, "Oooh, format changed to %s\n", ast_getformatname(&f->subclass.format));
1243 ast_format_cap_remove_bytype(ast_channel_nativeformats(p->owner), AST_FORMAT_TYPE_AUDIO);
1244 ast_format_cap_add(ast_channel_nativeformats(p->owner), &f->subclass.format);
1245 ast_set_read_format(p->owner, ast_channel_readformat(p->owner));
1246 ast_set_write_format(p->owner, ast_channel_writeformat(p->owner));
1248 /* if ((ast_test_flag(p, SIP_DTMF) == SIP_DTMF_INBAND) && p->vad) {
1249 f = ast_dsp_process(p->owner, p->vad, f);
1250 if (f && (f->frametype == AST_FRAME_DTMF))
1251 ast_debug(1, "* Detected inband DTMF '%c'\n", f->subclass.codec);
1258 static struct ast_frame *jingle_read(struct ast_channel *ast)
1260 struct ast_frame *fr;
1261 struct jingle_pvt *p = ast_channel_tech_pvt(ast);
1263 ast_mutex_lock(&p->lock);
1264 fr = jingle_rtp_read(ast, p);
1265 ast_mutex_unlock(&p->lock);
1269 /*! \brief Send frame to media channel (rtp) */
1270 static int jingle_write(struct ast_channel *ast, struct ast_frame *frame)
1272 struct jingle_pvt *p = ast_channel_tech_pvt(ast);
1276 switch (frame->frametype) {
1277 case AST_FRAME_VOICE:
1278 if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &frame->subclass.format))) {
1279 ast_log(LOG_WARNING,
1280 "Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n",
1281 ast_getformatname(&frame->subclass.format),
1282 ast_getformatname_multiple(buf, sizeof(buf), ast_channel_nativeformats(ast)),
1283 ast_getformatname(ast_channel_readformat(ast)),
1284 ast_getformatname(ast_channel_writeformat(ast)));
1288 ast_mutex_lock(&p->lock);
1290 res = ast_rtp_instance_write(p->rtp, frame);
1292 ast_mutex_unlock(&p->lock);
1295 case AST_FRAME_VIDEO:
1297 ast_mutex_lock(&p->lock);
1299 res = ast_rtp_instance_write(p->vrtp, frame);
1301 ast_mutex_unlock(&p->lock);
1304 case AST_FRAME_IMAGE:
1308 ast_log(LOG_WARNING, "Can't send %d type frames with Jingle write\n",
1316 static int jingle_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
1318 struct jingle_pvt *p = ast_channel_tech_pvt(newchan);
1319 ast_mutex_lock(&p->lock);
1321 if ((p->owner != oldchan)) {
1322 ast_mutex_unlock(&p->lock);
1325 if (p->owner == oldchan)
1327 ast_mutex_unlock(&p->lock);
1331 static int jingle_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
1335 switch (condition) {
1336 case AST_CONTROL_HOLD:
1337 ast_moh_start(ast, data, NULL);
1339 case AST_CONTROL_UNHOLD:
1343 ast_log(LOG_NOTICE, "Don't know how to indicate condition '%d'\n", condition);
1345 case AST_CONTROL_PVT_CAUSE_CODE:
1352 static int jingle_sendtext(struct ast_channel *chan, const char *text)
1355 struct aji_client *client = NULL;
1356 struct jingle_pvt *p = ast_channel_tech_pvt(chan);
1360 ast_log(LOG_ERROR, "Parent channel not found\n");
1363 if (!p->parent->connection) {
1364 ast_log(LOG_ERROR, "XMPP client not found\n");
1367 client = p->parent->connection;
1368 res = ast_aji_send_chat(client, p->them, text);
1372 static int jingle_digit(struct ast_channel *ast, char digit, unsigned int duration)
1374 struct jingle_pvt *p = ast_channel_tech_pvt(ast);
1375 struct jingle *client = p->parent;
1376 iks *iq, *jingle, *dtmf;
1377 char buffer[2] = {digit, '\0'};
1379 jingle = iks_new("jingle");
1380 dtmf = iks_new("dtmf");
1381 if(!iq || !jingle || !dtmf) {
1385 ast_log(LOG_ERROR, "Did not send dtmf do to memory issue\n");
1389 iks_insert_attrib(iq, "type", "set");
1390 iks_insert_attrib(iq, "to", p->them);
1391 iks_insert_attrib(iq, "from", client->connection->jid->full);
1392 iks_insert_attrib(iq, "id", client->connection->mid);
1393 ast_aji_increment_mid(client->connection->mid);
1394 iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
1395 iks_insert_attrib(jingle, "action", "session-info");
1396 iks_insert_attrib(jingle, "initiator", p->initiator ? client->connection->jid->full : p->them);
1397 iks_insert_attrib(jingle, "sid", p->sid);
1398 iks_insert_attrib(dtmf, "xmlns", JINGLE_DTMF_NS);
1399 iks_insert_attrib(dtmf, "code", buffer);
1400 iks_insert_node(iq, jingle);
1401 iks_insert_node(jingle, dtmf);
1403 ast_mutex_lock(&p->lock);
1404 if (ast_channel_dtmff(ast)->frametype == AST_FRAME_DTMF_BEGIN || duration == 0) {
1405 iks_insert_attrib(dtmf, "action", "button-down");
1406 } else if (ast_channel_dtmff(ast)->frametype == AST_FRAME_DTMF_END || duration != 0) {
1407 iks_insert_attrib(dtmf, "action", "button-up");
1409 ast_aji_send(client->connection, iq);
1414 ast_mutex_unlock(&p->lock);
1418 static int jingle_digit_begin(struct ast_channel *chan, char digit)
1420 return jingle_digit(chan, digit, 0);
1423 static int jingle_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
1425 return jingle_digit(ast, digit, duration);
1428 static int jingle_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
1430 ast_log(LOG_NOTICE, "XXX Implement jingle sendhtml XXX\n");
1434 static int jingle_transmit_invite(struct jingle_pvt *p)
1436 struct jingle *aux = NULL;
1437 struct aji_client *client = NULL;
1438 iks *iq, *jingle, *content, *description, *transport;
1439 iks *payload_eg711u, *payload_pcmu;
1442 client = aux->connection;
1444 jingle = iks_new(JINGLE_NODE);
1445 content = iks_new("content");
1446 description = iks_new("description");
1447 transport = iks_new("transport");
1448 payload_pcmu = iks_new("payload-type");
1449 payload_eg711u = iks_new("payload-type");
1451 ast_copy_string(p->audio_content_name, "asterisk-audio-content", sizeof(p->audio_content_name));
1453 iks_insert_attrib(iq, "type", "set");
1454 iks_insert_attrib(iq, "to", p->them);
1455 iks_insert_attrib(iq, "from", client->jid->full);
1456 iks_insert_attrib(iq, "id", client->mid);
1457 ast_aji_increment_mid(client->mid);
1458 iks_insert_attrib(jingle, "action", JINGLE_INITIATE);
1459 iks_insert_attrib(jingle, JINGLE_SID, p->sid);
1460 iks_insert_attrib(jingle, "initiator", client->jid->full);
1461 iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
1463 /* For now, we only send one audio based content */
1464 iks_insert_attrib(content, "creator", "initiator");
1465 iks_insert_attrib(content, "name", p->audio_content_name);
1466 iks_insert_attrib(content, "profile", "RTP/AVP");
1467 iks_insert_attrib(description, "xmlns", JINGLE_AUDIO_RTP_NS);
1468 iks_insert_attrib(transport, "xmlns", JINGLE_ICE_UDP_NS);
1469 iks_insert_attrib(payload_pcmu, "id", "0");
1470 iks_insert_attrib(payload_pcmu, "name", "PCMU");
1471 iks_insert_attrib(payload_eg711u, "id", "100");
1472 iks_insert_attrib(payload_eg711u, "name", "EG711U");
1473 iks_insert_node(description, payload_pcmu);
1474 iks_insert_node(description, payload_eg711u);
1475 iks_insert_node(content, description);
1476 iks_insert_node(content, transport);
1477 iks_insert_node(jingle, content);
1478 iks_insert_node(iq, jingle);
1480 ast_aji_send(client, iq);
1484 iks_delete(content);
1485 iks_delete(description);
1486 iks_delete(transport);
1487 iks_delete(payload_eg711u);
1488 iks_delete(payload_pcmu);
1492 /* Not in use right now.
1493 static int jingle_auto_congest(void *nothing)
1495 struct jingle_pvt *p = nothing;
1497 ast_mutex_lock(&p->lock);
1499 if (!ast_channel_trylock(p->owner)) {
1500 ast_log(LOG_NOTICE, "Auto-congesting %s\n", p->owner->name);
1501 ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
1502 ast_channel_unlock(p->owner);
1505 ast_mutex_unlock(&p->lock);
1510 /*! \brief Initiate new call, part of PBX interface
1511 * dest is the dial string */
1512 static int jingle_call(struct ast_channel *ast, const char *dest, int timeout)
1514 struct jingle_pvt *p = ast_channel_tech_pvt(ast);
1516 if ((ast_channel_state(ast) != AST_STATE_DOWN) && (ast_channel_state(ast) != AST_STATE_RESERVED)) {
1517 ast_log(LOG_WARNING, "jingle_call called on %s, neither down nor reserved\n", ast_channel_name(ast));
1521 ast_setstate(ast, AST_STATE_RING);
1522 ast_format_cap_copy(p->jointcap, p->cap);
1524 ast_copy_string(p->ring, p->parent->connection->mid, sizeof(p->ring));
1525 p->ringrule = iks_filter_add_rule(p->parent->connection->f, jingle_ringing_ack, p,
1526 IKS_RULE_ID, p->ring, IKS_RULE_DONE);
1528 ast_log(LOG_WARNING, "Whoa, already have a ring rule!\n");
1530 jingle_transmit_invite(p);
1531 jingle_create_candidates(p->parent, p, p->sid, p->them);
1536 /*! \brief Hangup a call through the jingle proxy channel */
1537 static int jingle_hangup(struct ast_channel *ast)
1539 struct jingle_pvt *p = ast_channel_tech_pvt(ast);
1540 struct jingle *client;
1542 ast_mutex_lock(&p->lock);
1545 ast_channel_tech_pvt_set(ast, NULL);
1546 if (!p->alreadygone)
1547 jingle_action(client, p, JINGLE_TERMINATE);
1548 ast_mutex_unlock(&p->lock);
1550 jingle_free_pvt(client, p);
1555 /*! \brief Part of PBX interface */
1556 static struct ast_channel *jingle_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
1558 struct jingle_pvt *p = NULL;
1559 struct jingle *client = NULL;
1560 char *sender = NULL, *to = NULL, *s = NULL;
1561 struct ast_channel *chan = NULL;
1564 s = ast_strdupa(data);
1565 sender = strsep(&s, "/");
1566 if (sender && (sender[0] != '\0'))
1567 to = strsep(&s, "/");
1569 ast_log(LOG_ERROR, "Bad arguments in Jingle Dialstring: %s\n", data);
1573 ast_log(LOG_ERROR, "Bad arguments in Jingle Dialstring: %s\n", (char*) data);
1578 client = find_jingle(to, sender);
1580 ast_log(LOG_WARNING, "Could not find recipient.\n");
1583 if (!strcasecmp(client->name, "guest")){
1584 /* the guest account is not tied to any configured XMPP client,
1586 if (client->connection) {
1587 ASTOBJ_UNREF(client->connection, ast_aji_client_destroy);
1589 client->connection = ast_aji_get_client(sender);
1590 if (!client->connection) {
1591 ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", sender);
1596 ASTOBJ_WRLOCK(client);
1597 p = jingle_alloc(client, to, NULL);
1599 chan = jingle_new(client, p, AST_STATE_DOWN, to, requestor ? ast_channel_linkedid(requestor) : NULL);
1600 ASTOBJ_UNLOCK(client);
1605 /*! \brief CLI command "jingle show channels" */
1606 static char *jingle_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1608 #define FORMAT "%-30.30s %-30.30s %-15.15s %-5.5s %-5.5s \n"
1609 struct jingle_pvt *p;
1610 struct ast_channel *chan;
1612 char them[AJI_MAX_JIDLEN];
1614 char *resource = NULL;
1618 e->command = "jingle show channels";
1620 "Usage: jingle show channels\n"
1621 " Shows current state of the Jingle channels.\n";
1628 return CLI_SHOWUSAGE;
1630 ast_mutex_lock(&jinglelock);
1631 ast_cli(a->fd, FORMAT, "Channel", "Jabber ID", "Resource", "Read", "Write");
1632 ASTOBJ_CONTAINER_TRAVERSE(&jingle_list, 1, {
1633 ASTOBJ_WRLOCK(iterator);
1637 ast_copy_string(them, p->them, sizeof(them));
1639 resource = strchr(them, '/');
1647 ast_cli(a->fd, FORMAT,
1648 ast_channel_name(chan),
1651 ast_getformatname(ast_channel_readformat(chan)),
1652 ast_getformatname(ast_channel_writeformat(chan))
1655 ast_log(LOG_WARNING, "No available channel\n");
1659 ASTOBJ_UNLOCK(iterator);
1662 ast_mutex_unlock(&jinglelock);
1664 ast_cli(a->fd, "%d active jingle channel%s\n", numchans, (numchans != 1) ? "s" : "");
1669 /*! \brief CLI command "jingle reload" */
1670 static char *jingle_do_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1674 e->command = "jingle reload";
1676 "Usage: jingle reload\n"
1677 " Reload jingle channel driver.\n";
1686 static int jingle_parser(void *data, ikspak *pak)
1688 struct jingle *client = ASTOBJ_REF((struct jingle *) data);
1689 ast_log(LOG_NOTICE, "Filter matched\n");
1691 if (iks_find_with_attrib(pak->x, JINGLE_NODE, "action", JINGLE_INITIATE)) {
1693 jingle_newcall(client, pak);
1694 } else if (iks_find_with_attrib(pak->x, JINGLE_NODE, "action", JINGLE_NEGOTIATE)) {
1695 ast_debug(3, "About to add candidate!\n");
1696 jingle_add_candidate(client, pak);
1697 ast_debug(3, "Candidate Added!\n");
1698 } else if (iks_find_with_attrib(pak->x, JINGLE_NODE, "action", JINGLE_ACCEPT)) {
1699 jingle_is_answered(client, pak);
1700 } else if (iks_find_with_attrib(pak->x, JINGLE_NODE, "action", JINGLE_INFO)) {
1701 jingle_handle_dtmf(client, pak);
1702 } else if (iks_find_with_attrib(pak->x, JINGLE_NODE, "action", JINGLE_TERMINATE)) {
1703 jingle_hangup_farend(client, pak);
1704 } else if (iks_find_with_attrib(pak->x, JINGLE_NODE, "action", "reject")) {
1705 jingle_hangup_farend(client, pak);
1707 ASTOBJ_UNREF(client, jingle_member_destroy);
1708 return IKS_FILTER_EAT;
1710 /* Not using this anymore probably take out soon
1711 static struct jingle_candidate *jingle_create_candidate(char *args)
1713 char *name, *type, *preference, *protocol;
1714 struct jingle_candidate *res;
1715 res = ast_calloc(1, sizeof(*res));
1718 if ((args = strchr(args, ','))) {
1723 if ((args = strchr(args, ','))) {
1728 if ((args = strchr(args, ','))) {
1734 ast_copy_string(res->name, name, sizeof(res->name));
1736 res->preference = atof(preference);
1739 if (!strcasecmp("udp", protocol))
1740 res->protocol = AJI_PROTOCOL_UDP;
1741 if (!strcasecmp("ssltcp", protocol))
1742 res->protocol = AJI_PROTOCOL_SSLTCP;
1745 if (!strcasecmp("host", type))
1746 res->type = AJI_CONNECT_HOST;
1747 if (!strcasecmp("prflx", type))
1748 res->type = AJI_CONNECT_PRFLX;
1749 if (!strcasecmp("relay", type))
1750 res->type = AJI_CONNECT_RELAY;
1751 if (!strcasecmp("srflx", type))
1752 res->type = AJI_CONNECT_SRFLX;
1759 static int jingle_create_member(char *label, struct ast_variable *var, int allowguest,
1760 struct ast_codec_pref prefs, char *context,
1761 struct jingle *member)
1763 struct aji_client *client;
1766 ast_log(LOG_WARNING, "Out of memory.\n");
1768 ast_copy_string(member->name, label, sizeof(member->name));
1769 ast_copy_string(member->user, label, sizeof(member->user));
1770 ast_copy_string(member->context, context, sizeof(member->context));
1771 member->allowguest = allowguest;
1772 member->prefs = prefs;
1775 struct jingle_candidate *candidate = NULL;
1777 if (!strcasecmp(var->name, "username"))
1778 ast_copy_string(member->user, var->value, sizeof(member->user));
1779 else if (!strcasecmp(var->name, "disallow"))
1780 ast_parse_allow_disallow(&member->prefs, member->cap, var->value, 0);
1781 else if (!strcasecmp(var->name, "allow"))
1782 ast_parse_allow_disallow(&member->prefs, member->cap, var->value, 1);
1783 else if (!strcasecmp(var->name, "context"))
1784 ast_copy_string(member->context, var->value, sizeof(member->context));
1786 else if (!strcasecmp(var->name, "candidate")) {
1787 candidate = jingle_create_candidate(var->value);
1789 candidate->next = member->ourcandidates;
1790 member->ourcandidates = candidate;
1794 else if (!strcasecmp(var->name, "connection")) {
1795 if ((client = ast_aji_get_client(var->value))) {
1796 member->connection = client;
1797 iks_filter_add_rule(client->f, jingle_parser, member,
1798 IKS_RULE_TYPE, IKS_PAK_IQ,
1799 IKS_RULE_FROM_PARTIAL, member->user,
1800 IKS_RULE_NS, JINGLE_NS,
1803 ast_log(LOG_ERROR, "connection referenced not found!\n");
1809 if (member->connection && member->user)
1810 member->buddy = ASTOBJ_CONTAINER_FIND(&member->connection->buddies, member->user);
1812 ast_log(LOG_ERROR, "No Connection or Username!\n");
1817 static int jingle_load_config(void)
1820 struct ast_config *cfg = NULL;
1823 struct ast_variable *var;
1824 struct jingle *member;
1826 struct ast_hostent ahp;
1827 struct ast_codec_pref prefs;
1828 struct aji_client_container *clients;
1829 struct jingle_candidate *global_candidates = NULL;
1830 struct ast_flags config_flags = { 0 };
1832 cfg = ast_config_load(JINGLE_CONFIG, config_flags);
1833 if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
1837 /* Copy the default jb config over global_jbconf */
1838 memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
1840 cat = ast_category_browse(cfg, NULL);
1841 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
1842 /* handle jb conf */
1843 if (!ast_jb_read_conf(&global_jbconf, var->name, var->value))
1846 if (!strcasecmp(var->name, "allowguest"))
1848 (ast_true(ast_variable_retrieve(cfg, "general", "allowguest"))) ? 1 : 0;
1849 else if (!strcasecmp(var->name, "disallow"))
1850 ast_parse_allow_disallow(&prefs, global_capability, var->value, 0);
1851 else if (!strcasecmp(var->name, "allow"))
1852 ast_parse_allow_disallow(&prefs, global_capability, var->value, 1);
1853 else if (!strcasecmp(var->name, "context"))
1854 ast_copy_string(context, var->value, sizeof(context));
1855 else if (!strcasecmp(var->name, "externip"))
1856 ast_copy_string(externip, var->value, sizeof(externip));
1857 else if (!strcasecmp(var->name, "bindaddr")) {
1858 if (!(hp = ast_gethostbyname(var->value, &ahp))) {
1859 ast_log(LOG_WARNING, "Invalid address: %s\n", var->value);
1861 memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
1864 /* Idea to allow for custom candidates */
1866 else if (!strcasecmp(var->name, "candidate")) {
1867 candidate = jingle_create_candidate(var->value);
1869 candidate->next = global_candidates;
1870 global_candidates = candidate;
1876 if (strcasecmp(cat, "general")) {
1877 var = ast_variable_browse(cfg, cat);
1878 member = ast_calloc(1, sizeof(*member));
1879 ASTOBJ_INIT(member);
1880 ASTOBJ_WRLOCK(member);
1881 member->cap = ast_format_cap_alloc_nolock();
1882 if (!strcasecmp(cat, "guest")) {
1883 ast_copy_string(member->name, "guest", sizeof(member->name));
1884 ast_copy_string(member->user, "guest", sizeof(member->user));
1885 ast_copy_string(member->context, context, sizeof(member->context));
1886 member->allowguest = allowguest;
1887 member->prefs = prefs;
1889 if (!strcasecmp(var->name, "disallow"))
1890 ast_parse_allow_disallow(&member->prefs, member->cap,
1892 else if (!strcasecmp(var->name, "allow"))
1893 ast_parse_allow_disallow(&member->prefs, member->cap,
1895 else if (!strcasecmp(var->name, "context"))
1896 ast_copy_string(member->context, var->value,
1897 sizeof(member->context));
1898 else if (!strcasecmp(var->name, "parkinglot"))
1899 ast_copy_string(member->parkinglot, var->value,
1900 sizeof(member->parkinglot));
1901 /* Idea to allow for custom candidates */
1903 else if (!strcasecmp(var->name, "candidate")) {
1904 candidate = jingle_create_candidate(var->value);
1906 candidate->next = member->ourcandidates;
1907 member->ourcandidates = candidate;
1913 ASTOBJ_UNLOCK(member);
1914 clients = ast_aji_get_clients();
1916 ASTOBJ_CONTAINER_TRAVERSE(clients, 1, {
1917 ASTOBJ_WRLOCK(iterator);
1918 ASTOBJ_WRLOCK(member);
1919 if (member->connection) {
1920 ASTOBJ_UNREF(member->connection, ast_aji_client_destroy);
1922 member->connection = NULL;
1923 iks_filter_add_rule(iterator->f, jingle_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, JINGLE_NS, IKS_RULE_DONE);
1924 iks_filter_add_rule(iterator->f, jingle_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, JINGLE_DTMF_NS, IKS_RULE_DONE);
1925 ASTOBJ_UNLOCK(member);
1926 ASTOBJ_UNLOCK(iterator);
1928 ASTOBJ_CONTAINER_LINK(&jingle_list, member);
1930 ASTOBJ_UNLOCK(member);
1931 ASTOBJ_UNREF(member, jingle_member_destroy);
1934 ASTOBJ_UNLOCK(member);
1935 if (jingle_create_member(cat, var, allowguest, prefs, context, member))
1936 ASTOBJ_CONTAINER_LINK(&jingle_list, member);
1937 ASTOBJ_UNREF(member, jingle_member_destroy);
1940 cat = ast_category_browse(cfg, cat);
1942 ast_config_destroy(cfg);
1943 jingle_free_candidates(global_candidates);
1948 * \brief Load the module
1950 * Module loading including tests for configuration or dependencies.
1951 * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
1952 * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
1953 * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
1954 * configuration file or other non-critical problem return
1955 * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
1957 static int load_module(void)
1959 struct ast_sockaddr ourip_tmp;
1960 struct ast_sockaddr bindaddr_tmp;
1961 struct ast_format tmpfmt;
1963 char *jabber_loaded = ast_module_helper("", "res_jabber.so", 0, 0, 0, 0);
1965 if (!(jingle_tech.capabilities = ast_format_cap_alloc())) {
1966 return AST_MODULE_LOAD_DECLINE;
1969 ast_format_cap_add_all_by_type(jingle_tech.capabilities, AST_FORMAT_TYPE_AUDIO);
1970 if (!(global_capability = ast_format_cap_alloc())) {
1971 return AST_MODULE_LOAD_DECLINE;
1973 ast_format_cap_add(global_capability, ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0));
1974 ast_format_cap_add(global_capability, ast_format_set(&tmpfmt, AST_FORMAT_GSM, 0));
1975 ast_format_cap_add(global_capability, ast_format_set(&tmpfmt, AST_FORMAT_ALAW, 0));
1976 ast_format_cap_add(global_capability, ast_format_set(&tmpfmt, AST_FORMAT_H263, 0));
1978 free(jabber_loaded);
1979 if (!jabber_loaded) {
1980 /* Dependency module has a different name, if embedded */
1981 jabber_loaded = ast_module_helper("", "res_jabber", 0, 0, 0, 0);
1982 free(jabber_loaded);
1983 if (!jabber_loaded) {
1984 ast_log(LOG_ERROR, "chan_jingle.so depends upon res_jabber.so\n");
1985 return AST_MODULE_LOAD_DECLINE;
1989 ASTOBJ_CONTAINER_INIT(&jingle_list);
1990 if (!jingle_load_config()) {
1991 ast_log(LOG_ERROR, "Unable to read config file %s. Not loading module.\n", JINGLE_CONFIG);
1992 return AST_MODULE_LOAD_DECLINE;
1995 sched = ast_sched_context_create();
1997 ast_log(LOG_WARNING, "Unable to create schedule context\n");
2000 io = io_context_create();
2002 ast_log(LOG_WARNING, "Unable to create I/O context\n");
2005 ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
2006 if (ast_find_ourip(&ourip_tmp, &bindaddr_tmp, AF_INET)) {
2007 ast_log(LOG_WARNING, "Unable to get own IP address, Jingle disabled\n");
2010 __ourip.s_addr = htonl(ast_sockaddr_ipv4(&ourip_tmp));
2012 ast_rtp_glue_register(&jingle_rtp_glue);
2013 ast_cli_register_multiple(jingle_cli, ARRAY_LEN(jingle_cli));
2014 /* Make sure we can register our channel type */
2015 if (ast_channel_register(&jingle_tech)) {
2016 ast_log(LOG_ERROR, "Unable to register channel class %s\n", channel_type);
2022 /*! \brief Reload module */
2023 static int reload(void)
2028 /*! \brief Unload the jingle channel from Asterisk */
2029 static int unload_module(void)
2031 struct jingle_pvt *privates = NULL;
2032 ast_cli_unregister_multiple(jingle_cli, ARRAY_LEN(jingle_cli));
2033 /* First, take us out of the channel loop */
2034 ast_channel_unregister(&jingle_tech);
2035 ast_rtp_glue_unregister(&jingle_rtp_glue);
2037 if (!ast_mutex_lock(&jinglelock)) {
2038 /* Hangup all interfaces if they have an owner */
2039 ASTOBJ_CONTAINER_TRAVERSE(&jingle_list, 1, {
2040 ASTOBJ_WRLOCK(iterator);
2041 privates = iterator->p;
2043 if (privates->owner)
2044 ast_softhangup(privates->owner, AST_SOFTHANGUP_APPUNLOAD);
2045 privates = privates->next;
2048 ASTOBJ_UNLOCK(iterator);
2050 ast_mutex_unlock(&jinglelock);
2052 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
2055 ASTOBJ_CONTAINER_DESTROYALL(&jingle_list, jingle_member_destroy);
2056 ASTOBJ_CONTAINER_DESTROY(&jingle_list);
2058 global_capability = ast_format_cap_destroy(global_capability);
2062 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Jingle Channel Driver",
2063 .load = load_module,
2064 .unload = unload_module,
2066 .load_pri = AST_MODPRI_CHANNEL_DRIVER,