2006-05-22 21:12:30 +00:00
|
|
|
/*
|
|
|
|
* Asterisk -- An open source telephony toolkit.
|
|
|
|
*
|
|
|
|
* Copyright (C) 1999 - 2005, Digium, Inc.
|
|
|
|
*
|
|
|
|
* Matt O'Gorman <mogorman@digium.com>
|
|
|
|
*
|
|
|
|
* See http://www.asterisk.org for more information about
|
|
|
|
* the Asterisk project. Please do not directly contact
|
|
|
|
* any of the maintainers of this project for assistance;
|
|
|
|
* the project provides a web site, mailing lists and IRC
|
|
|
|
* channels for your use.
|
|
|
|
*
|
|
|
|
* This program is free software, distributed under the terms of
|
|
|
|
* the GNU General Public License Version 2. See the LICENSE file
|
|
|
|
* at the top of the source tree.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*! \file
|
|
|
|
*
|
|
|
|
* \author Matt O'Gorman <mogorman@digium.com>
|
|
|
|
*
|
|
|
|
* \brief Jingle Channel Driver
|
2007-05-07 18:25:56 +00:00
|
|
|
*
|
2012-09-21 17:14:59 +00:00
|
|
|
* Iksemel http://iksemel.jabberstudio.org/
|
2006-05-22 21:12:30 +00:00
|
|
|
*
|
|
|
|
* \ingroup channel_drivers
|
|
|
|
*/
|
|
|
|
|
2012-10-14 21:47:40 +00:00
|
|
|
/*! \li \ref chan_jingle.c uses the configuration file \ref jingle.conf
|
2012-10-01 23:24:35 +00:00
|
|
|
* \addtogroup configuration_file
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*! \page jingle.conf jingle.conf
|
|
|
|
* \verbinclude jingle.conf.sample
|
|
|
|
*/
|
|
|
|
|
2006-05-22 21:12:30 +00:00
|
|
|
/*** MODULEINFO
|
|
|
|
<depend>iksemel</depend>
|
2007-02-10 00:20:57 +00:00
|
|
|
<depend>res_jabber</depend>
|
2011-07-05 22:11:40 +00:00
|
|
|
<use type="external">openssl</use>
|
2011-07-14 20:28:54 +00:00
|
|
|
<defaultenabled>no</defaultenabled>
|
2012-09-10 19:49:30 +00:00
|
|
|
<support_level>deprecated</support_level>
|
|
|
|
<replacement>chan_motif</replacement>
|
2006-05-22 21:12:30 +00:00
|
|
|
***/
|
|
|
|
|
2006-06-07 18:54:56 +00:00
|
|
|
#include "asterisk.h"
|
|
|
|
|
|
|
|
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
2006-05-22 21:12:30 +00:00
|
|
|
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <netdb.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
#include <sys/signal.h>
|
|
|
|
#include <iksemel.h>
|
2007-05-25 15:07:26 +00:00
|
|
|
#include <pthread.h>
|
|
|
|
|
2006-05-22 21:12:30 +00:00
|
|
|
#include "asterisk/lock.h"
|
|
|
|
#include "asterisk/channel.h"
|
|
|
|
#include "asterisk/config.h"
|
|
|
|
#include "asterisk/module.h"
|
|
|
|
#include "asterisk/pbx.h"
|
|
|
|
#include "asterisk/sched.h"
|
|
|
|
#include "asterisk/io.h"
|
2009-04-02 17:20:52 +00:00
|
|
|
#include "asterisk/rtp_engine.h"
|
2006-05-22 21:12:30 +00:00
|
|
|
#include "asterisk/acl.h"
|
|
|
|
#include "asterisk/callerid.h"
|
|
|
|
#include "asterisk/file.h"
|
|
|
|
#include "asterisk/cli.h"
|
|
|
|
#include "asterisk/app.h"
|
|
|
|
#include "asterisk/musiconhold.h"
|
|
|
|
#include "asterisk/manager.h"
|
|
|
|
#include "asterisk/stringfields.h"
|
|
|
|
#include "asterisk/utils.h"
|
|
|
|
#include "asterisk/causes.h"
|
|
|
|
#include "asterisk/astobj.h"
|
2006-06-01 16:47:28 +00:00
|
|
|
#include "asterisk/abstract_jb.h"
|
2006-05-22 21:12:30 +00:00
|
|
|
#include "asterisk/jabber.h"
|
|
|
|
#include "asterisk/jingle.h"
|
|
|
|
|
|
|
|
#define JINGLE_CONFIG "jingle.conf"
|
|
|
|
|
2006-06-01 16:47:28 +00:00
|
|
|
/*! Global jitterbuffer configuration - by default, jb is disabled */
|
|
|
|
static struct ast_jb_conf default_jbconf =
|
|
|
|
{
|
|
|
|
.flags = 0,
|
|
|
|
.max_size = -1,
|
|
|
|
.resync_threshold = -1,
|
2010-03-02 19:08:38 +00:00
|
|
|
.impl = "",
|
|
|
|
.target_extra = -1,
|
2006-06-01 16:47:28 +00:00
|
|
|
};
|
|
|
|
static struct ast_jb_conf global_jbconf;
|
|
|
|
|
2006-05-22 21:12:30 +00:00
|
|
|
enum jingle_protocol {
|
2007-09-25 09:07:30 +00:00
|
|
|
AJI_PROTOCOL_UDP,
|
|
|
|
AJI_PROTOCOL_SSLTCP,
|
2006-05-22 21:12:30 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
enum jingle_connect_type {
|
2007-09-25 09:07:30 +00:00
|
|
|
AJI_CONNECT_HOST,
|
|
|
|
AJI_CONNECT_PRFLX,
|
|
|
|
AJI_CONNECT_RELAY,
|
|
|
|
AJI_CONNECT_SRFLX,
|
2006-05-22 21:12:30 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct jingle_pvt {
|
2006-08-07 21:15:28 +00:00
|
|
|
ast_mutex_t lock; /*!< Channel private lock */
|
2006-05-22 21:12:30 +00:00
|
|
|
time_t laststun;
|
2006-08-07 21:15:28 +00:00
|
|
|
struct jingle *parent; /*!< Parent client */
|
2006-05-22 21:12:30 +00:00
|
|
|
char sid[100];
|
2007-10-16 10:29:33 +00:00
|
|
|
char them[AJI_MAX_JIDLEN];
|
2006-08-07 21:15:28 +00:00
|
|
|
char ring[10]; /*!< Message ID of ring */
|
|
|
|
iksrule *ringrule; /*!< Rule for matching RING request */
|
|
|
|
int initiator; /*!< If we're the initiator */
|
2006-05-22 21:12:30 +00:00
|
|
|
int alreadygone;
|
|
|
|
struct ast_codec_pref prefs;
|
|
|
|
struct jingle_candidate *theircandidates;
|
|
|
|
struct jingle_candidate *ourcandidates;
|
2006-08-07 21:15:28 +00:00
|
|
|
char cid_num[80]; /*!< Caller ID num */
|
|
|
|
char cid_name[80]; /*!< Caller ID name */
|
|
|
|
char exten[80]; /*!< Called extension */
|
|
|
|
struct ast_channel *owner; /*!< Master Channel */
|
2008-05-28 14:10:48 +00:00
|
|
|
char audio_content_name[100]; /*!< name attribute of content tag */
|
2009-04-02 17:20:52 +00:00
|
|
|
struct ast_rtp_instance *rtp; /*!< RTP audio session */
|
2008-05-28 14:10:48 +00:00
|
|
|
char video_content_name[100]; /*!< name attribute of content tag */
|
2009-04-02 17:20:52 +00:00
|
|
|
struct ast_rtp_instance *vrtp; /*!< RTP video session */
|
2011-02-03 16:22:10 +00:00
|
|
|
struct ast_format_cap *cap;
|
|
|
|
struct ast_format_cap *jointcap; /*!< Supported capability at both ends (codecs ) */
|
|
|
|
struct ast_format_cap *peercap;
|
2006-05-22 21:12:30 +00:00
|
|
|
struct jingle_pvt *next; /* Next entity */
|
|
|
|
};
|
|
|
|
|
|
|
|
struct jingle_candidate {
|
2007-09-25 09:07:30 +00:00
|
|
|
unsigned int component; /*!< ex. : 1 for RTP, 2 for RTCP */
|
|
|
|
unsigned int foundation; /*!< Function of IP, protocol, type */
|
|
|
|
unsigned int generation;
|
|
|
|
char ip[16];
|
|
|
|
unsigned int network;
|
|
|
|
unsigned int port;
|
|
|
|
unsigned int priority;
|
2006-05-22 21:12:30 +00:00
|
|
|
enum jingle_protocol protocol;
|
|
|
|
char password[100];
|
|
|
|
enum jingle_connect_type type;
|
2007-09-25 09:07:30 +00:00
|
|
|
char ufrag[100];
|
|
|
|
unsigned int preference;
|
2006-05-22 21:12:30 +00:00
|
|
|
struct jingle_candidate *next;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct jingle {
|
|
|
|
ASTOBJ_COMPONENTS(struct jingle);
|
|
|
|
struct aji_client *connection;
|
|
|
|
struct aji_buddy *buddy;
|
|
|
|
struct jingle_pvt *p;
|
|
|
|
struct ast_codec_pref prefs;
|
|
|
|
int amaflags; /*!< AMA Flags */
|
|
|
|
char user[100];
|
|
|
|
char context[100];
|
2006-08-07 21:15:28 +00:00
|
|
|
char accountcode[AST_MAX_ACCOUNT_CODE]; /*!< Account code */
|
2011-02-03 16:22:10 +00:00
|
|
|
struct ast_format_cap *cap;
|
2006-05-22 21:12:30 +00:00
|
|
|
ast_group_t callgroup; /*!< Call group */
|
|
|
|
ast_group_t pickupgroup; /*!< Pickup group */
|
|
|
|
int callingpres; /*!< Calling presentation */
|
|
|
|
int allowguest;
|
|
|
|
char language[MAX_LANGUAGE]; /*!< Default language for prompts */
|
|
|
|
char musicclass[MAX_MUSICCLASS]; /*!< Music on Hold class */
|
2008-04-21 23:42:45 +00:00
|
|
|
char parkinglot[AST_MAX_CONTEXT]; /*!< Parkinglot */
|
2006-05-22 21:12:30 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct jingle_container {
|
2006-09-18 16:36:14 +00:00
|
|
|
ASTOBJ_CONTAINER_COMPONENTS(struct jingle);
|
2006-05-22 21:12:30 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const char desc[] = "Jingle Channel";
|
2008-08-09 12:53:57 +00:00
|
|
|
static const char channel_type[] = "Jingle";
|
2006-05-22 21:12:30 +00:00
|
|
|
|
2011-02-03 16:22:10 +00:00
|
|
|
static struct ast_format_cap *global_capability;
|
2006-05-22 21:12:30 +00:00
|
|
|
|
2006-08-08 17:07:41 +00:00
|
|
|
AST_MUTEX_DEFINE_STATIC(jinglelock); /*!< Protect the interface list (of jingle_pvt's) */
|
2006-05-22 21:12:30 +00:00
|
|
|
|
2006-08-07 21:15:28 +00:00
|
|
|
/* Forward declarations */
|
2012-02-01 19:53:38 +00:00
|
|
|
static struct ast_channel *jingle_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause);
|
2009-09-25 10:54:42 +00:00
|
|
|
static int jingle_sendtext(struct ast_channel *ast, const char *text);
|
2006-08-31 01:59:02 +00:00
|
|
|
static int jingle_digit_begin(struct ast_channel *ast, char digit);
|
Merged revisions 51311 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r51311 | russell | 2007-01-19 11:49:38 -0600 (Fri, 19 Jan 2007) | 23 lines
Merge the changes from the /team/group/vldtmf_fixup branch.
The main bug being addressed here is a problem introduced when two SIP
channels using SIP INFO dtmf have their media directly bridged. So, when a
DTMF END frame comes into Asterisk from an incoming INFO message, Asterisk
would try to emulate a digit of some length by first sending a DTMF BEGIN
frame and sending a DTMF END later timed off of incoming audio. However,
since there was no audio coming in, the DTMF_END was never generated. This
caused DTMF based features to no longer work.
To fix this, the core now knows when a channel doesn't care about DTMF BEGIN
frames (such as a SIP channel sending INFO dtmf). If this is the case, then
Asterisk will not emulate a digit of some length, and will instead just pass
through the single DTMF END event.
Channel drivers also now get passed the length of the digit to their digit_end
callback. This improves SIP INFO support even further by enabling us to put
the real digit duration in the INFO message instead of a hard coded 250ms.
Also, for an incoming INFO message, the duration is read from the frame and
passed into the core instead of just getting ignored.
(issue #8597, maybe others...)
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@51314 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-01-19 18:06:03 +00:00
|
|
|
static int jingle_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
|
2012-02-01 19:53:38 +00:00
|
|
|
static int jingle_call(struct ast_channel *ast, const char *dest, int timeout);
|
2006-05-22 21:12:30 +00:00
|
|
|
static int jingle_hangup(struct ast_channel *ast);
|
|
|
|
static int jingle_answer(struct ast_channel *ast);
|
|
|
|
static int jingle_newcall(struct jingle *client, ikspak *pak);
|
|
|
|
static struct ast_frame *jingle_read(struct ast_channel *ast);
|
|
|
|
static int jingle_write(struct ast_channel *ast, struct ast_frame *f);
|
2006-05-23 16:25:37 +00:00
|
|
|
static int jingle_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
|
2006-05-22 21:12:30 +00:00
|
|
|
static int jingle_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
|
|
|
|
static int jingle_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
|
|
|
|
static struct jingle_pvt *jingle_alloc(struct jingle *client, const char *from, const char *sid);
|
2007-10-16 10:29:33 +00:00
|
|
|
static char *jingle_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
|
|
|
|
static char *jingle_do_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
|
2006-05-22 21:12:30 +00:00
|
|
|
|
2006-08-07 21:15:28 +00:00
|
|
|
/*! \brief PBX interface structure for channel registration */
|
2011-02-03 16:22:10 +00:00
|
|
|
static struct ast_channel_tech jingle_tech = {
|
2007-10-15 15:26:58 +00:00
|
|
|
.type = "Jingle",
|
2006-08-21 02:11:39 +00:00
|
|
|
.description = "Jingle Channel Driver",
|
2006-05-22 21:12:30 +00:00
|
|
|
.requester = jingle_request,
|
2009-09-25 10:54:42 +00:00
|
|
|
.send_text = jingle_sendtext,
|
2006-08-31 01:59:02 +00:00
|
|
|
.send_digit_begin = jingle_digit_begin,
|
|
|
|
.send_digit_end = jingle_digit_end,
|
2009-04-02 17:20:52 +00:00
|
|
|
.bridge = ast_rtp_instance_bridge,
|
2006-05-22 21:12:30 +00:00
|
|
|
.call = jingle_call,
|
|
|
|
.hangup = jingle_hangup,
|
|
|
|
.answer = jingle_answer,
|
|
|
|
.read = jingle_read,
|
|
|
|
.write = jingle_write,
|
|
|
|
.exception = jingle_read,
|
|
|
|
.indicate = jingle_indicate,
|
|
|
|
.fixup = jingle_fixup,
|
|
|
|
.send_html = jingle_sendhtml,
|
2006-05-31 17:21:21 +00:00
|
|
|
.properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER
|
2006-05-22 21:12:30 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct sockaddr_in bindaddr = { 0, }; /*!< The address we bind to */
|
|
|
|
|
2010-12-20 17:15:54 +00:00
|
|
|
static struct ast_sched_context *sched; /*!< The scheduling context */
|
2006-05-22 21:12:30 +00:00
|
|
|
static struct io_context *io; /*!< The IO context */
|
|
|
|
static struct in_addr __ourip;
|
|
|
|
|
2007-10-16 10:29:33 +00:00
|
|
|
static struct ast_cli_entry jingle_cli[] = {
|
2007-10-22 20:05:18 +00:00
|
|
|
AST_CLI_DEFINE(jingle_do_reload, "Reload Jingle configuration"),
|
|
|
|
AST_CLI_DEFINE(jingle_show_channels, "Show Jingle channels"),
|
2007-10-16 10:29:33 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2006-05-27 18:47:44 +00:00
|
|
|
static char externip[16];
|
2006-05-22 21:12:30 +00:00
|
|
|
|
2007-10-16 10:29:33 +00:00
|
|
|
static struct jingle_container jingle_list;
|
2006-05-22 21:12:30 +00:00
|
|
|
|
|
|
|
static void jingle_member_destroy(struct jingle *obj)
|
|
|
|
{
|
2011-02-03 16:22:10 +00:00
|
|
|
obj->cap = ast_format_cap_destroy(obj->cap);
|
2011-11-23 17:16:33 +00:00
|
|
|
if (obj->connection) {
|
|
|
|
ASTOBJ_UNREF(obj->connection, ast_aji_client_destroy);
|
|
|
|
}
|
|
|
|
if (obj->buddy) {
|
|
|
|
ASTOBJ_UNREF(obj->buddy, ast_aji_buddy_destroy);
|
|
|
|
}
|
2007-06-03 06:10:27 +00:00
|
|
|
ast_free(obj);
|
2006-05-22 21:12:30 +00:00
|
|
|
}
|
|
|
|
|
2011-11-23 17:16:33 +00:00
|
|
|
/* XXX This could be a source of reference leaks given that the CONTAINER_FIND
|
|
|
|
* macros bump the refcount while the traversal does not. */
|
2006-05-22 21:12:30 +00:00
|
|
|
static struct jingle *find_jingle(char *name, char *connection)
|
|
|
|
{
|
|
|
|
struct jingle *jingle = NULL;
|
|
|
|
|
2007-10-16 10:29:33 +00:00
|
|
|
jingle = ASTOBJ_CONTAINER_FIND(&jingle_list, name);
|
2006-05-22 21:12:30 +00:00
|
|
|
if (!jingle && strchr(name, '@'))
|
2007-10-16 10:29:33 +00:00
|
|
|
jingle = ASTOBJ_CONTAINER_FIND_FULL(&jingle_list, name, user,,, strcasecmp);
|
2006-05-22 21:12:30 +00:00
|
|
|
|
2008-06-02 14:35:24 +00:00
|
|
|
if (!jingle) {
|
|
|
|
/* guest call */
|
2007-10-16 10:29:33 +00:00
|
|
|
ASTOBJ_CONTAINER_TRAVERSE(&jingle_list, 1, {
|
2007-02-21 20:30:54 +00:00
|
|
|
ASTOBJ_RDLOCK(iterator);
|
2006-05-22 21:12:30 +00:00
|
|
|
if (!strcasecmp(iterator->name, "guest")) {
|
2008-06-02 14:35:24 +00:00
|
|
|
jingle = iterator;
|
2006-05-22 21:12:30 +00:00
|
|
|
}
|
|
|
|
ASTOBJ_UNLOCK(iterator);
|
2007-02-21 20:30:54 +00:00
|
|
|
|
|
|
|
if (jingle)
|
|
|
|
break;
|
2006-05-22 21:12:30 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
return jingle;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-02-03 16:22:10 +00:00
|
|
|
static void add_codec_to_answer(const struct jingle_pvt *p, struct ast_format *codec, iks *dcodecs)
|
2006-05-22 21:12:30 +00:00
|
|
|
{
|
Media Project Phase2: SILK 8khz-24khz, SLINEAR 8khz-192khz, SPEEX 32khz, hd audio ConfBridge, and other stuff
-Functional changes
1. Dynamic global format list build by codecs defined in codecs.conf
2. SILK 8khz, 12khz, 16khz, and 24khz with custom attributes defined in codecs.conf
3. Negotiation of SILK attributes in chan_sip.
4. SPEEX 32khz with translation
5. SLINEAR 8khz, 12khz, 24khz, 32khz, 44.1khz, 48khz, 96khz, 192khz with translation
using codec_resample.c
6. Various changes to RTP code required to properly handle the dynamic format list
and formats with attributes.
7. ConfBridge now dynamically jumps to the best possible sample rate. This allows
for conferences to take advantage of HD audio (Which sounds awesome)
8. Audiohooks are no longer limited to 8khz audio, and most effects have been
updated to take advantage of this such as Volume, DENOISE, PITCH_SHIFT.
9. codec_resample now uses its own code rather than depending on libresample.
-Organizational changes
Global format list is moved from frame.c to format.c
Various format specific functions moved from frame.c to format.c
Review: https://reviewboard.asterisk.org/r/1104/
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@308582 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2011-02-22 23:04:49 +00:00
|
|
|
const char *format = ast_getformatname(codec);
|
2006-08-07 21:15:28 +00:00
|
|
|
|
|
|
|
if (!strcasecmp("ulaw", format)) {
|
2006-05-22 21:12:30 +00:00
|
|
|
iks *payload_eg711u, *payload_pcmu;
|
|
|
|
payload_pcmu = iks_new("payload-type");
|
|
|
|
iks_insert_attrib(payload_pcmu, "id", "0");
|
|
|
|
iks_insert_attrib(payload_pcmu, "name", "PCMU");
|
|
|
|
payload_eg711u = iks_new("payload-type");
|
|
|
|
iks_insert_attrib(payload_eg711u, "id", "100");
|
|
|
|
iks_insert_attrib(payload_eg711u, "name", "EG711U");
|
|
|
|
iks_insert_node(dcodecs, payload_pcmu);
|
2006-05-23 16:43:58 +00:00
|
|
|
iks_insert_node(dcodecs, payload_eg711u);
|
2006-05-22 21:12:30 +00:00
|
|
|
}
|
2006-08-07 21:15:28 +00:00
|
|
|
if (!strcasecmp("alaw", format)) {
|
|
|
|
iks *payload_eg711a;
|
|
|
|
iks *payload_pcma = iks_new("payload-type");
|
2006-05-22 21:12:30 +00:00
|
|
|
iks_insert_attrib(payload_pcma, "id", "8");
|
|
|
|
iks_insert_attrib(payload_pcma, "name", "PCMA");
|
|
|
|
payload_eg711a = iks_new("payload-type");
|
|
|
|
iks_insert_attrib(payload_eg711a, "id", "101");
|
|
|
|
iks_insert_attrib(payload_eg711a, "name", "EG711A");
|
|
|
|
iks_insert_node(dcodecs, payload_pcma);
|
|
|
|
iks_insert_node(dcodecs, payload_eg711a);
|
|
|
|
}
|
2006-08-07 21:15:28 +00:00
|
|
|
if (!strcasecmp("ilbc", format)) {
|
|
|
|
iks *payload_ilbc = iks_new("payload-type");
|
2007-06-27 23:14:39 +00:00
|
|
|
iks_insert_attrib(payload_ilbc, "id", "97");
|
2006-05-22 21:12:30 +00:00
|
|
|
iks_insert_attrib(payload_ilbc, "name", "iLBC");
|
|
|
|
iks_insert_node(dcodecs, payload_ilbc);
|
|
|
|
}
|
2006-08-07 21:15:28 +00:00
|
|
|
if (!strcasecmp("g723", format)) {
|
|
|
|
iks *payload_g723 = iks_new("payload-type");
|
2006-05-22 21:12:30 +00:00
|
|
|
iks_insert_attrib(payload_g723, "id", "4");
|
|
|
|
iks_insert_attrib(payload_g723, "name", "G723");
|
|
|
|
iks_insert_node(dcodecs, payload_g723);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int jingle_accept_call(struct jingle *client, struct jingle_pvt *p)
|
|
|
|
{
|
|
|
|
struct jingle_pvt *tmp = client->p;
|
|
|
|
struct aji_client *c = client->connection;
|
|
|
|
iks *iq, *jingle, *dcodecs, *payload_red, *payload_audio, *payload_cn;
|
|
|
|
int x;
|
2011-02-03 16:22:10 +00:00
|
|
|
struct ast_format pref_codec;
|
|
|
|
struct ast_format_cap *alreadysent = ast_format_cap_alloc_nolock();
|
2006-05-22 21:12:30 +00:00
|
|
|
|
2011-02-03 16:22:10 +00:00
|
|
|
if (p->initiator || !alreadysent)
|
2006-05-22 21:12:30 +00:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
iq = iks_new("iq");
|
2007-09-19 13:55:08 +00:00
|
|
|
jingle = iks_new(JINGLE_NODE);
|
2006-05-22 21:12:30 +00:00
|
|
|
dcodecs = iks_new("description");
|
|
|
|
if (iq && jingle && dcodecs) {
|
2007-09-19 13:55:08 +00:00
|
|
|
iks_insert_attrib(dcodecs, "xmlns", JINGLE_AUDIO_RTP_NS);
|
2006-05-22 21:12:30 +00:00
|
|
|
|
2011-02-03 16:22:10 +00:00
|
|
|
for (x = 0; x < AST_CODEC_PREF_SIZE; x++) {
|
|
|
|
if (!(ast_codec_pref_index(&client->prefs, x, &pref_codec)))
|
2006-05-22 21:12:30 +00:00
|
|
|
break;
|
2011-02-03 16:22:10 +00:00
|
|
|
if (!(ast_format_cap_iscompatible(client->cap, &pref_codec)))
|
2006-05-22 21:12:30 +00:00
|
|
|
continue;
|
2011-02-03 16:22:10 +00:00
|
|
|
if ((ast_format_cap_iscompatible(alreadysent, &pref_codec)))
|
2006-05-22 21:12:30 +00:00
|
|
|
continue;
|
2011-02-03 16:22:10 +00:00
|
|
|
add_codec_to_answer(p, &pref_codec, dcodecs);
|
|
|
|
ast_format_cap_add(alreadysent, &pref_codec);
|
2006-05-22 21:12:30 +00:00
|
|
|
}
|
|
|
|
payload_red = iks_new("payload-type");
|
|
|
|
iks_insert_attrib(payload_red, "id", "117");
|
|
|
|
iks_insert_attrib(payload_red, "name", "red");
|
|
|
|
payload_audio = iks_new("payload-type");
|
|
|
|
iks_insert_attrib(payload_audio, "id", "106");
|
|
|
|
iks_insert_attrib(payload_audio, "name", "audio/telephone-event");
|
|
|
|
payload_cn = iks_new("payload-type");
|
|
|
|
iks_insert_attrib(payload_cn, "id", "13");
|
|
|
|
iks_insert_attrib(payload_cn, "name", "CN");
|
|
|
|
|
|
|
|
|
|
|
|
iks_insert_attrib(iq, "type", "set");
|
2007-10-16 10:29:33 +00:00
|
|
|
iks_insert_attrib(iq, "to", (p->them) ? p->them : client->user);
|
2006-05-22 21:12:30 +00:00
|
|
|
iks_insert_attrib(iq, "id", client->connection->mid);
|
|
|
|
ast_aji_increment_mid(client->connection->mid);
|
|
|
|
|
2007-09-19 13:55:08 +00:00
|
|
|
iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
|
2007-09-25 09:07:30 +00:00
|
|
|
iks_insert_attrib(jingle, "action", JINGLE_ACCEPT);
|
2007-10-16 10:29:33 +00:00
|
|
|
iks_insert_attrib(jingle, "initiator", p->initiator ? client->connection->jid->full : p->them);
|
2007-09-19 13:55:08 +00:00
|
|
|
iks_insert_attrib(jingle, JINGLE_SID, tmp->sid);
|
2006-05-22 21:12:30 +00:00
|
|
|
iks_insert_node(iq, jingle);
|
|
|
|
iks_insert_node(jingle, dcodecs);
|
|
|
|
iks_insert_node(dcodecs, payload_red);
|
|
|
|
iks_insert_node(dcodecs, payload_audio);
|
|
|
|
iks_insert_node(dcodecs, payload_cn);
|
|
|
|
|
2007-11-06 18:44:19 +00:00
|
|
|
ast_aji_send(c, iq);
|
2008-02-29 14:15:03 +00:00
|
|
|
|
2006-05-22 21:12:30 +00:00
|
|
|
iks_delete(payload_red);
|
|
|
|
iks_delete(payload_audio);
|
|
|
|
iks_delete(payload_cn);
|
|
|
|
iks_delete(dcodecs);
|
|
|
|
iks_delete(jingle);
|
|
|
|
iks_delete(iq);
|
|
|
|
}
|
2011-02-03 16:22:10 +00:00
|
|
|
alreadysent = ast_format_cap_destroy(alreadysent);
|
2006-05-22 21:12:30 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int jingle_ringing_ack(void *data, ikspak *pak)
|
|
|
|
{
|
|
|
|
struct jingle_pvt *p = data;
|
2006-08-07 21:15:28 +00:00
|
|
|
|
2006-05-22 21:12:30 +00:00
|
|
|
if (p->ringrule)
|
|
|
|
iks_filter_remove_rule(p->parent->connection->f, p->ringrule);
|
|
|
|
p->ringrule = NULL;
|
|
|
|
if (p->owner)
|
|
|
|
ast_queue_control(p->owner, AST_CONTROL_RINGING);
|
|
|
|
return IKS_FILTER_EAT;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int jingle_answer(struct ast_channel *ast)
|
|
|
|
{
|
2012-02-20 23:43:27 +00:00
|
|
|
struct jingle_pvt *p = ast_channel_tech_pvt(ast);
|
2006-05-22 21:12:30 +00:00
|
|
|
struct jingle *client = p->parent;
|
|
|
|
int res = 0;
|
2006-08-07 21:15:28 +00:00
|
|
|
|
2007-06-14 19:39:12 +00:00
|
|
|
ast_debug(1, "Answer!\n");
|
2006-05-22 21:12:30 +00:00
|
|
|
ast_mutex_lock(&p->lock);
|
|
|
|
jingle_accept_call(client, p);
|
|
|
|
ast_mutex_unlock(&p->lock);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2009-04-02 17:20:52 +00:00
|
|
|
static enum ast_rtp_glue_result jingle_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
|
2006-05-22 21:12:30 +00:00
|
|
|
{
|
2012-02-20 23:43:27 +00:00
|
|
|
struct jingle_pvt *p = ast_channel_tech_pvt(chan);
|
2009-04-02 17:20:52 +00:00
|
|
|
enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_FORBID;
|
2006-08-07 21:15:28 +00:00
|
|
|
|
2006-05-22 21:12:30 +00:00
|
|
|
if (!p)
|
2006-08-29 13:55:54 +00:00
|
|
|
return res;
|
|
|
|
|
2006-05-22 21:12:30 +00:00
|
|
|
ast_mutex_lock(&p->lock);
|
2006-08-29 13:55:54 +00:00
|
|
|
if (p->rtp) {
|
2009-04-02 17:20:52 +00:00
|
|
|
ao2_ref(p->rtp, +1);
|
|
|
|
*instance = p->rtp;
|
|
|
|
res = AST_RTP_GLUE_RESULT_LOCAL;
|
2006-08-29 13:55:54 +00:00
|
|
|
}
|
2006-05-22 21:12:30 +00:00
|
|
|
ast_mutex_unlock(&p->lock);
|
2006-08-29 13:55:54 +00:00
|
|
|
|
|
|
|
return res;
|
2006-05-22 21:12:30 +00:00
|
|
|
}
|
|
|
|
|
2011-02-03 16:22:10 +00:00
|
|
|
static void jingle_get_codec(struct ast_channel *chan, struct ast_format_cap *result)
|
2006-05-22 21:12:30 +00:00
|
|
|
{
|
2012-02-20 23:43:27 +00:00
|
|
|
struct jingle_pvt *p = ast_channel_tech_pvt(chan);
|
2011-02-03 16:22:10 +00:00
|
|
|
ast_mutex_lock(&p->lock);
|
|
|
|
ast_format_cap_copy(result, p->peercap);
|
|
|
|
ast_mutex_unlock(&p->lock);
|
2006-05-22 21:12:30 +00:00
|
|
|
}
|
|
|
|
|
2011-02-03 16:22:10 +00:00
|
|
|
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)
|
2006-05-22 21:12:30 +00:00
|
|
|
{
|
|
|
|
struct jingle_pvt *p;
|
|
|
|
|
2012-02-20 23:43:27 +00:00
|
|
|
p = ast_channel_tech_pvt(chan);
|
2006-05-22 21:12:30 +00:00
|
|
|
if (!p)
|
|
|
|
return -1;
|
|
|
|
ast_mutex_lock(&p->lock);
|
|
|
|
|
|
|
|
/* if (rtp)
|
|
|
|
ast_rtp_get_peer(rtp, &p->redirip);
|
|
|
|
else
|
|
|
|
memset(&p->redirip, 0, sizeof(p->redirip));
|
|
|
|
p->redircodecs = codecs; */
|
|
|
|
|
|
|
|
/* Reset lastrtprx timer */
|
|
|
|
ast_mutex_unlock(&p->lock);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-04-02 17:20:52 +00:00
|
|
|
static struct ast_rtp_glue jingle_rtp_glue = {
|
|
|
|
.type = "Jingle",
|
|
|
|
.get_rtp_info = jingle_get_rtp_peer,
|
|
|
|
.get_codec = jingle_get_codec,
|
|
|
|
.update_peer = jingle_set_rtp_peer,
|
|
|
|
};
|
|
|
|
|
2006-08-02 01:00:24 +00:00
|
|
|
static int jingle_response(struct jingle *client, ikspak *pak, const char *reasonstr, const char *reasonstr2)
|
2006-05-22 21:12:30 +00:00
|
|
|
{
|
2006-08-08 17:07:41 +00:00
|
|
|
iks *response = NULL, *error = NULL, *reason = NULL;
|
2006-05-22 21:12:30 +00:00
|
|
|
int res = -1;
|
|
|
|
|
|
|
|
response = iks_new("iq");
|
|
|
|
if (response) {
|
|
|
|
iks_insert_attrib(response, "type", "result");
|
|
|
|
iks_insert_attrib(response, "from", client->connection->jid->full);
|
|
|
|
iks_insert_attrib(response, "to", iks_find_attrib(pak->x, "from"));
|
|
|
|
iks_insert_attrib(response, "id", iks_find_attrib(pak->x, "id"));
|
|
|
|
if (reasonstr) {
|
|
|
|
error = iks_new("error");
|
|
|
|
if (error) {
|
|
|
|
iks_insert_attrib(error, "type", "cancel");
|
|
|
|
reason = iks_new(reasonstr);
|
|
|
|
if (reason)
|
|
|
|
iks_insert_node(error, reason);
|
|
|
|
iks_insert_node(response, error);
|
|
|
|
}
|
|
|
|
}
|
2007-11-06 18:44:19 +00:00
|
|
|
ast_aji_send(client->connection, response);
|
2006-05-22 21:12:30 +00:00
|
|
|
res = 0;
|
|
|
|
}
|
2008-02-29 14:15:03 +00:00
|
|
|
|
|
|
|
iks_delete(reason);
|
|
|
|
iks_delete(error);
|
|
|
|
iks_delete(response);
|
|
|
|
|
2006-05-22 21:12:30 +00:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int jingle_is_answered(struct jingle *client, ikspak *pak)
|
|
|
|
{
|
|
|
|
struct jingle_pvt *tmp;
|
|
|
|
|
2007-06-14 19:39:12 +00:00
|
|
|
ast_debug(1, "The client is %s\n", client->name);
|
2006-05-22 21:12:30 +00:00
|
|
|
/* Make sure our new call doesn't exist yet */
|
2006-06-18 20:51:14 +00:00
|
|
|
for (tmp = client->p; tmp; tmp = tmp->next) {
|
2007-09-19 13:55:08 +00:00
|
|
|
if (iks_find_with_attrib(pak->x, JINGLE_NODE, JINGLE_SID, tmp->sid))
|
2006-05-22 21:12:30 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tmp) {
|
|
|
|
if (tmp->owner)
|
|
|
|
ast_queue_control(tmp->owner, AST_CONTROL_ANSWER);
|
|
|
|
} else
|
|
|
|
ast_log(LOG_NOTICE, "Whoa, didn't find call!\n");
|
2006-08-02 01:00:24 +00:00
|
|
|
jingle_response(client, pak, NULL, NULL);
|
2006-05-22 21:12:30 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2006-08-02 01:00:24 +00:00
|
|
|
static int jingle_handle_dtmf(struct jingle *client, ikspak *pak)
|
|
|
|
{
|
|
|
|
struct jingle_pvt *tmp;
|
2007-09-14 13:02:31 +00:00
|
|
|
iks *dtmfnode = NULL, *dtmfchild = NULL;
|
2006-08-02 01:00:24 +00:00
|
|
|
char *dtmf;
|
|
|
|
/* Make sure our new call doesn't exist yet */
|
|
|
|
for (tmp = client->p; tmp; tmp = tmp->next) {
|
2007-09-19 13:55:08 +00:00
|
|
|
if (iks_find_with_attrib(pak->x, JINGLE_NODE, JINGLE_SID, tmp->sid))
|
2006-08-02 01:00:24 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tmp) {
|
|
|
|
if(iks_find_with_attrib(pak->x, "dtmf-method", "method", "rtp")) {
|
|
|
|
jingle_response(client,pak,
|
|
|
|
"feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'",
|
2007-09-13 15:05:16 +00:00
|
|
|
"unsupported-dtmf-method xmlns='http://www.xmpp.org/extensions/xep-0181.html#ns-errors'");
|
2006-08-02 01:00:24 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2006-09-18 16:36:14 +00:00
|
|
|
if ((dtmfnode = iks_find(pak->x, "dtmf"))) {
|
2006-08-02 01:00:24 +00:00
|
|
|
if((dtmf = iks_find_attrib(dtmfnode, "code"))) {
|
|
|
|
if(iks_find_with_attrib(pak->x, "dtmf", "action", "button-up")) {
|
|
|
|
struct ast_frame f = {AST_FRAME_DTMF_BEGIN, };
|
2009-11-04 14:05:12 +00:00
|
|
|
f.subclass.integer = dtmf[0];
|
2006-08-02 01:00:24 +00:00
|
|
|
ast_queue_frame(tmp->owner, &f);
|
2009-11-04 14:05:12 +00:00
|
|
|
ast_verbose("JINGLE! DTMF-relay event received: %c\n", f.subclass.integer);
|
2006-08-02 01:00:24 +00:00
|
|
|
} else if(iks_find_with_attrib(pak->x, "dtmf", "action", "button-down")) {
|
|
|
|
struct ast_frame f = {AST_FRAME_DTMF_END, };
|
2009-11-04 14:05:12 +00:00
|
|
|
f.subclass.integer = dtmf[0];
|
2006-08-02 01:00:24 +00:00
|
|
|
ast_queue_frame(tmp->owner, &f);
|
2009-11-04 14:05:12 +00:00
|
|
|
ast_verbose("JINGLE! DTMF-relay event received: %c\n", f.subclass.integer);
|
2006-08-02 01:00:24 +00:00
|
|
|
} else if(iks_find_attrib(pak->x, "dtmf")) { /* 250 millasecond default */
|
|
|
|
struct ast_frame f = {AST_FRAME_DTMF, };
|
2009-11-04 14:05:12 +00:00
|
|
|
f.subclass.integer = dtmf[0];
|
2006-08-02 01:00:24 +00:00
|
|
|
ast_queue_frame(tmp->owner, &f);
|
2009-11-04 14:05:12 +00:00
|
|
|
ast_verbose("JINGLE! DTMF-relay event received: %c\n", f.subclass.integer);
|
2006-08-02 01:00:24 +00:00
|
|
|
}
|
|
|
|
}
|
2007-09-14 13:02:31 +00:00
|
|
|
} else if ((dtmfnode = iks_find_with_attrib(pak->x, JINGLE_NODE, "action", "session-info"))) {
|
|
|
|
if((dtmfchild = iks_find(dtmfnode, "dtmf"))) {
|
|
|
|
if((dtmf = iks_find_attrib(dtmfchild, "code"))) {
|
|
|
|
if(iks_find_with_attrib(dtmfnode, "dtmf", "action", "button-up")) {
|
|
|
|
struct ast_frame f = {AST_FRAME_DTMF_END, };
|
2009-11-04 14:05:12 +00:00
|
|
|
f.subclass.integer = dtmf[0];
|
2007-09-14 13:02:31 +00:00
|
|
|
ast_queue_frame(tmp->owner, &f);
|
2009-11-04 14:05:12 +00:00
|
|
|
ast_verbose("JINGLE! DTMF-relay event received: %c\n", f.subclass.integer);
|
2007-09-14 13:02:31 +00:00
|
|
|
} else if(iks_find_with_attrib(dtmfnode, "dtmf", "action", "button-down")) {
|
|
|
|
struct ast_frame f = {AST_FRAME_DTMF_BEGIN, };
|
2009-11-04 14:05:12 +00:00
|
|
|
f.subclass.integer = dtmf[0];
|
2007-09-14 13:02:31 +00:00
|
|
|
ast_queue_frame(tmp->owner, &f);
|
2009-11-04 14:05:12 +00:00
|
|
|
ast_verbose("JINGLE! DTMF-relay event received: %c\n", f.subclass.integer);
|
2007-09-14 13:02:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2006-08-02 01:00:24 +00:00
|
|
|
}
|
|
|
|
jingle_response(client, pak, NULL, NULL);
|
|
|
|
return 1;
|
|
|
|
} else
|
|
|
|
ast_log(LOG_NOTICE, "Whoa, didn't find call!\n");
|
|
|
|
|
|
|
|
jingle_response(client, pak, NULL, NULL);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-05-22 21:12:30 +00:00
|
|
|
static int jingle_hangup_farend(struct jingle *client, ikspak *pak)
|
|
|
|
{
|
|
|
|
struct jingle_pvt *tmp;
|
|
|
|
|
2007-06-14 19:39:12 +00:00
|
|
|
ast_debug(1, "The client is %s\n", client->name);
|
2006-05-22 21:12:30 +00:00
|
|
|
/* Make sure our new call doesn't exist yet */
|
2006-06-18 20:51:14 +00:00
|
|
|
for (tmp = client->p; tmp; tmp = tmp->next) {
|
2007-09-19 13:55:08 +00:00
|
|
|
if (iks_find_with_attrib(pak->x, JINGLE_NODE, JINGLE_SID, tmp->sid))
|
2006-05-22 21:12:30 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tmp) {
|
|
|
|
tmp->alreadygone = 1;
|
2007-06-19 19:15:03 +00:00
|
|
|
if (tmp->owner)
|
2008-05-22 16:29:54 +00:00
|
|
|
ast_queue_hangup(tmp->owner);
|
2006-05-22 21:12:30 +00:00
|
|
|
} else
|
|
|
|
ast_log(LOG_NOTICE, "Whoa, didn't find call!\n");
|
2006-08-02 01:00:24 +00:00
|
|
|
jingle_response(client, pak, NULL, NULL);
|
2006-05-22 21:12:30 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int jingle_create_candidates(struct jingle *client, struct jingle_pvt *p, char *sid, char *from)
|
|
|
|
{
|
|
|
|
struct jingle_candidate *tmp;
|
|
|
|
struct aji_client *c = client->connection;
|
|
|
|
struct jingle_candidate *ours1 = NULL, *ours2 = NULL;
|
2009-04-10 18:02:44 +00:00
|
|
|
struct sockaddr_in sin = { 0, };
|
2010-07-08 22:08:07 +00:00
|
|
|
struct ast_sockaddr sin_tmp;
|
|
|
|
struct ast_sockaddr us_tmp;
|
|
|
|
struct ast_sockaddr bindaddr_tmp;
|
2006-05-22 21:12:30 +00:00
|
|
|
struct in_addr us;
|
2007-09-25 09:07:30 +00:00
|
|
|
struct in_addr externaddr;
|
|
|
|
iks *iq, *jingle, *content, *transport, *candidate;
|
|
|
|
char component[16], foundation[16], generation[16], network[16], pass[16], port[7], priority[16], user[16];
|
2006-05-22 21:12:30 +00:00
|
|
|
|
|
|
|
|
|
|
|
iq = iks_new("iq");
|
2007-09-19 13:55:08 +00:00
|
|
|
jingle = iks_new(JINGLE_NODE);
|
2007-09-25 09:07:30 +00:00
|
|
|
content = iks_new("content");
|
|
|
|
transport = iks_new("transport");
|
2006-05-22 21:12:30 +00:00
|
|
|
candidate = iks_new("candidate");
|
2007-09-25 09:07:30 +00:00
|
|
|
if (!iq || !jingle || !content || !transport || !candidate) {
|
2006-06-18 20:51:14 +00:00
|
|
|
ast_log(LOG_ERROR, "Memory allocation error\n");
|
2006-05-22 21:12:30 +00:00
|
|
|
goto safeout;
|
|
|
|
}
|
2006-06-18 20:51:14 +00:00
|
|
|
ours1 = ast_calloc(1, sizeof(*ours1));
|
|
|
|
ours2 = ast_calloc(1, sizeof(*ours2));
|
2006-06-18 21:24:35 +00:00
|
|
|
if (!ours1 || !ours2)
|
|
|
|
goto safeout;
|
2007-09-25 09:07:30 +00:00
|
|
|
|
2006-05-22 21:12:30 +00:00
|
|
|
iks_insert_node(iq, jingle);
|
2007-09-25 09:07:30 +00:00
|
|
|
iks_insert_node(jingle, content);
|
|
|
|
iks_insert_node(content, transport);
|
|
|
|
iks_insert_node(transport, candidate);
|
2006-05-22 21:12:30 +00:00
|
|
|
|
2006-06-18 20:51:14 +00:00
|
|
|
for (; p; p = p->next) {
|
|
|
|
if (!strcasecmp(p->sid, sid))
|
2006-05-22 21:12:30 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!p) {
|
2006-08-07 21:15:28 +00:00
|
|
|
ast_log(LOG_NOTICE, "No matching jingle session - SID %s!\n", sid);
|
2006-05-22 21:12:30 +00:00
|
|
|
goto safeout;
|
|
|
|
}
|
|
|
|
|
2010-07-08 22:08:07 +00:00
|
|
|
ast_rtp_instance_get_local_address(p->rtp, &sin_tmp);
|
|
|
|
ast_sockaddr_to_sin(&sin_tmp, &sin);
|
2010-07-08 23:46:20 +00:00
|
|
|
ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
|
2010-10-14 15:21:42 +00:00
|
|
|
ast_find_ourip(&us_tmp, &bindaddr_tmp, AF_INET);
|
2010-07-08 22:08:07 +00:00
|
|
|
us.s_addr = htonl(ast_sockaddr_ipv4(&us_tmp));
|
2006-05-22 21:12:30 +00:00
|
|
|
|
2007-09-25 09:07:30 +00:00
|
|
|
/* Setup our first jingle candidate */
|
|
|
|
ours1->component = 1;
|
|
|
|
ours1->foundation = (unsigned int)bindaddr.sin_addr.s_addr | AJI_CONNECT_HOST | AJI_PROTOCOL_UDP;
|
|
|
|
ours1->generation = 0;
|
|
|
|
ast_copy_string(ours1->ip, ast_inet_ntoa(us), sizeof(ours1->ip));
|
|
|
|
ours1->network = 0;
|
2006-05-22 21:12:30 +00:00
|
|
|
ours1->port = ntohs(sin.sin_port);
|
2007-09-25 09:07:30 +00:00
|
|
|
ours1->priority = 1678246398;
|
|
|
|
ours1->protocol = AJI_PROTOCOL_UDP;
|
2006-05-30 20:24:40 +00:00
|
|
|
snprintf(pass, sizeof(pass), "%08lx%08lx", ast_random(), ast_random());
|
2006-05-22 21:12:30 +00:00
|
|
|
ast_copy_string(ours1->password, pass, sizeof(ours1->password));
|
2007-09-25 09:07:30 +00:00
|
|
|
ours1->type = AJI_CONNECT_HOST;
|
|
|
|
snprintf(user, sizeof(user), "%08lx%08lx", ast_random(), ast_random());
|
|
|
|
ast_copy_string(ours1->ufrag, user, sizeof(ours1->ufrag));
|
2006-05-22 21:12:30 +00:00
|
|
|
p->ourcandidates = ours1;
|
|
|
|
|
|
|
|
if (!ast_strlen_zero(externip)) {
|
|
|
|
/* XXX We should really stun for this one not just go with externip XXX */
|
2007-09-25 09:07:30 +00:00
|
|
|
if (inet_aton(externip, &externaddr))
|
|
|
|
ast_log(LOG_WARNING, "Invalid extern IP : %s\n", externip);
|
|
|
|
|
|
|
|
ours2->component = 1;
|
|
|
|
ours2->foundation = (unsigned int)externaddr.s_addr | AJI_CONNECT_PRFLX | AJI_PROTOCOL_UDP;
|
|
|
|
ours2->generation = 0;
|
2006-05-22 21:12:30 +00:00
|
|
|
ast_copy_string(ours2->ip, externip, sizeof(ours2->ip));
|
2007-09-25 09:07:30 +00:00
|
|
|
ours2->network = 0;
|
2006-05-22 21:12:30 +00:00
|
|
|
ours2->port = ntohs(sin.sin_port);
|
2007-09-25 09:07:30 +00:00
|
|
|
ours2->priority = 1678246397;
|
2006-05-22 21:12:30 +00:00
|
|
|
ours2->protocol = AJI_PROTOCOL_UDP;
|
2007-09-25 09:07:30 +00:00
|
|
|
snprintf(pass, sizeof(pass), "%08lx%08lx", ast_random(), ast_random());
|
|
|
|
ast_copy_string(ours2->password, pass, sizeof(ours2->password));
|
|
|
|
ours2->type = AJI_CONNECT_PRFLX;
|
|
|
|
|
|
|
|
snprintf(user, sizeof(user), "%08lx%08lx", ast_random(), ast_random());
|
|
|
|
ast_copy_string(ours2->ufrag, user, sizeof(ours2->ufrag));
|
2006-05-22 21:12:30 +00:00
|
|
|
ours1->next = ours2;
|
|
|
|
ours2 = NULL;
|
|
|
|
}
|
|
|
|
ours1 = NULL;
|
|
|
|
|
2006-06-18 20:51:14 +00:00
|
|
|
for (tmp = p->ourcandidates; tmp; tmp = tmp->next) {
|
2007-09-25 09:07:30 +00:00
|
|
|
snprintf(component, sizeof(component), "%u", tmp->component);
|
|
|
|
snprintf(foundation, sizeof(foundation), "%u", tmp->foundation);
|
|
|
|
snprintf(generation, sizeof(generation), "%u", tmp->generation);
|
|
|
|
snprintf(network, sizeof(network), "%u", tmp->network);
|
|
|
|
snprintf(port, sizeof(port), "%u", tmp->port);
|
|
|
|
snprintf(priority, sizeof(priority), "%u", tmp->priority);
|
|
|
|
|
2006-05-22 21:12:30 +00:00
|
|
|
iks_insert_attrib(iq, "from", c->jid->full);
|
|
|
|
iks_insert_attrib(iq, "to", from);
|
|
|
|
iks_insert_attrib(iq, "type", "set");
|
|
|
|
iks_insert_attrib(iq, "id", c->mid);
|
|
|
|
ast_aji_increment_mid(c->mid);
|
2007-09-25 09:07:30 +00:00
|
|
|
iks_insert_attrib(jingle, "action", JINGLE_NEGOTIATE);
|
|
|
|
iks_insert_attrib(jingle, JINGLE_SID, sid);
|
2006-05-22 21:12:30 +00:00
|
|
|
iks_insert_attrib(jingle, "initiator", (p->initiator) ? c->jid->full : from);
|
2007-09-19 13:55:08 +00:00
|
|
|
iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
|
2007-09-25 09:07:30 +00:00
|
|
|
iks_insert_attrib(content, "creator", p->initiator ? "initiator" : "responder");
|
|
|
|
iks_insert_attrib(content, "name", "asterisk-audio-content");
|
|
|
|
iks_insert_attrib(transport, "xmlns", JINGLE_ICE_UDP_NS);
|
|
|
|
iks_insert_attrib(candidate, "component", component);
|
|
|
|
iks_insert_attrib(candidate, "foundation", foundation);
|
|
|
|
iks_insert_attrib(candidate, "generation", generation);
|
|
|
|
iks_insert_attrib(candidate, "ip", tmp->ip);
|
|
|
|
iks_insert_attrib(candidate, "network", network);
|
2006-05-22 21:12:30 +00:00
|
|
|
iks_insert_attrib(candidate, "port", port);
|
2007-09-25 09:07:30 +00:00
|
|
|
iks_insert_attrib(candidate, "priority", priority);
|
|
|
|
switch (tmp->protocol) {
|
|
|
|
case AJI_PROTOCOL_UDP:
|
2006-05-22 21:12:30 +00:00
|
|
|
iks_insert_attrib(candidate, "protocol", "udp");
|
2007-09-25 09:07:30 +00:00
|
|
|
break;
|
|
|
|
case AJI_PROTOCOL_SSLTCP:
|
2006-05-22 21:12:30 +00:00
|
|
|
iks_insert_attrib(candidate, "protocol", "ssltcp");
|
2007-09-25 09:07:30 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
iks_insert_attrib(candidate, "pwd", tmp->password);
|
|
|
|
switch (tmp->type) {
|
|
|
|
case AJI_CONNECT_HOST:
|
|
|
|
iks_insert_attrib(candidate, "type", "host");
|
|
|
|
break;
|
|
|
|
case AJI_CONNECT_PRFLX:
|
|
|
|
iks_insert_attrib(candidate, "type", "prflx");
|
|
|
|
break;
|
|
|
|
case AJI_CONNECT_RELAY:
|
2006-05-22 21:12:30 +00:00
|
|
|
iks_insert_attrib(candidate, "type", "relay");
|
2007-09-25 09:07:30 +00:00
|
|
|
break;
|
|
|
|
case AJI_CONNECT_SRFLX:
|
|
|
|
iks_insert_attrib(candidate, "type", "srflx");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
iks_insert_attrib(candidate, "ufrag", tmp->ufrag);
|
|
|
|
|
2007-11-06 18:44:19 +00:00
|
|
|
ast_aji_send(c, iq);
|
2006-05-22 21:12:30 +00:00
|
|
|
}
|
|
|
|
p->laststun = 0;
|
|
|
|
|
|
|
|
safeout:
|
|
|
|
if (ours1)
|
2007-06-03 06:10:27 +00:00
|
|
|
ast_free(ours1);
|
2006-05-22 21:12:30 +00:00
|
|
|
if (ours2)
|
2007-06-03 06:10:27 +00:00
|
|
|
ast_free(ours2);
|
2008-02-29 14:15:03 +00:00
|
|
|
iks_delete(iq);
|
|
|
|
iks_delete(jingle);
|
|
|
|
iks_delete(content);
|
|
|
|
iks_delete(transport);
|
|
|
|
iks_delete(candidate);
|
|
|
|
|
2006-05-22 21:12:30 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct jingle_pvt *jingle_alloc(struct jingle *client, const char *from, const char *sid)
|
|
|
|
{
|
|
|
|
struct jingle_pvt *tmp = NULL;
|
|
|
|
struct aji_resource *resources = NULL;
|
2011-11-23 17:16:33 +00:00
|
|
|
struct aji_buddy *buddy = NULL;
|
2006-05-22 21:12:30 +00:00
|
|
|
char idroster[200];
|
2010-07-08 22:08:07 +00:00
|
|
|
struct ast_sockaddr bindaddr_tmp;
|
2006-05-22 21:12:30 +00:00
|
|
|
|
2007-06-14 19:39:12 +00:00
|
|
|
ast_debug(1, "The client is %s for alloc\n", client->name);
|
2006-08-07 21:15:28 +00:00
|
|
|
if (!sid && !strchr(from, '/')) { /* I started call! */
|
2006-05-22 21:12:30 +00:00
|
|
|
if (!strcasecmp(client->name, "guest")) {
|
|
|
|
buddy = ASTOBJ_CONTAINER_FIND(&client->connection->buddies, from);
|
2011-11-23 17:16:33 +00:00
|
|
|
if (buddy) {
|
2006-05-22 21:12:30 +00:00
|
|
|
resources = buddy->resources;
|
2011-11-23 17:16:33 +00:00
|
|
|
}
|
2007-02-21 02:04:10 +00:00
|
|
|
} else if (client->buddy)
|
2006-05-22 21:12:30 +00:00
|
|
|
resources = client->buddy->resources;
|
|
|
|
while (resources) {
|
|
|
|
if (resources->cap->jingle) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
resources = resources->next;
|
|
|
|
}
|
|
|
|
if (resources)
|
|
|
|
snprintf(idroster, sizeof(idroster), "%s/%s", from, resources->resource);
|
|
|
|
else {
|
|
|
|
ast_log(LOG_ERROR, "no jingle capable clients to talk to.\n");
|
2011-11-23 17:16:33 +00:00
|
|
|
if (buddy) {
|
|
|
|
ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
|
|
|
|
}
|
2006-05-22 21:12:30 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2011-11-23 17:16:33 +00:00
|
|
|
if (buddy) {
|
|
|
|
ASTOBJ_UNREF(buddy, ast_aji_buddy_destroy);
|
|
|
|
}
|
2006-05-22 21:12:30 +00:00
|
|
|
}
|
|
|
|
if (!(tmp = ast_calloc(1, sizeof(*tmp)))) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2007-04-03 22:33:03 +00:00
|
|
|
|
2011-02-03 16:22:10 +00:00
|
|
|
tmp->cap = ast_format_cap_alloc_nolock();
|
|
|
|
tmp->jointcap = ast_format_cap_alloc_nolock();
|
|
|
|
tmp->peercap = ast_format_cap_alloc_nolock();
|
|
|
|
if (!tmp->cap || !tmp->jointcap || !tmp->peercap) {
|
|
|
|
tmp->cap = ast_format_cap_destroy(tmp->cap);
|
|
|
|
tmp->jointcap = ast_format_cap_destroy(tmp->jointcap);
|
|
|
|
tmp->peercap = ast_format_cap_destroy(tmp->peercap);
|
|
|
|
ast_free(tmp);
|
|
|
|
return NULL;
|
|
|
|
}
|
2007-04-03 22:33:03 +00:00
|
|
|
memcpy(&tmp->prefs, &client->prefs, sizeof(tmp->prefs));
|
|
|
|
|
2006-05-22 21:12:30 +00:00
|
|
|
if (sid) {
|
|
|
|
ast_copy_string(tmp->sid, sid, sizeof(tmp->sid));
|
2007-10-16 10:29:33 +00:00
|
|
|
ast_copy_string(tmp->them, from, sizeof(tmp->them));
|
2006-05-22 21:12:30 +00:00
|
|
|
} else {
|
|
|
|
snprintf(tmp->sid, sizeof(tmp->sid), "%08lx%08lx", ast_random(), ast_random());
|
2007-10-16 10:29:33 +00:00
|
|
|
ast_copy_string(tmp->them, idroster, sizeof(tmp->them));
|
2006-05-22 21:12:30 +00:00
|
|
|
tmp->initiator = 1;
|
|
|
|
}
|
2010-07-08 23:46:20 +00:00
|
|
|
ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
|
2010-07-08 22:08:07 +00:00
|
|
|
tmp->rtp = ast_rtp_instance_new("asterisk", sched, &bindaddr_tmp, NULL);
|
2006-05-22 21:12:30 +00:00
|
|
|
tmp->parent = client;
|
|
|
|
if (!tmp->rtp) {
|
|
|
|
ast_log(LOG_WARNING, "Out of RTP sessions?\n");
|
2007-06-03 06:10:27 +00:00
|
|
|
ast_free(tmp);
|
2006-05-22 21:12:30 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
ast_copy_string(tmp->exten, "s", sizeof(tmp->exten));
|
|
|
|
ast_mutex_init(&tmp->lock);
|
|
|
|
ast_mutex_lock(&jinglelock);
|
|
|
|
tmp->next = client->p;
|
|
|
|
client->p = tmp;
|
|
|
|
ast_mutex_unlock(&jinglelock);
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! \brief Start new jingle channel */
|
2009-06-26 15:28:53 +00:00
|
|
|
static struct ast_channel *jingle_new(struct jingle *client, struct jingle_pvt *i, int state, const char *title, const char *linkedid)
|
2006-05-22 21:12:30 +00:00
|
|
|
{
|
|
|
|
struct ast_channel *tmp;
|
2011-02-03 16:22:10 +00:00
|
|
|
struct ast_format_cap *what; /* SHALLOW COPY DO NOT DESTROY */
|
|
|
|
struct ast_format tmpfmt;
|
2006-11-08 07:21:45 +00:00
|
|
|
const char *str;
|
2006-05-22 21:12:30 +00:00
|
|
|
|
2006-11-07 21:47:49 +00:00
|
|
|
if (title)
|
|
|
|
str = title;
|
|
|
|
else
|
2007-10-16 10:29:33 +00:00
|
|
|
str = i->them;
|
2009-06-26 15:28:53 +00:00
|
|
|
tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, "", "", "", linkedid, 0, "Jingle/%s-%04lx", str, ast_random() & 0xffff);
|
2006-05-22 21:12:30 +00:00
|
|
|
if (!tmp) {
|
|
|
|
ast_log(LOG_WARNING, "Unable to allocate Jingle channel structure!\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
2012-02-20 23:43:27 +00:00
|
|
|
ast_channel_tech_set(tmp, &jingle_tech);
|
2006-05-22 21:12:30 +00:00
|
|
|
|
|
|
|
/* Select our native format based on codec preference until we receive
|
|
|
|
something from another device to the contrary. */
|
2011-02-03 16:22:10 +00:00
|
|
|
if (!ast_format_cap_is_empty(i->jointcap))
|
|
|
|
what = i->jointcap;
|
|
|
|
else if (!(ast_format_cap_is_empty(i->cap)))
|
|
|
|
what = i->cap;
|
2006-05-22 21:12:30 +00:00
|
|
|
else
|
|
|
|
what = global_capability;
|
2007-04-03 22:33:03 +00:00
|
|
|
|
|
|
|
/* Set Frame packetization */
|
|
|
|
if (i->rtp)
|
2009-04-02 17:20:52 +00:00
|
|
|
ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(i->rtp), i->rtp, &i->prefs);
|
2007-04-03 22:33:03 +00:00
|
|
|
|
2011-02-03 16:22:10 +00:00
|
|
|
ast_codec_choose(&i->prefs, what, 1, &tmpfmt);
|
2012-02-20 23:43:27 +00:00
|
|
|
ast_format_cap_add(ast_channel_nativeformats(tmp), &tmpfmt);
|
2011-02-03 16:22:10 +00:00
|
|
|
|
|
|
|
ast_format_cap_iter_start(i->jointcap);
|
|
|
|
while (!(ast_format_cap_iter_next(i->jointcap, &tmpfmt))) {
|
|
|
|
if (AST_FORMAT_GET_TYPE(tmpfmt.id) == AST_FORMAT_TYPE_VIDEO) {
|
2012-02-20 23:43:27 +00:00
|
|
|
ast_format_cap_add(ast_channel_nativeformats(tmp), &tmpfmt);
|
2011-02-03 16:22:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ast_format_cap_iter_end(i->jointcap);
|
2006-05-22 21:12:30 +00:00
|
|
|
|
|
|
|
if (i->rtp) {
|
2009-04-02 17:20:52 +00:00
|
|
|
ast_channel_set_fd(tmp, 0, ast_rtp_instance_fd(i->rtp, 0));
|
|
|
|
ast_channel_set_fd(tmp, 1, ast_rtp_instance_fd(i->rtp, 1));
|
2006-05-22 21:12:30 +00:00
|
|
|
}
|
|
|
|
if (i->vrtp) {
|
2009-04-02 17:20:52 +00:00
|
|
|
ast_channel_set_fd(tmp, 2, ast_rtp_instance_fd(i->vrtp, 0));
|
|
|
|
ast_channel_set_fd(tmp, 3, ast_rtp_instance_fd(i->vrtp, 1));
|
2006-05-22 21:12:30 +00:00
|
|
|
}
|
|
|
|
if (state == AST_STATE_RING)
|
2012-02-20 23:43:27 +00:00
|
|
|
ast_channel_rings_set(tmp, 1);
|
|
|
|
ast_channel_adsicpe_set(tmp, AST_ADSI_UNAVAILABLE);
|
2011-02-03 16:22:10 +00:00
|
|
|
|
|
|
|
|
2012-02-20 23:43:27 +00:00
|
|
|
ast_best_codec(ast_channel_nativeformats(tmp), &tmpfmt);
|
2012-02-24 00:32:20 +00:00
|
|
|
ast_format_copy(ast_channel_writeformat(tmp), &tmpfmt);
|
|
|
|
ast_format_copy(ast_channel_rawwriteformat(tmp), &tmpfmt);
|
|
|
|
ast_format_copy(ast_channel_readformat(tmp), &tmpfmt);
|
|
|
|
ast_format_copy(ast_channel_rawreadformat(tmp), &tmpfmt);
|
2012-02-20 23:43:27 +00:00
|
|
|
ast_channel_tech_pvt_set(tmp, i);
|
2006-05-22 21:12:30 +00:00
|
|
|
|
2012-03-01 22:09:18 +00:00
|
|
|
ast_channel_callgroup_set(tmp, client->callgroup);
|
|
|
|
ast_channel_pickupgroup_set(tmp, client->pickupgroup);
|
2012-02-29 16:52:47 +00:00
|
|
|
ast_channel_caller(tmp)->id.name.presentation = client->callingpres;
|
|
|
|
ast_channel_caller(tmp)->id.number.presentation = client->callingpres;
|
2006-05-22 21:12:30 +00:00
|
|
|
if (!ast_strlen_zero(client->accountcode))
|
2012-01-24 20:12:09 +00:00
|
|
|
ast_channel_accountcode_set(tmp, client->accountcode);
|
2006-05-22 21:12:30 +00:00
|
|
|
if (client->amaflags)
|
2012-02-20 23:43:27 +00:00
|
|
|
ast_channel_amaflags_set(tmp, client->amaflags);
|
2006-05-22 21:12:30 +00:00
|
|
|
if (!ast_strlen_zero(client->language))
|
2012-01-24 20:12:09 +00:00
|
|
|
ast_channel_language_set(tmp, client->language);
|
2006-05-22 21:12:30 +00:00
|
|
|
if (!ast_strlen_zero(client->musicclass))
|
2012-01-24 20:12:09 +00:00
|
|
|
ast_channel_musicclass_set(tmp, client->musicclass);
|
2006-05-22 21:12:30 +00:00
|
|
|
i->owner = tmp;
|
2012-02-13 17:27:06 +00:00
|
|
|
ast_channel_context_set(tmp, client->context);
|
|
|
|
ast_channel_exten_set(tmp, i->exten);
|
2006-11-07 21:47:49 +00:00
|
|
|
/* Don't use ast_set_callerid() here because it will
|
|
|
|
* generate an unnecessary NewCallerID event */
|
2010-07-14 16:58:03 +00:00
|
|
|
if (!ast_strlen_zero(i->cid_num)) {
|
2012-02-29 16:52:47 +00:00
|
|
|
ast_channel_caller(tmp)->ani.number.valid = 1;
|
|
|
|
ast_channel_caller(tmp)->ani.number.str = ast_strdup(i->cid_num);
|
2010-07-14 16:58:03 +00:00
|
|
|
}
|
2010-07-14 15:48:36 +00:00
|
|
|
if (!ast_strlen_zero(i->exten) && strcmp(i->exten, "s")) {
|
2012-02-29 16:52:47 +00:00
|
|
|
ast_channel_dialed(tmp)->number.str = ast_strdup(i->exten);
|
2010-07-14 15:48:36 +00:00
|
|
|
}
|
2012-02-20 23:43:27 +00:00
|
|
|
ast_channel_priority_set(tmp, 1);
|
2006-08-16 03:43:47 +00:00
|
|
|
if (i->rtp)
|
|
|
|
ast_jb_configure(tmp, &global_jbconf);
|
2006-05-22 21:12:30 +00:00
|
|
|
if (state != AST_STATE_DOWN && ast_pbx_start(tmp)) {
|
2012-01-09 22:15:50 +00:00
|
|
|
ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
|
2012-02-20 23:43:27 +00:00
|
|
|
ast_channel_hangupcause_set(tmp, AST_CAUSE_SWITCH_CONGESTION);
|
2006-05-22 21:12:30 +00:00
|
|
|
ast_hangup(tmp);
|
2006-06-23 16:49:12 +00:00
|
|
|
tmp = NULL;
|
2006-05-22 21:12:30 +00:00
|
|
|
}
|
2006-06-01 16:47:28 +00:00
|
|
|
|
2006-05-22 21:12:30 +00:00
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int jingle_action(struct jingle *client, struct jingle_pvt *p, const char *action)
|
|
|
|
{
|
2007-09-25 09:07:30 +00:00
|
|
|
iks *iq, *jingle = NULL;
|
2006-05-22 21:12:30 +00:00
|
|
|
int res = -1;
|
|
|
|
|
2007-09-25 09:07:30 +00:00
|
|
|
iq = iks_new("iq");
|
|
|
|
jingle = iks_new("jingle");
|
|
|
|
|
|
|
|
if (iq) {
|
|
|
|
iks_insert_attrib(iq, "type", "set");
|
|
|
|
iks_insert_attrib(iq, "from", client->connection->jid->full);
|
2007-10-16 10:29:33 +00:00
|
|
|
iks_insert_attrib(iq, "to", p->them);
|
2007-09-25 09:07:30 +00:00
|
|
|
iks_insert_attrib(iq, "id", client->connection->mid);
|
2006-05-22 21:12:30 +00:00
|
|
|
ast_aji_increment_mid(client->connection->mid);
|
2007-09-25 09:07:30 +00:00
|
|
|
if (jingle) {
|
|
|
|
iks_insert_attrib(jingle, "action", action);
|
|
|
|
iks_insert_attrib(jingle, JINGLE_SID, p->sid);
|
2007-10-16 10:29:33 +00:00
|
|
|
iks_insert_attrib(jingle, "initiator", p->initiator ? client->connection->jid->full : p->them);
|
2007-09-25 09:07:30 +00:00
|
|
|
iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
|
|
|
|
|
|
|
|
iks_insert_node(iq, jingle);
|
|
|
|
|
2007-11-06 18:44:19 +00:00
|
|
|
ast_aji_send(client->connection, iq);
|
2006-05-22 21:12:30 +00:00
|
|
|
res = 0;
|
|
|
|
}
|
|
|
|
}
|
2008-02-29 14:15:03 +00:00
|
|
|
|
|
|
|
iks_delete(jingle);
|
|
|
|
iks_delete(iq);
|
|
|
|
|
2006-05-22 21:12:30 +00:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void jingle_free_candidates(struct jingle_candidate *candidate)
|
|
|
|
{
|
|
|
|
struct jingle_candidate *last;
|
|
|
|
while (candidate) {
|
|
|
|
last = candidate;
|
|
|
|
candidate = candidate->next;
|
2007-06-03 06:10:27 +00:00
|
|
|
ast_free(last);
|
2006-05-22 21:12:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void jingle_free_pvt(struct jingle *client, struct jingle_pvt *p)
|
|
|
|
{
|
|
|
|
struct jingle_pvt *cur, *prev = NULL;
|
|
|
|
cur = client->p;
|
|
|
|
while (cur) {
|
|
|
|
if (cur == p) {
|
|
|
|
if (prev)
|
|
|
|
prev->next = p->next;
|
|
|
|
else
|
|
|
|
client->p = p->next;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
prev = cur;
|
|
|
|
cur = cur->next;
|
|
|
|
}
|
|
|
|
if (p->ringrule)
|
|
|
|
iks_filter_remove_rule(p->parent->connection->f, p->ringrule);
|
|
|
|
if (p->owner)
|
|
|
|
ast_log(LOG_WARNING, "Uh oh, there's an owner, this is going to be messy.\n");
|
|
|
|
if (p->rtp)
|
2009-04-02 17:20:52 +00:00
|
|
|
ast_rtp_instance_destroy(p->rtp);
|
2006-05-22 21:12:30 +00:00
|
|
|
if (p->vrtp)
|
2009-04-02 17:20:52 +00:00
|
|
|
ast_rtp_instance_destroy(p->vrtp);
|
2006-05-22 21:12:30 +00:00
|
|
|
jingle_free_candidates(p->theircandidates);
|
2011-02-03 16:22:10 +00:00
|
|
|
p->cap = ast_format_cap_destroy(p->cap);
|
|
|
|
p->jointcap = ast_format_cap_destroy(p->jointcap);
|
|
|
|
p->peercap = ast_format_cap_destroy(p->peercap);
|
|
|
|
|
2007-06-03 06:10:27 +00:00
|
|
|
ast_free(p);
|
2006-05-22 21:12:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int jingle_newcall(struct jingle *client, ikspak *pak)
|
|
|
|
{
|
|
|
|
struct jingle_pvt *p, *tmp = client->p;
|
|
|
|
struct ast_channel *chan;
|
|
|
|
int res;
|
2008-05-28 14:10:48 +00:00
|
|
|
iks *codec, *content, *description;
|
2008-06-02 14:35:24 +00:00
|
|
|
char *from = NULL;
|
2006-05-22 21:12:30 +00:00
|
|
|
|
|
|
|
/* Make sure our new call doesn't exist yet */
|
2008-06-02 14:35:24 +00:00
|
|
|
from = iks_find_attrib(pak->x,"to");
|
|
|
|
if(!from)
|
|
|
|
from = client->connection->jid->full;
|
|
|
|
|
2006-05-22 21:12:30 +00:00
|
|
|
while (tmp) {
|
2007-09-19 13:55:08 +00:00
|
|
|
if (iks_find_with_attrib(pak->x, JINGLE_NODE, JINGLE_SID, tmp->sid)) {
|
2006-05-22 21:12:30 +00:00
|
|
|
ast_log(LOG_NOTICE, "Ignoring duplicate call setup on SID %s\n", tmp->sid);
|
2006-08-02 01:00:24 +00:00
|
|
|
jingle_response(client, pak, "out-of-order", NULL);
|
2006-05-22 21:12:30 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
tmp = tmp->next;
|
|
|
|
}
|
|
|
|
|
2011-11-23 17:16:33 +00:00
|
|
|
if (!strcasecmp(client->name, "guest")){
|
|
|
|
/* the guest account is not tied to any configured XMPP client,
|
|
|
|
let's set it now */
|
|
|
|
if (client->connection) {
|
|
|
|
ASTOBJ_UNREF(client->connection, ast_aji_client_destroy);
|
|
|
|
}
|
|
|
|
client->connection = ast_aji_get_client(from);
|
|
|
|
if (!client->connection) {
|
|
|
|
ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", from);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
2008-06-02 14:35:24 +00:00
|
|
|
|
2007-09-19 13:55:08 +00:00
|
|
|
p = jingle_alloc(client, pak->from->partial, iks_find_attrib(pak->query, JINGLE_SID));
|
2006-05-22 21:12:30 +00:00
|
|
|
if (!p) {
|
|
|
|
ast_log(LOG_WARNING, "Unable to allocate jingle structure!\n");
|
|
|
|
return -1;
|
|
|
|
}
|
2009-06-26 15:28:53 +00:00
|
|
|
chan = jingle_new(client, p, AST_STATE_DOWN, pak->from->user, NULL);
|
2008-05-28 08:39:10 +00:00
|
|
|
if (!chan) {
|
2006-05-22 21:12:30 +00:00
|
|
|
jingle_free_pvt(client, p);
|
2008-05-28 08:39:10 +00:00
|
|
|
return -1;
|
2006-05-22 21:12:30 +00:00
|
|
|
}
|
2008-05-28 08:39:10 +00:00
|
|
|
ast_mutex_lock(&p->lock);
|
|
|
|
ast_copy_string(p->them, pak->from->full, sizeof(p->them));
|
|
|
|
if (iks_find_attrib(pak->query, JINGLE_SID)) {
|
|
|
|
ast_copy_string(p->sid, iks_find_attrib(pak->query, JINGLE_SID),
|
|
|
|
sizeof(p->sid));
|
|
|
|
}
|
|
|
|
|
2008-05-28 14:10:48 +00:00
|
|
|
/* content points to the first <content/> tag */
|
|
|
|
content = iks_child(iks_child(pak->x));
|
|
|
|
while (content) {
|
|
|
|
description = iks_find_with_attrib(content, "description", "xmlns", JINGLE_AUDIO_RTP_NS);
|
|
|
|
if (description) {
|
|
|
|
/* audio content found */
|
|
|
|
codec = iks_child(iks_child(content));
|
|
|
|
ast_copy_string(p->audio_content_name, iks_find_attrib(content, "name"), sizeof(p->audio_content_name));
|
|
|
|
|
|
|
|
while (codec) {
|
2009-04-02 17:20:52 +00:00
|
|
|
ast_rtp_codecs_payloads_set_m_type(ast_rtp_instance_get_codecs(p->rtp), p->rtp, atoi(iks_find_attrib(codec, "id")));
|
|
|
|
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);
|
2008-05-28 14:10:48 +00:00
|
|
|
codec = iks_next(codec);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
description = NULL;
|
|
|
|
codec = NULL;
|
|
|
|
|
|
|
|
description = iks_find_with_attrib(content, "description", "xmlns", JINGLE_VIDEO_RTP_NS);
|
|
|
|
if (description) {
|
|
|
|
/* video content found */
|
|
|
|
codec = iks_child(iks_child(content));
|
|
|
|
ast_copy_string(p->video_content_name, iks_find_attrib(content, "name"), sizeof(p->video_content_name));
|
|
|
|
|
|
|
|
while (codec) {
|
2009-04-02 17:20:52 +00:00
|
|
|
ast_rtp_codecs_payloads_set_m_type(ast_rtp_instance_get_codecs(p->rtp), p->rtp, atoi(iks_find_attrib(codec, "id")));
|
|
|
|
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);
|
2008-05-28 14:10:48 +00:00
|
|
|
codec = iks_next(codec);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
content = iks_next(content);
|
2008-05-28 08:39:10 +00:00
|
|
|
}
|
2008-05-28 14:10:48 +00:00
|
|
|
|
2008-05-28 08:39:10 +00:00
|
|
|
ast_mutex_unlock(&p->lock);
|
|
|
|
ast_setstate(chan, AST_STATE_RING);
|
|
|
|
res = ast_pbx_start(chan);
|
|
|
|
|
|
|
|
switch (res) {
|
|
|
|
case AST_PBX_FAILED:
|
|
|
|
ast_log(LOG_WARNING, "Failed to start PBX :(\n");
|
|
|
|
jingle_response(client, pak, "service-unavailable", NULL);
|
|
|
|
break;
|
|
|
|
case AST_PBX_CALL_LIMIT:
|
|
|
|
ast_log(LOG_WARNING, "Failed to start PBX (call limit reached) \n");
|
|
|
|
jingle_response(client, pak, "service-unavailable", NULL);
|
|
|
|
break;
|
|
|
|
case AST_PBX_SUCCESS:
|
|
|
|
jingle_response(client, pak, NULL, NULL);
|
|
|
|
jingle_create_candidates(client, p,
|
|
|
|
iks_find_attrib(pak->query, JINGLE_SID),
|
|
|
|
iks_find_attrib(pak->x, "from"));
|
|
|
|
/* nothing to do */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2006-05-22 21:12:30 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int jingle_update_stun(struct jingle *client, struct jingle_pvt *p)
|
|
|
|
{
|
|
|
|
struct jingle_candidate *tmp;
|
|
|
|
struct hostent *hp;
|
|
|
|
struct ast_hostent ahp;
|
|
|
|
struct sockaddr_in sin;
|
2010-07-08 22:08:07 +00:00
|
|
|
struct ast_sockaddr sin_tmp;
|
2006-05-22 21:12:30 +00:00
|
|
|
|
|
|
|
if (time(NULL) == p->laststun)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
tmp = p->theircandidates;
|
|
|
|
p->laststun = time(NULL);
|
|
|
|
while (tmp) {
|
|
|
|
char username[256];
|
|
|
|
hp = ast_gethostbyname(tmp->ip, &ahp);
|
|
|
|
sin.sin_family = AF_INET;
|
|
|
|
memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
|
|
|
|
sin.sin_port = htons(tmp->port);
|
2007-09-25 09:07:30 +00:00
|
|
|
snprintf(username, sizeof(username), "%s:%s", tmp->ufrag, p->ourcandidates->ufrag);
|
2006-05-22 21:12:30 +00:00
|
|
|
|
2010-07-08 23:46:20 +00:00
|
|
|
ast_sockaddr_from_sin(&sin_tmp, &sin);
|
2010-07-08 22:08:07 +00:00
|
|
|
ast_rtp_instance_stun_request(p->rtp, &sin_tmp, username);
|
2006-05-22 21:12:30 +00:00
|
|
|
tmp = tmp->next;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int jingle_add_candidate(struct jingle *client, ikspak *pak)
|
|
|
|
{
|
|
|
|
struct jingle_pvt *p = NULL, *tmp = NULL;
|
|
|
|
struct aji_client *c = client->connection;
|
|
|
|
struct jingle_candidate *newcandidate = NULL;
|
2006-09-18 16:36:14 +00:00
|
|
|
iks *traversenodes = NULL, *receipt = NULL;
|
2007-10-31 21:18:52 +00:00
|
|
|
|
2006-06-18 20:51:14 +00:00
|
|
|
for (tmp = client->p; tmp; tmp = tmp->next) {
|
2007-09-19 13:55:08 +00:00
|
|
|
if (iks_find_with_attrib(pak->x, JINGLE_NODE, JINGLE_SID, tmp->sid)) {
|
2006-05-22 21:12:30 +00:00
|
|
|
p = tmp;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-06-18 20:51:14 +00:00
|
|
|
if (!p)
|
2006-05-22 21:12:30 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
traversenodes = pak->query;
|
|
|
|
while(traversenodes) {
|
2007-10-16 09:47:22 +00:00
|
|
|
if(!strcasecmp(iks_name(traversenodes), "jingle")) {
|
2006-05-22 21:12:30 +00:00
|
|
|
traversenodes = iks_child(traversenodes);
|
|
|
|
continue;
|
|
|
|
}
|
2007-10-16 09:47:22 +00:00
|
|
|
if(!strcasecmp(iks_name(traversenodes), "content")) {
|
|
|
|
traversenodes = iks_child(traversenodes);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if(!strcasecmp(iks_name(traversenodes), "transport")) {
|
|
|
|
traversenodes = iks_child(traversenodes);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2006-05-22 21:12:30 +00:00
|
|
|
if(!strcasecmp(iks_name(traversenodes), "candidate")) {
|
2006-06-18 20:51:14 +00:00
|
|
|
newcandidate = ast_calloc(1, sizeof(*newcandidate));
|
2006-05-22 21:12:30 +00:00
|
|
|
if (!newcandidate)
|
|
|
|
return 0;
|
2007-10-16 09:47:22 +00:00
|
|
|
ast_copy_string(newcandidate->ip, iks_find_attrib(traversenodes, "ip"), sizeof(newcandidate->ip));
|
2006-05-22 21:12:30 +00:00
|
|
|
newcandidate->port = atoi(iks_find_attrib(traversenodes, "port"));
|
2007-10-16 09:47:22 +00:00
|
|
|
ast_copy_string(newcandidate->password, iks_find_attrib(traversenodes, "pwd"), sizeof(newcandidate->password));
|
2006-05-22 21:12:30 +00:00
|
|
|
if (!strcasecmp(iks_find_attrib(traversenodes, "protocol"), "udp"))
|
|
|
|
newcandidate->protocol = AJI_PROTOCOL_UDP;
|
2007-10-16 09:47:22 +00:00
|
|
|
else if (!strcasecmp(iks_find_attrib(traversenodes, "protocol"), "ssltcp"))
|
2006-05-22 21:12:30 +00:00
|
|
|
newcandidate->protocol = AJI_PROTOCOL_SSLTCP;
|
2007-10-16 09:47:22 +00:00
|
|
|
|
2007-09-25 09:07:30 +00:00
|
|
|
if (!strcasecmp(iks_find_attrib(traversenodes, "type"), "host"))
|
|
|
|
newcandidate->type = AJI_CONNECT_HOST;
|
2007-10-16 09:47:22 +00:00
|
|
|
else if (!strcasecmp(iks_find_attrib(traversenodes, "type"), "prflx"))
|
2007-09-25 09:07:30 +00:00
|
|
|
newcandidate->type = AJI_CONNECT_PRFLX;
|
2007-10-16 09:47:22 +00:00
|
|
|
else if (!strcasecmp(iks_find_attrib(traversenodes, "type"), "relay"))
|
2006-05-22 21:12:30 +00:00
|
|
|
newcandidate->type = AJI_CONNECT_RELAY;
|
2007-10-16 09:47:22 +00:00
|
|
|
else if (!strcasecmp(iks_find_attrib(traversenodes, "type"), "srflx"))
|
2007-09-25 09:07:30 +00:00
|
|
|
newcandidate->type = AJI_CONNECT_SRFLX;
|
|
|
|
|
|
|
|
newcandidate->network = atoi(iks_find_attrib(traversenodes, "network"));
|
2006-05-22 21:12:30 +00:00
|
|
|
newcandidate->generation = atoi(iks_find_attrib(traversenodes, "generation"));
|
|
|
|
newcandidate->next = NULL;
|
|
|
|
|
|
|
|
newcandidate->next = p->theircandidates;
|
|
|
|
p->theircandidates = newcandidate;
|
|
|
|
p->laststun = 0;
|
|
|
|
jingle_update_stun(p->parent, p);
|
|
|
|
newcandidate = NULL;
|
|
|
|
}
|
|
|
|
traversenodes = iks_next(traversenodes);
|
|
|
|
}
|
|
|
|
|
|
|
|
receipt = iks_new("iq");
|
|
|
|
iks_insert_attrib(receipt, "type", "result");
|
|
|
|
iks_insert_attrib(receipt, "from", c->jid->full);
|
|
|
|
iks_insert_attrib(receipt, "to", iks_find_attrib(pak->x, "from"));
|
|
|
|
iks_insert_attrib(receipt, "id", iks_find_attrib(pak->x, "id"));
|
2007-11-06 18:44:19 +00:00
|
|
|
ast_aji_send(c, receipt);
|
2008-02-29 14:15:03 +00:00
|
|
|
|
2006-05-22 21:12:30 +00:00
|
|
|
iks_delete(receipt);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct ast_frame *jingle_rtp_read(struct ast_channel *ast, struct jingle_pvt *p)
|
|
|
|
{
|
|
|
|
struct ast_frame *f;
|
2006-08-07 21:15:28 +00:00
|
|
|
|
|
|
|
if (!p->rtp)
|
2006-05-22 21:12:30 +00:00
|
|
|
return &ast_null_frame;
|
2009-04-02 17:20:52 +00:00
|
|
|
f = ast_rtp_instance_read(p->rtp, 0);
|
2006-05-22 21:12:30 +00:00
|
|
|
jingle_update_stun(p->parent, p);
|
|
|
|
if (p->owner) {
|
|
|
|
/* We already hold the channel lock */
|
|
|
|
if (f->frametype == AST_FRAME_VOICE) {
|
2012-02-20 23:43:27 +00:00
|
|
|
if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(p->owner), &f->subclass.format))) {
|
2011-02-03 16:22:10 +00:00
|
|
|
ast_debug(1, "Oooh, format changed to %s\n", ast_getformatname(&f->subclass.format));
|
2012-02-20 23:43:27 +00:00
|
|
|
ast_format_cap_remove_bytype(ast_channel_nativeformats(p->owner), AST_FORMAT_TYPE_AUDIO);
|
|
|
|
ast_format_cap_add(ast_channel_nativeformats(p->owner), &f->subclass.format);
|
2012-02-24 00:32:20 +00:00
|
|
|
ast_set_read_format(p->owner, ast_channel_readformat(p->owner));
|
|
|
|
ast_set_write_format(p->owner, ast_channel_writeformat(p->owner));
|
2006-05-22 21:12:30 +00:00
|
|
|
}
|
|
|
|
/* if ((ast_test_flag(p, SIP_DTMF) == SIP_DTMF_INBAND) && p->vad) {
|
|
|
|
f = ast_dsp_process(p->owner, p->vad, f);
|
2007-06-14 19:39:12 +00:00
|
|
|
if (f && (f->frametype == AST_FRAME_DTMF))
|
2009-11-04 14:05:12 +00:00
|
|
|
ast_debug(1, "* Detected inband DTMF '%c'\n", f->subclass.codec);
|
2006-05-22 21:12:30 +00:00
|
|
|
} */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct ast_frame *jingle_read(struct ast_channel *ast)
|
|
|
|
{
|
|
|
|
struct ast_frame *fr;
|
2012-02-20 23:43:27 +00:00
|
|
|
struct jingle_pvt *p = ast_channel_tech_pvt(ast);
|
2006-05-22 21:12:30 +00:00
|
|
|
|
|
|
|
ast_mutex_lock(&p->lock);
|
|
|
|
fr = jingle_rtp_read(ast, p);
|
|
|
|
ast_mutex_unlock(&p->lock);
|
|
|
|
return fr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! \brief Send frame to media channel (rtp) */
|
|
|
|
static int jingle_write(struct ast_channel *ast, struct ast_frame *frame)
|
|
|
|
{
|
2012-02-20 23:43:27 +00:00
|
|
|
struct jingle_pvt *p = ast_channel_tech_pvt(ast);
|
2006-05-22 21:12:30 +00:00
|
|
|
int res = 0;
|
2009-11-04 14:05:12 +00:00
|
|
|
char buf[256];
|
2006-05-22 21:12:30 +00:00
|
|
|
|
|
|
|
switch (frame->frametype) {
|
|
|
|
case AST_FRAME_VOICE:
|
2012-02-20 23:43:27 +00:00
|
|
|
if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &frame->subclass.format))) {
|
2006-05-22 21:12:30 +00:00
|
|
|
ast_log(LOG_WARNING,
|
2009-11-04 14:05:12 +00:00
|
|
|
"Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n",
|
2011-02-03 16:22:10 +00:00
|
|
|
ast_getformatname(&frame->subclass.format),
|
2012-02-20 23:43:27 +00:00
|
|
|
ast_getformatname_multiple(buf, sizeof(buf), ast_channel_nativeformats(ast)),
|
2012-02-24 00:32:20 +00:00
|
|
|
ast_getformatname(ast_channel_readformat(ast)),
|
|
|
|
ast_getformatname(ast_channel_writeformat(ast)));
|
2006-05-22 21:12:30 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (p) {
|
|
|
|
ast_mutex_lock(&p->lock);
|
|
|
|
if (p->rtp) {
|
2009-04-02 17:20:52 +00:00
|
|
|
res = ast_rtp_instance_write(p->rtp, frame);
|
2006-05-22 21:12:30 +00:00
|
|
|
}
|
|
|
|
ast_mutex_unlock(&p->lock);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case AST_FRAME_VIDEO:
|
|
|
|
if (p) {
|
|
|
|
ast_mutex_lock(&p->lock);
|
|
|
|
if (p->vrtp) {
|
2009-04-02 17:20:52 +00:00
|
|
|
res = ast_rtp_instance_write(p->vrtp, frame);
|
2006-05-22 21:12:30 +00:00
|
|
|
}
|
|
|
|
ast_mutex_unlock(&p->lock);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case AST_FRAME_IMAGE:
|
|
|
|
return 0;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ast_log(LOG_WARNING, "Can't send %d type frames with Jingle write\n",
|
|
|
|
frame->frametype);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int jingle_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
|
|
|
|
{
|
2012-02-20 23:43:27 +00:00
|
|
|
struct jingle_pvt *p = ast_channel_tech_pvt(newchan);
|
2006-05-22 21:12:30 +00:00
|
|
|
ast_mutex_lock(&p->lock);
|
|
|
|
|
|
|
|
if ((p->owner != oldchan)) {
|
|
|
|
ast_mutex_unlock(&p->lock);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (p->owner == oldchan)
|
|
|
|
p->owner = newchan;
|
|
|
|
ast_mutex_unlock(&p->lock);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-05-23 16:25:37 +00:00
|
|
|
static int jingle_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
|
2006-05-22 21:12:30 +00:00
|
|
|
{
|
2006-07-19 20:44:39 +00:00
|
|
|
int res = 0;
|
2006-05-22 21:12:30 +00:00
|
|
|
|
2006-07-19 20:44:39 +00:00
|
|
|
switch (condition) {
|
|
|
|
case AST_CONTROL_HOLD:
|
|
|
|
ast_moh_start(ast, data, NULL);
|
|
|
|
break;
|
|
|
|
case AST_CONTROL_UNHOLD:
|
|
|
|
ast_moh_stop(ast);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ast_log(LOG_NOTICE, "Don't know how to indicate condition '%d'\n", condition);
|
2012-05-14 19:44:27 +00:00
|
|
|
/* fallthrough */
|
|
|
|
case AST_CONTROL_PVT_CAUSE_CODE:
|
2006-07-19 20:44:39 +00:00
|
|
|
res = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
2006-05-22 21:12:30 +00:00
|
|
|
}
|
|
|
|
|
2009-09-25 10:54:42 +00:00
|
|
|
static int jingle_sendtext(struct ast_channel *chan, const char *text)
|
|
|
|
{
|
|
|
|
int res = 0;
|
|
|
|
struct aji_client *client = NULL;
|
2012-02-20 23:43:27 +00:00
|
|
|
struct jingle_pvt *p = ast_channel_tech_pvt(chan);
|
2009-09-25 10:54:42 +00:00
|
|
|
|
|
|
|
|
|
|
|
if (!p->parent) {
|
|
|
|
ast_log(LOG_ERROR, "Parent channel not found\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (!p->parent->connection) {
|
|
|
|
ast_log(LOG_ERROR, "XMPP client not found\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
client = p->parent->connection;
|
|
|
|
res = ast_aji_send_chat(client, p->them, text);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
Merged revisions 51311 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r51311 | russell | 2007-01-19 11:49:38 -0600 (Fri, 19 Jan 2007) | 23 lines
Merge the changes from the /team/group/vldtmf_fixup branch.
The main bug being addressed here is a problem introduced when two SIP
channels using SIP INFO dtmf have their media directly bridged. So, when a
DTMF END frame comes into Asterisk from an incoming INFO message, Asterisk
would try to emulate a digit of some length by first sending a DTMF BEGIN
frame and sending a DTMF END later timed off of incoming audio. However,
since there was no audio coming in, the DTMF_END was never generated. This
caused DTMF based features to no longer work.
To fix this, the core now knows when a channel doesn't care about DTMF BEGIN
frames (such as a SIP channel sending INFO dtmf). If this is the case, then
Asterisk will not emulate a digit of some length, and will instead just pass
through the single DTMF END event.
Channel drivers also now get passed the length of the digit to their digit_end
callback. This improves SIP INFO support even further by enabling us to put
the real digit duration in the INFO message instead of a hard coded 250ms.
Also, for an incoming INFO message, the duration is read from the frame and
passed into the core instead of just getting ignored.
(issue #8597, maybe others...)
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@51314 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-01-19 18:06:03 +00:00
|
|
|
static int jingle_digit(struct ast_channel *ast, char digit, unsigned int duration)
|
2006-05-22 21:12:30 +00:00
|
|
|
{
|
2012-02-20 23:43:27 +00:00
|
|
|
struct jingle_pvt *p = ast_channel_tech_pvt(ast);
|
2006-08-02 01:00:24 +00:00
|
|
|
struct jingle *client = p->parent;
|
|
|
|
iks *iq, *jingle, *dtmf;
|
|
|
|
char buffer[2] = {digit, '\0'};
|
|
|
|
iq = iks_new("iq");
|
|
|
|
jingle = iks_new("jingle");
|
|
|
|
dtmf = iks_new("dtmf");
|
|
|
|
if(!iq || !jingle || !dtmf) {
|
2008-02-29 14:15:03 +00:00
|
|
|
iks_delete(iq);
|
|
|
|
iks_delete(jingle);
|
|
|
|
iks_delete(dtmf);
|
2006-08-02 01:00:24 +00:00
|
|
|
ast_log(LOG_ERROR, "Did not send dtmf do to memory issue\n");
|
|
|
|
return -1;
|
|
|
|
}
|
2006-05-22 21:12:30 +00:00
|
|
|
|
2006-08-02 01:00:24 +00:00
|
|
|
iks_insert_attrib(iq, "type", "set");
|
2007-10-16 10:29:33 +00:00
|
|
|
iks_insert_attrib(iq, "to", p->them);
|
2006-08-02 01:00:24 +00:00
|
|
|
iks_insert_attrib(iq, "from", client->connection->jid->full);
|
|
|
|
iks_insert_attrib(iq, "id", client->connection->mid);
|
|
|
|
ast_aji_increment_mid(client->connection->mid);
|
2007-09-13 15:05:16 +00:00
|
|
|
iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
|
2007-09-13 14:00:56 +00:00
|
|
|
iks_insert_attrib(jingle, "action", "session-info");
|
2007-10-16 10:29:33 +00:00
|
|
|
iks_insert_attrib(jingle, "initiator", p->initiator ? client->connection->jid->full : p->them);
|
2006-08-02 01:00:24 +00:00
|
|
|
iks_insert_attrib(jingle, "sid", p->sid);
|
2007-09-13 15:05:16 +00:00
|
|
|
iks_insert_attrib(dtmf, "xmlns", JINGLE_DTMF_NS);
|
2006-08-02 01:00:24 +00:00
|
|
|
iks_insert_attrib(dtmf, "code", buffer);
|
|
|
|
iks_insert_node(iq, jingle);
|
|
|
|
iks_insert_node(jingle, dtmf);
|
|
|
|
|
|
|
|
ast_mutex_lock(&p->lock);
|
2012-02-29 16:52:47 +00:00
|
|
|
if (ast_channel_dtmff(ast)->frametype == AST_FRAME_DTMF_BEGIN || duration == 0) {
|
2006-08-02 01:00:24 +00:00
|
|
|
iks_insert_attrib(dtmf, "action", "button-down");
|
2012-02-29 16:52:47 +00:00
|
|
|
} else if (ast_channel_dtmff(ast)->frametype == AST_FRAME_DTMF_END || duration != 0) {
|
2006-08-02 01:00:24 +00:00
|
|
|
iks_insert_attrib(dtmf, "action", "button-up");
|
|
|
|
}
|
2007-11-06 18:44:19 +00:00
|
|
|
ast_aji_send(client->connection, iq);
|
2008-02-29 14:15:03 +00:00
|
|
|
|
2006-08-02 01:00:24 +00:00
|
|
|
iks_delete(iq);
|
|
|
|
iks_delete(jingle);
|
|
|
|
iks_delete(dtmf);
|
|
|
|
ast_mutex_unlock(&p->lock);
|
|
|
|
return 0;
|
2006-05-22 21:12:30 +00:00
|
|
|
}
|
|
|
|
|
Merged revisions 51311 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r51311 | russell | 2007-01-19 11:49:38 -0600 (Fri, 19 Jan 2007) | 23 lines
Merge the changes from the /team/group/vldtmf_fixup branch.
The main bug being addressed here is a problem introduced when two SIP
channels using SIP INFO dtmf have their media directly bridged. So, when a
DTMF END frame comes into Asterisk from an incoming INFO message, Asterisk
would try to emulate a digit of some length by first sending a DTMF BEGIN
frame and sending a DTMF END later timed off of incoming audio. However,
since there was no audio coming in, the DTMF_END was never generated. This
caused DTMF based features to no longer work.
To fix this, the core now knows when a channel doesn't care about DTMF BEGIN
frames (such as a SIP channel sending INFO dtmf). If this is the case, then
Asterisk will not emulate a digit of some length, and will instead just pass
through the single DTMF END event.
Channel drivers also now get passed the length of the digit to their digit_end
callback. This improves SIP INFO support even further by enabling us to put
the real digit duration in the INFO message instead of a hard coded 250ms.
Also, for an incoming INFO message, the duration is read from the frame and
passed into the core instead of just getting ignored.
(issue #8597, maybe others...)
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@51314 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-01-19 18:06:03 +00:00
|
|
|
static int jingle_digit_begin(struct ast_channel *chan, char digit)
|
|
|
|
{
|
|
|
|
return jingle_digit(chan, digit, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int jingle_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
|
|
|
|
{
|
|
|
|
return jingle_digit(ast, digit, duration);
|
|
|
|
}
|
|
|
|
|
2006-05-22 21:12:30 +00:00
|
|
|
static int jingle_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
|
|
|
|
{
|
|
|
|
ast_log(LOG_NOTICE, "XXX Implement jingle sendhtml XXX\n");
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
static int jingle_transmit_invite(struct jingle_pvt *p)
|
|
|
|
{
|
2007-09-19 12:23:56 +00:00
|
|
|
struct jingle *aux = NULL;
|
2006-08-08 17:07:41 +00:00
|
|
|
struct aji_client *client = NULL;
|
2007-09-19 12:23:56 +00:00
|
|
|
iks *iq, *jingle, *content, *description, *transport;
|
2006-05-22 21:12:30 +00:00
|
|
|
iks *payload_eg711u, *payload_pcmu;
|
|
|
|
|
2007-09-19 12:23:56 +00:00
|
|
|
aux = p->parent;
|
|
|
|
client = aux->connection;
|
2006-05-22 21:12:30 +00:00
|
|
|
iq = iks_new("iq");
|
2007-09-19 12:23:56 +00:00
|
|
|
jingle = iks_new(JINGLE_NODE);
|
|
|
|
content = iks_new("content");
|
|
|
|
description = iks_new("description");
|
|
|
|
transport = iks_new("transport");
|
|
|
|
payload_pcmu = iks_new("payload-type");
|
|
|
|
payload_eg711u = iks_new("payload-type");
|
|
|
|
|
2008-05-28 14:10:48 +00:00
|
|
|
ast_copy_string(p->audio_content_name, "asterisk-audio-content", sizeof(p->audio_content_name));
|
|
|
|
|
2006-05-22 21:12:30 +00:00
|
|
|
iks_insert_attrib(iq, "type", "set");
|
2007-10-16 10:29:33 +00:00
|
|
|
iks_insert_attrib(iq, "to", p->them);
|
2006-05-22 21:12:30 +00:00
|
|
|
iks_insert_attrib(iq, "from", client->jid->full);
|
|
|
|
iks_insert_attrib(iq, "id", client->mid);
|
|
|
|
ast_aji_increment_mid(client->mid);
|
2007-09-19 12:23:56 +00:00
|
|
|
iks_insert_attrib(jingle, "action", JINGLE_INITIATE);
|
|
|
|
iks_insert_attrib(jingle, JINGLE_SID, p->sid);
|
|
|
|
iks_insert_attrib(jingle, "initiator", client->jid->full);
|
|
|
|
iks_insert_attrib(jingle, "xmlns", JINGLE_NS);
|
2008-05-28 14:10:48 +00:00
|
|
|
|
|
|
|
/* For now, we only send one audio based content */
|
2007-09-19 12:23:56 +00:00
|
|
|
iks_insert_attrib(content, "creator", "initiator");
|
2008-05-28 14:10:48 +00:00
|
|
|
iks_insert_attrib(content, "name", p->audio_content_name);
|
2007-09-19 12:23:56 +00:00
|
|
|
iks_insert_attrib(content, "profile", "RTP/AVP");
|
|
|
|
iks_insert_attrib(description, "xmlns", JINGLE_AUDIO_RTP_NS);
|
|
|
|
iks_insert_attrib(transport, "xmlns", JINGLE_ICE_UDP_NS);
|
2006-05-22 21:12:30 +00:00
|
|
|
iks_insert_attrib(payload_pcmu, "id", "0");
|
|
|
|
iks_insert_attrib(payload_pcmu, "name", "PCMU");
|
|
|
|
iks_insert_attrib(payload_eg711u, "id", "100");
|
|
|
|
iks_insert_attrib(payload_eg711u, "name", "EG711U");
|
2007-09-19 12:23:56 +00:00
|
|
|
iks_insert_node(description, payload_pcmu);
|
|
|
|
iks_insert_node(description, payload_eg711u);
|
|
|
|
iks_insert_node(content, description);
|
|
|
|
iks_insert_node(content, transport);
|
|
|
|
iks_insert_node(jingle, content);
|
|
|
|
iks_insert_node(iq, jingle);
|
|
|
|
|
2007-11-06 18:44:19 +00:00
|
|
|
ast_aji_send(client, iq);
|
2007-09-19 12:23:56 +00:00
|
|
|
|
2006-05-22 21:12:30 +00:00
|
|
|
iks_delete(iq);
|
2007-09-19 12:23:56 +00:00
|
|
|
iks_delete(jingle);
|
|
|
|
iks_delete(content);
|
|
|
|
iks_delete(description);
|
|
|
|
iks_delete(transport);
|
2006-05-22 21:12:30 +00:00
|
|
|
iks_delete(payload_eg711u);
|
|
|
|
iks_delete(payload_pcmu);
|
|
|
|
return 0;
|
|
|
|
}
|
2006-08-07 21:15:28 +00:00
|
|
|
|
2006-05-23 16:43:58 +00:00
|
|
|
/* Not in use right now.
|
2006-05-22 21:12:30 +00:00
|
|
|
static int jingle_auto_congest(void *nothing)
|
|
|
|
{
|
|
|
|
struct jingle_pvt *p = nothing;
|
|
|
|
|
|
|
|
ast_mutex_lock(&p->lock);
|
|
|
|
if (p->owner) {
|
|
|
|
if (!ast_channel_trylock(p->owner)) {
|
|
|
|
ast_log(LOG_NOTICE, "Auto-congesting %s\n", p->owner->name);
|
|
|
|
ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
|
|
|
|
ast_channel_unlock(p->owner);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ast_mutex_unlock(&p->lock);
|
|
|
|
return 0;
|
|
|
|
}
|
2006-05-23 16:43:58 +00:00
|
|
|
*/
|
2006-05-22 21:12:30 +00:00
|
|
|
|
|
|
|
/*! \brief Initiate new call, part of PBX interface
|
|
|
|
* dest is the dial string */
|
2012-02-01 19:53:38 +00:00
|
|
|
static int jingle_call(struct ast_channel *ast, const char *dest, int timeout)
|
2006-05-22 21:12:30 +00:00
|
|
|
{
|
2012-02-20 23:43:27 +00:00
|
|
|
struct jingle_pvt *p = ast_channel_tech_pvt(ast);
|
2006-05-22 21:12:30 +00:00
|
|
|
|
2012-02-20 23:43:27 +00:00
|
|
|
if ((ast_channel_state(ast) != AST_STATE_DOWN) && (ast_channel_state(ast) != AST_STATE_RESERVED)) {
|
2012-01-09 22:15:50 +00:00
|
|
|
ast_log(LOG_WARNING, "jingle_call called on %s, neither down nor reserved\n", ast_channel_name(ast));
|
2006-05-22 21:12:30 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ast_setstate(ast, AST_STATE_RING);
|
2011-02-03 16:22:10 +00:00
|
|
|
ast_format_cap_copy(p->jointcap, p->cap);
|
2006-05-22 21:12:30 +00:00
|
|
|
if (!p->ringrule) {
|
|
|
|
ast_copy_string(p->ring, p->parent->connection->mid, sizeof(p->ring));
|
|
|
|
p->ringrule = iks_filter_add_rule(p->parent->connection->f, jingle_ringing_ack, p,
|
|
|
|
IKS_RULE_ID, p->ring, IKS_RULE_DONE);
|
2006-08-07 21:15:28 +00:00
|
|
|
} else
|
2006-05-22 21:12:30 +00:00
|
|
|
ast_log(LOG_WARNING, "Whoa, already have a ring rule!\n");
|
2006-08-07 21:15:28 +00:00
|
|
|
|
2006-05-22 21:12:30 +00:00
|
|
|
jingle_transmit_invite(p);
|
2007-10-16 10:29:33 +00:00
|
|
|
jingle_create_candidates(p->parent, p, p->sid, p->them);
|
2006-05-22 21:12:30 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! \brief Hangup a call through the jingle proxy channel */
|
|
|
|
static int jingle_hangup(struct ast_channel *ast)
|
|
|
|
{
|
2012-02-20 23:43:27 +00:00
|
|
|
struct jingle_pvt *p = ast_channel_tech_pvt(ast);
|
2006-05-22 21:12:30 +00:00
|
|
|
struct jingle *client;
|
|
|
|
|
|
|
|
ast_mutex_lock(&p->lock);
|
|
|
|
client = p->parent;
|
|
|
|
p->owner = NULL;
|
2012-02-20 23:43:27 +00:00
|
|
|
ast_channel_tech_pvt_set(ast, NULL);
|
2006-05-22 21:12:30 +00:00
|
|
|
if (!p->alreadygone)
|
2007-09-25 09:07:30 +00:00
|
|
|
jingle_action(client, p, JINGLE_TERMINATE);
|
2006-05-22 21:12:30 +00:00
|
|
|
ast_mutex_unlock(&p->lock);
|
|
|
|
|
|
|
|
jingle_free_pvt(client, p);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! \brief Part of PBX interface */
|
2012-02-01 19:53:38 +00:00
|
|
|
static struct ast_channel *jingle_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
|
2006-05-22 21:12:30 +00:00
|
|
|
{
|
|
|
|
struct jingle_pvt *p = NULL;
|
|
|
|
struct jingle *client = NULL;
|
|
|
|
char *sender = NULL, *to = NULL, *s = NULL;
|
|
|
|
struct ast_channel *chan = NULL;
|
|
|
|
|
|
|
|
if (data) {
|
2007-02-20 16:56:58 +00:00
|
|
|
s = ast_strdupa(data);
|
2012-07-31 20:21:43 +00:00
|
|
|
sender = strsep(&s, "/");
|
|
|
|
if (sender && (sender[0] != '\0'))
|
|
|
|
to = strsep(&s, "/");
|
|
|
|
if (!to) {
|
|
|
|
ast_log(LOG_ERROR, "Bad arguments in Jingle Dialstring: %s\n", data);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (!to) {
|
|
|
|
ast_log(LOG_ERROR, "Bad arguments in Jingle Dialstring: %s\n", (char*) data);
|
|
|
|
return NULL;
|
2006-05-22 21:12:30 +00:00
|
|
|
}
|
|
|
|
}
|
2008-06-02 14:35:24 +00:00
|
|
|
|
2006-05-22 21:12:30 +00:00
|
|
|
client = find_jingle(to, sender);
|
|
|
|
if (!client) {
|
2006-08-07 21:15:28 +00:00
|
|
|
ast_log(LOG_WARNING, "Could not find recipient.\n");
|
2006-05-22 21:12:30 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2008-06-02 14:35:24 +00:00
|
|
|
if (!strcasecmp(client->name, "guest")){
|
|
|
|
/* the guest account is not tied to any configured XMPP client,
|
|
|
|
let's set it now */
|
2011-11-23 17:16:33 +00:00
|
|
|
if (client->connection) {
|
|
|
|
ASTOBJ_UNREF(client->connection, ast_aji_client_destroy);
|
|
|
|
}
|
2008-06-02 14:35:24 +00:00
|
|
|
client->connection = ast_aji_get_client(sender);
|
|
|
|
if (!client->connection) {
|
|
|
|
ast_log(LOG_ERROR, "No XMPP client to talk to, us (partial JID) : %s\n", sender);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-02-21 20:30:54 +00:00
|
|
|
ASTOBJ_WRLOCK(client);
|
2006-05-22 21:12:30 +00:00
|
|
|
p = jingle_alloc(client, to, NULL);
|
2006-08-07 21:15:28 +00:00
|
|
|
if (p)
|
2012-01-24 20:12:09 +00:00
|
|
|
chan = jingle_new(client, p, AST_STATE_DOWN, to, requestor ? ast_channel_linkedid(requestor) : NULL);
|
2007-02-21 20:30:54 +00:00
|
|
|
ASTOBJ_UNLOCK(client);
|
2006-08-07 21:15:28 +00:00
|
|
|
|
2006-05-22 21:12:30 +00:00
|
|
|
return chan;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! \brief CLI command "jingle show channels" */
|
2007-10-16 10:29:33 +00:00
|
|
|
static char *jingle_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
|
2006-05-22 21:12:30 +00:00
|
|
|
{
|
2007-10-16 10:29:33 +00:00
|
|
|
#define FORMAT "%-30.30s %-30.30s %-15.15s %-5.5s %-5.5s \n"
|
|
|
|
struct jingle_pvt *p;
|
|
|
|
struct ast_channel *chan;
|
|
|
|
int numchans = 0;
|
|
|
|
char them[AJI_MAX_JIDLEN];
|
|
|
|
char *jid = NULL;
|
|
|
|
char *resource = NULL;
|
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
case CLI_INIT:
|
|
|
|
e->command = "jingle show channels";
|
|
|
|
e->usage =
|
|
|
|
"Usage: jingle show channels\n"
|
|
|
|
" Shows current state of the Jingle channels.\n";
|
|
|
|
return NULL;
|
|
|
|
case CLI_GENERATE:
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (a->argc != 3)
|
|
|
|
return CLI_SHOWUSAGE;
|
|
|
|
|
2006-05-22 21:12:30 +00:00
|
|
|
ast_mutex_lock(&jinglelock);
|
2007-10-16 10:29:33 +00:00
|
|
|
ast_cli(a->fd, FORMAT, "Channel", "Jabber ID", "Resource", "Read", "Write");
|
|
|
|
ASTOBJ_CONTAINER_TRAVERSE(&jingle_list, 1, {
|
|
|
|
ASTOBJ_WRLOCK(iterator);
|
|
|
|
p = iterator->p;
|
|
|
|
while(p) {
|
|
|
|
chan = p->owner;
|
|
|
|
ast_copy_string(them, p->them, sizeof(them));
|
|
|
|
jid = them;
|
|
|
|
resource = strchr(them, '/');
|
|
|
|
if (!resource)
|
|
|
|
resource = "None";
|
|
|
|
else {
|
|
|
|
*resource = '\0';
|
|
|
|
resource ++;
|
|
|
|
}
|
|
|
|
if (chan)
|
|
|
|
ast_cli(a->fd, FORMAT,
|
2012-01-09 22:15:50 +00:00
|
|
|
ast_channel_name(chan),
|
2007-10-16 10:29:33 +00:00
|
|
|
jid,
|
|
|
|
resource,
|
2012-02-24 00:32:20 +00:00
|
|
|
ast_getformatname(ast_channel_readformat(chan)),
|
|
|
|
ast_getformatname(ast_channel_writeformat(chan))
|
2007-10-16 10:29:33 +00:00
|
|
|
);
|
|
|
|
else
|
|
|
|
ast_log(LOG_WARNING, "No available channel\n");
|
|
|
|
numchans ++;
|
|
|
|
p = p->next;
|
2006-05-22 21:12:30 +00:00
|
|
|
}
|
2007-10-16 10:29:33 +00:00
|
|
|
ASTOBJ_UNLOCK(iterator);
|
|
|
|
});
|
|
|
|
|
2006-05-22 21:12:30 +00:00
|
|
|
ast_mutex_unlock(&jinglelock);
|
2007-10-16 10:29:33 +00:00
|
|
|
|
|
|
|
ast_cli(a->fd, "%d active jingle channel%s\n", numchans, (numchans != 1) ? "s" : "");
|
|
|
|
return CLI_SUCCESS;
|
|
|
|
#undef FORMAT
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! \brief CLI command "jingle reload" */
|
|
|
|
static char *jingle_do_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
|
|
|
|
{
|
|
|
|
switch (cmd) {
|
|
|
|
case CLI_INIT:
|
|
|
|
e->command = "jingle reload";
|
|
|
|
e->usage =
|
|
|
|
"Usage: jingle reload\n"
|
|
|
|
" Reload jingle channel driver.\n";
|
|
|
|
return NULL;
|
|
|
|
case CLI_GENERATE:
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return CLI_SUCCESS;
|
2006-05-22 21:12:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int jingle_parser(void *data, ikspak *pak)
|
|
|
|
{
|
|
|
|
struct jingle *client = ASTOBJ_REF((struct jingle *) data);
|
2007-09-25 09:07:30 +00:00
|
|
|
ast_log(LOG_NOTICE, "Filter matched\n");
|
2006-05-22 21:12:30 +00:00
|
|
|
|
2007-09-25 09:07:30 +00:00
|
|
|
if (iks_find_with_attrib(pak->x, JINGLE_NODE, "action", JINGLE_INITIATE)) {
|
2006-05-22 21:12:30 +00:00
|
|
|
/* New call */
|
|
|
|
jingle_newcall(client, pak);
|
2007-09-25 09:07:30 +00:00
|
|
|
} else if (iks_find_with_attrib(pak->x, JINGLE_NODE, "action", JINGLE_NEGOTIATE)) {
|
2007-06-14 19:39:12 +00:00
|
|
|
ast_debug(3, "About to add candidate!\n");
|
2006-05-22 21:12:30 +00:00
|
|
|
jingle_add_candidate(client, pak);
|
2007-06-14 19:39:12 +00:00
|
|
|
ast_debug(3, "Candidate Added!\n");
|
2007-09-25 09:07:30 +00:00
|
|
|
} else if (iks_find_with_attrib(pak->x, JINGLE_NODE, "action", JINGLE_ACCEPT)) {
|
2006-05-22 21:12:30 +00:00
|
|
|
jingle_is_answered(client, pak);
|
2007-09-25 09:07:30 +00:00
|
|
|
} else if (iks_find_with_attrib(pak->x, JINGLE_NODE, "action", JINGLE_INFO)) {
|
2006-08-02 01:00:24 +00:00
|
|
|
jingle_handle_dtmf(client, pak);
|
2007-09-25 09:07:30 +00:00
|
|
|
} else if (iks_find_with_attrib(pak->x, JINGLE_NODE, "action", JINGLE_TERMINATE)) {
|
2006-05-22 21:12:30 +00:00
|
|
|
jingle_hangup_farend(client, pak);
|
2007-09-25 09:07:30 +00:00
|
|
|
} else if (iks_find_with_attrib(pak->x, JINGLE_NODE, "action", "reject")) {
|
2006-05-22 21:12:30 +00:00
|
|
|
jingle_hangup_farend(client, pak);
|
|
|
|
}
|
|
|
|
ASTOBJ_UNREF(client, jingle_member_destroy);
|
|
|
|
return IKS_FILTER_EAT;
|
|
|
|
}
|
2006-05-23 16:43:58 +00:00
|
|
|
/* Not using this anymore probably take out soon
|
2006-05-22 21:12:30 +00:00
|
|
|
static struct jingle_candidate *jingle_create_candidate(char *args)
|
|
|
|
{
|
|
|
|
char *name, *type, *preference, *protocol;
|
|
|
|
struct jingle_candidate *res;
|
2007-06-03 06:10:27 +00:00
|
|
|
res = ast_calloc(1, sizeof(*res));
|
2006-05-22 21:12:30 +00:00
|
|
|
if (args)
|
|
|
|
name = args;
|
|
|
|
if ((args = strchr(args, ','))) {
|
|
|
|
*args = '\0';
|
|
|
|
args++;
|
|
|
|
preference = args;
|
|
|
|
}
|
|
|
|
if ((args = strchr(args, ','))) {
|
|
|
|
*args = '\0';
|
|
|
|
args++;
|
|
|
|
protocol = args;
|
|
|
|
}
|
|
|
|
if ((args = strchr(args, ','))) {
|
|
|
|
*args = '\0';
|
|
|
|
args++;
|
|
|
|
type = args;
|
|
|
|
}
|
|
|
|
if (name)
|
|
|
|
ast_copy_string(res->name, name, sizeof(res->name));
|
|
|
|
if (preference) {
|
|
|
|
res->preference = atof(preference);
|
|
|
|
}
|
|
|
|
if (protocol) {
|
|
|
|
if (!strcasecmp("udp", protocol))
|
|
|
|
res->protocol = AJI_PROTOCOL_UDP;
|
|
|
|
if (!strcasecmp("ssltcp", protocol))
|
|
|
|
res->protocol = AJI_PROTOCOL_SSLTCP;
|
|
|
|
}
|
|
|
|
if (type) {
|
2007-09-25 09:07:30 +00:00
|
|
|
if (!strcasecmp("host", type))
|
|
|
|
res->type = AJI_CONNECT_HOST;
|
|
|
|
if (!strcasecmp("prflx", type))
|
|
|
|
res->type = AJI_CONNECT_PRFLX;
|
2006-05-22 21:12:30 +00:00
|
|
|
if (!strcasecmp("relay", type))
|
|
|
|
res->type = AJI_CONNECT_RELAY;
|
2007-09-25 09:07:30 +00:00
|
|
|
if (!strcasecmp("srflx", type))
|
|
|
|
res->type = AJI_CONNECT_SRFLX;
|
2006-05-22 21:12:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
2006-05-23 16:43:58 +00:00
|
|
|
*/
|
2006-08-07 21:15:28 +00:00
|
|
|
|
2006-05-22 21:12:30 +00:00
|
|
|
static int jingle_create_member(char *label, struct ast_variable *var, int allowguest,
|
|
|
|
struct ast_codec_pref prefs, char *context,
|
|
|
|
struct jingle *member)
|
|
|
|
{
|
|
|
|
struct aji_client *client;
|
2006-08-07 21:15:28 +00:00
|
|
|
|
2006-05-22 21:12:30 +00:00
|
|
|
if (!member)
|
|
|
|
ast_log(LOG_WARNING, "Out of memory.\n");
|
|
|
|
|
|
|
|
ast_copy_string(member->name, label, sizeof(member->name));
|
|
|
|
ast_copy_string(member->user, label, sizeof(member->user));
|
|
|
|
ast_copy_string(member->context, context, sizeof(member->context));
|
|
|
|
member->allowguest = allowguest;
|
|
|
|
member->prefs = prefs;
|
|
|
|
while (var) {
|
|
|
|
#if 0
|
|
|
|
struct jingle_candidate *candidate = NULL;
|
|
|
|
#endif
|
|
|
|
if (!strcasecmp(var->name, "username"))
|
|
|
|
ast_copy_string(member->user, var->value, sizeof(member->user));
|
|
|
|
else if (!strcasecmp(var->name, "disallow"))
|
2011-02-03 16:22:10 +00:00
|
|
|
ast_parse_allow_disallow(&member->prefs, member->cap, var->value, 0);
|
2006-05-22 21:12:30 +00:00
|
|
|
else if (!strcasecmp(var->name, "allow"))
|
2011-02-03 16:22:10 +00:00
|
|
|
ast_parse_allow_disallow(&member->prefs, member->cap, var->value, 1);
|
2006-05-22 21:12:30 +00:00
|
|
|
else if (!strcasecmp(var->name, "context"))
|
|
|
|
ast_copy_string(member->context, var->value, sizeof(member->context));
|
|
|
|
#if 0
|
|
|
|
else if (!strcasecmp(var->name, "candidate")) {
|
|
|
|
candidate = jingle_create_candidate(var->value);
|
|
|
|
if (candidate) {
|
|
|
|
candidate->next = member->ourcandidates;
|
|
|
|
member->ourcandidates = candidate;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
else if (!strcasecmp(var->name, "connection")) {
|
|
|
|
if ((client = ast_aji_get_client(var->value))) {
|
|
|
|
member->connection = client;
|
2007-09-13 15:25:18 +00:00
|
|
|
iks_filter_add_rule(client->f, jingle_parser, member,
|
|
|
|
IKS_RULE_TYPE, IKS_PAK_IQ,
|
|
|
|
IKS_RULE_FROM_PARTIAL, member->user,
|
|
|
|
IKS_RULE_NS, JINGLE_NS,
|
|
|
|
IKS_RULE_DONE);
|
2006-05-22 21:12:30 +00:00
|
|
|
} else {
|
|
|
|
ast_log(LOG_ERROR, "connection referenced not found!\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
var = var->next;
|
|
|
|
}
|
|
|
|
if (member->connection && member->user)
|
|
|
|
member->buddy = ASTOBJ_CONTAINER_FIND(&member->connection->buddies, member->user);
|
|
|
|
else {
|
|
|
|
ast_log(LOG_ERROR, "No Connection or Username!\n");
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int jingle_load_config(void)
|
|
|
|
{
|
|
|
|
char *cat = NULL;
|
|
|
|
struct ast_config *cfg = NULL;
|
|
|
|
char context[100];
|
|
|
|
int allowguest = 1;
|
|
|
|
struct ast_variable *var;
|
|
|
|
struct jingle *member;
|
2007-09-25 09:07:30 +00:00
|
|
|
struct hostent *hp;
|
|
|
|
struct ast_hostent ahp;
|
2006-05-22 21:12:30 +00:00
|
|
|
struct ast_codec_pref prefs;
|
|
|
|
struct aji_client_container *clients;
|
|
|
|
struct jingle_candidate *global_candidates = NULL;
|
2007-08-16 21:09:46 +00:00
|
|
|
struct ast_flags config_flags = { 0 };
|
2006-05-22 21:12:30 +00:00
|
|
|
|
2007-08-16 21:09:46 +00:00
|
|
|
cfg = ast_config_load(JINGLE_CONFIG, config_flags);
|
2008-09-12 23:30:03 +00:00
|
|
|
if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
|
2006-05-22 21:12:30 +00:00
|
|
|
return 0;
|
2008-09-12 23:30:03 +00:00
|
|
|
}
|
2006-05-22 21:12:30 +00:00
|
|
|
|
2006-06-01 16:47:28 +00:00
|
|
|
/* Copy the default jb config over global_jbconf */
|
|
|
|
memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
|
|
|
|
|
2006-05-22 21:12:30 +00:00
|
|
|
cat = ast_category_browse(cfg, NULL);
|
|
|
|
for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
|
2006-06-01 16:47:28 +00:00
|
|
|
/* handle jb conf */
|
|
|
|
if (!ast_jb_read_conf(&global_jbconf, var->name, var->value))
|
|
|
|
continue;
|
|
|
|
|
2006-05-22 21:12:30 +00:00
|
|
|
if (!strcasecmp(var->name, "allowguest"))
|
|
|
|
allowguest =
|
|
|
|
(ast_true(ast_variable_retrieve(cfg, "general", "allowguest"))) ? 1 : 0;
|
|
|
|
else if (!strcasecmp(var->name, "disallow"))
|
2011-02-03 16:22:10 +00:00
|
|
|
ast_parse_allow_disallow(&prefs, global_capability, var->value, 0);
|
2006-05-22 21:12:30 +00:00
|
|
|
else if (!strcasecmp(var->name, "allow"))
|
2011-02-03 16:22:10 +00:00
|
|
|
ast_parse_allow_disallow(&prefs, global_capability, var->value, 1);
|
2006-05-22 21:12:30 +00:00
|
|
|
else if (!strcasecmp(var->name, "context"))
|
|
|
|
ast_copy_string(context, var->value, sizeof(context));
|
|
|
|
else if (!strcasecmp(var->name, "externip"))
|
|
|
|
ast_copy_string(externip, var->value, sizeof(externip));
|
2007-09-25 09:07:30 +00:00
|
|
|
else if (!strcasecmp(var->name, "bindaddr")) {
|
|
|
|
if (!(hp = ast_gethostbyname(var->value, &ahp))) {
|
|
|
|
ast_log(LOG_WARNING, "Invalid address: %s\n", var->value);
|
|
|
|
} else {
|
|
|
|
memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
|
|
|
|
}
|
|
|
|
}
|
2006-08-08 17:07:41 +00:00
|
|
|
/* Idea to allow for custom candidates */
|
|
|
|
/*
|
2006-05-22 21:12:30 +00:00
|
|
|
else if (!strcasecmp(var->name, "candidate")) {
|
|
|
|
candidate = jingle_create_candidate(var->value);
|
|
|
|
if (candidate) {
|
|
|
|
candidate->next = global_candidates;
|
|
|
|
global_candidates = candidate;
|
|
|
|
}
|
|
|
|
}
|
2006-08-08 17:07:41 +00:00
|
|
|
*/
|
2006-05-22 21:12:30 +00:00
|
|
|
}
|
|
|
|
while (cat) {
|
|
|
|
if (strcasecmp(cat, "general")) {
|
|
|
|
var = ast_variable_browse(cfg, cat);
|
2007-06-03 06:10:27 +00:00
|
|
|
member = ast_calloc(1, sizeof(*member));
|
2006-05-22 21:12:30 +00:00
|
|
|
ASTOBJ_INIT(member);
|
|
|
|
ASTOBJ_WRLOCK(member);
|
2011-02-03 16:22:10 +00:00
|
|
|
member->cap = ast_format_cap_alloc_nolock();
|
2006-05-22 21:12:30 +00:00
|
|
|
if (!strcasecmp(cat, "guest")) {
|
|
|
|
ast_copy_string(member->name, "guest", sizeof(member->name));
|
|
|
|
ast_copy_string(member->user, "guest", sizeof(member->user));
|
|
|
|
ast_copy_string(member->context, context, sizeof(member->context));
|
|
|
|
member->allowguest = allowguest;
|
|
|
|
member->prefs = prefs;
|
|
|
|
while (var) {
|
|
|
|
if (!strcasecmp(var->name, "disallow"))
|
2011-02-03 16:22:10 +00:00
|
|
|
ast_parse_allow_disallow(&member->prefs, member->cap,
|
2006-05-22 21:12:30 +00:00
|
|
|
var->value, 0);
|
|
|
|
else if (!strcasecmp(var->name, "allow"))
|
2011-02-03 16:22:10 +00:00
|
|
|
ast_parse_allow_disallow(&member->prefs, member->cap,
|
2006-05-22 21:12:30 +00:00
|
|
|
var->value, 1);
|
|
|
|
else if (!strcasecmp(var->name, "context"))
|
|
|
|
ast_copy_string(member->context, var->value,
|
|
|
|
sizeof(member->context));
|
2008-04-21 23:42:45 +00:00
|
|
|
else if (!strcasecmp(var->name, "parkinglot"))
|
|
|
|
ast_copy_string(member->parkinglot, var->value,
|
|
|
|
sizeof(member->parkinglot));
|
2006-08-08 17:07:41 +00:00
|
|
|
/* Idea to allow for custom candidates */
|
|
|
|
/*
|
2006-05-22 21:12:30 +00:00
|
|
|
else if (!strcasecmp(var->name, "candidate")) {
|
|
|
|
candidate = jingle_create_candidate(var->value);
|
|
|
|
if (candidate) {
|
|
|
|
candidate->next = member->ourcandidates;
|
|
|
|
member->ourcandidates = candidate;
|
|
|
|
}
|
|
|
|
}
|
2006-08-08 17:07:41 +00:00
|
|
|
*/
|
2006-05-22 21:12:30 +00:00
|
|
|
var = var->next;
|
|
|
|
}
|
|
|
|
ASTOBJ_UNLOCK(member);
|
|
|
|
clients = ast_aji_get_clients();
|
|
|
|
if (clients) {
|
|
|
|
ASTOBJ_CONTAINER_TRAVERSE(clients, 1, {
|
|
|
|
ASTOBJ_WRLOCK(iterator);
|
|
|
|
ASTOBJ_WRLOCK(member);
|
2011-11-23 17:16:33 +00:00
|
|
|
if (member->connection) {
|
|
|
|
ASTOBJ_UNREF(member->connection, ast_aji_client_destroy);
|
|
|
|
}
|
2008-06-02 14:35:24 +00:00
|
|
|
member->connection = NULL;
|
2007-09-13 15:25:18 +00:00
|
|
|
iks_filter_add_rule(iterator->f, jingle_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, JINGLE_NS, IKS_RULE_DONE);
|
2007-09-14 13:02:31 +00:00
|
|
|
iks_filter_add_rule(iterator->f, jingle_parser, member, IKS_RULE_TYPE, IKS_PAK_IQ, IKS_RULE_NS, JINGLE_DTMF_NS, IKS_RULE_DONE);
|
2006-05-22 21:12:30 +00:00
|
|
|
ASTOBJ_UNLOCK(member);
|
|
|
|
ASTOBJ_UNLOCK(iterator);
|
|
|
|
});
|
2008-06-02 14:35:24 +00:00
|
|
|
ASTOBJ_CONTAINER_LINK(&jingle_list, member);
|
2006-05-22 21:12:30 +00:00
|
|
|
} else {
|
|
|
|
ASTOBJ_UNLOCK(member);
|
|
|
|
ASTOBJ_UNREF(member, jingle_member_destroy);
|
|
|
|
}
|
|
|
|
} else {
|
2006-08-07 21:15:28 +00:00
|
|
|
ASTOBJ_UNLOCK(member);
|
|
|
|
if (jingle_create_member(cat, var, allowguest, prefs, context, member))
|
2007-10-16 10:29:33 +00:00
|
|
|
ASTOBJ_CONTAINER_LINK(&jingle_list, member);
|
2006-08-07 21:15:28 +00:00
|
|
|
ASTOBJ_UNREF(member, jingle_member_destroy);
|
2006-05-22 21:12:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
cat = ast_category_browse(cfg, cat);
|
|
|
|
}
|
2012-03-28 19:39:24 +00:00
|
|
|
ast_config_destroy(cfg);
|
2006-05-22 21:12:30 +00:00
|
|
|
jingle_free_candidates(global_candidates);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2012-10-01 23:24:35 +00:00
|
|
|
/*!
|
|
|
|
* \brief Load the module
|
|
|
|
*
|
|
|
|
* Module loading including tests for configuration or dependencies.
|
|
|
|
* This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
|
|
|
|
* or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
|
|
|
|
* tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
|
|
|
|
* configuration file or other non-critical problem return
|
|
|
|
* AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
|
|
|
|
*/
|
2006-08-21 02:11:39 +00:00
|
|
|
static int load_module(void)
|
2006-05-22 21:12:30 +00:00
|
|
|
{
|
2010-07-08 22:08:07 +00:00
|
|
|
struct ast_sockaddr ourip_tmp;
|
|
|
|
struct ast_sockaddr bindaddr_tmp;
|
2011-02-03 16:22:10 +00:00
|
|
|
struct ast_format tmpfmt;
|
2010-07-08 22:08:07 +00:00
|
|
|
|
2008-03-11 20:53:48 +00:00
|
|
|
char *jabber_loaded = ast_module_helper("", "res_jabber.so", 0, 0, 0, 0);
|
2011-02-03 16:22:10 +00:00
|
|
|
|
|
|
|
if (!(jingle_tech.capabilities = ast_format_cap_alloc())) {
|
|
|
|
return AST_MODULE_LOAD_DECLINE;
|
|
|
|
}
|
|
|
|
|
|
|
|
ast_format_cap_add_all_by_type(jingle_tech.capabilities, AST_FORMAT_TYPE_AUDIO);
|
|
|
|
if (!(global_capability = ast_format_cap_alloc())) {
|
|
|
|
return AST_MODULE_LOAD_DECLINE;
|
|
|
|
}
|
|
|
|
ast_format_cap_add(global_capability, ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0));
|
|
|
|
ast_format_cap_add(global_capability, ast_format_set(&tmpfmt, AST_FORMAT_GSM, 0));
|
|
|
|
ast_format_cap_add(global_capability, ast_format_set(&tmpfmt, AST_FORMAT_ALAW, 0));
|
|
|
|
ast_format_cap_add(global_capability, ast_format_set(&tmpfmt, AST_FORMAT_H263, 0));
|
|
|
|
|
2008-03-11 20:53:48 +00:00
|
|
|
free(jabber_loaded);
|
|
|
|
if (!jabber_loaded) {
|
2008-04-28 04:53:20 +00:00
|
|
|
/* Dependency module has a different name, if embedded */
|
|
|
|
jabber_loaded = ast_module_helper("", "res_jabber", 0, 0, 0, 0);
|
|
|
|
free(jabber_loaded);
|
|
|
|
if (!jabber_loaded) {
|
|
|
|
ast_log(LOG_ERROR, "chan_jingle.so depends upon res_jabber.so\n");
|
|
|
|
return AST_MODULE_LOAD_DECLINE;
|
|
|
|
}
|
2008-03-11 20:53:48 +00:00
|
|
|
}
|
|
|
|
|
2007-10-16 10:29:33 +00:00
|
|
|
ASTOBJ_CONTAINER_INIT(&jingle_list);
|
2006-05-22 21:12:30 +00:00
|
|
|
if (!jingle_load_config()) {
|
2006-08-07 21:15:28 +00:00
|
|
|
ast_log(LOG_ERROR, "Unable to read config file %s. Not loading module.\n", JINGLE_CONFIG);
|
2006-08-31 21:00:20 +00:00
|
|
|
return AST_MODULE_LOAD_DECLINE;
|
2006-05-22 21:12:30 +00:00
|
|
|
}
|
|
|
|
|
2010-12-20 17:15:54 +00:00
|
|
|
sched = ast_sched_context_create();
|
2010-10-14 15:21:42 +00:00
|
|
|
if (!sched) {
|
2006-05-22 21:12:30 +00:00
|
|
|
ast_log(LOG_WARNING, "Unable to create schedule context\n");
|
2010-10-14 15:21:42 +00:00
|
|
|
}
|
2006-05-22 21:12:30 +00:00
|
|
|
|
|
|
|
io = io_context_create();
|
2010-10-14 15:21:42 +00:00
|
|
|
if (!io) {
|
2006-05-22 21:12:30 +00:00
|
|
|
ast_log(LOG_WARNING, "Unable to create I/O context\n");
|
2010-10-14 15:21:42 +00:00
|
|
|
}
|
2006-05-22 21:12:30 +00:00
|
|
|
|
2010-07-08 23:46:20 +00:00
|
|
|
ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
|
2010-10-14 15:21:42 +00:00
|
|
|
if (ast_find_ourip(&ourip_tmp, &bindaddr_tmp, AF_INET)) {
|
2006-05-22 21:12:30 +00:00
|
|
|
ast_log(LOG_WARNING, "Unable to get own IP address, Jingle disabled\n");
|
|
|
|
return 0;
|
|
|
|
}
|
2010-07-08 22:08:07 +00:00
|
|
|
__ourip.s_addr = htonl(ast_sockaddr_ipv4(&ourip_tmp));
|
2006-05-22 21:12:30 +00:00
|
|
|
|
2009-04-02 17:20:52 +00:00
|
|
|
ast_rtp_glue_register(&jingle_rtp_glue);
|
2008-07-11 18:09:35 +00:00
|
|
|
ast_cli_register_multiple(jingle_cli, ARRAY_LEN(jingle_cli));
|
2006-05-22 21:12:30 +00:00
|
|
|
/* Make sure we can register our channel type */
|
|
|
|
if (ast_channel_register(&jingle_tech)) {
|
2008-08-09 12:53:57 +00:00
|
|
|
ast_log(LOG_ERROR, "Unable to register channel class %s\n", channel_type);
|
2006-05-22 21:12:30 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! \brief Reload module */
|
2006-08-21 02:11:39 +00:00
|
|
|
static int reload(void)
|
2006-05-22 21:12:30 +00:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! \brief Unload the jingle channel from Asterisk */
|
2006-08-21 02:11:39 +00:00
|
|
|
static int unload_module(void)
|
2006-05-22 21:12:30 +00:00
|
|
|
{
|
2006-05-23 16:43:58 +00:00
|
|
|
struct jingle_pvt *privates = NULL;
|
2008-07-11 18:09:35 +00:00
|
|
|
ast_cli_unregister_multiple(jingle_cli, ARRAY_LEN(jingle_cli));
|
2006-05-22 21:12:30 +00:00
|
|
|
/* First, take us out of the channel loop */
|
|
|
|
ast_channel_unregister(&jingle_tech);
|
2009-04-02 17:20:52 +00:00
|
|
|
ast_rtp_glue_unregister(&jingle_rtp_glue);
|
2006-08-07 21:15:28 +00:00
|
|
|
|
2006-05-22 21:12:30 +00:00
|
|
|
if (!ast_mutex_lock(&jinglelock)) {
|
|
|
|
/* Hangup all interfaces if they have an owner */
|
2007-10-16 10:29:33 +00:00
|
|
|
ASTOBJ_CONTAINER_TRAVERSE(&jingle_list, 1, {
|
2006-05-23 16:43:58 +00:00
|
|
|
ASTOBJ_WRLOCK(iterator);
|
|
|
|
privates = iterator->p;
|
|
|
|
while(privates) {
|
2006-09-18 16:36:14 +00:00
|
|
|
if (privates->owner)
|
|
|
|
ast_softhangup(privates->owner, AST_SOFTHANGUP_APPUNLOAD);
|
|
|
|
privates = privates->next;
|
2006-05-23 16:43:58 +00:00
|
|
|
}
|
|
|
|
iterator->p = NULL;
|
|
|
|
ASTOBJ_UNLOCK(iterator);
|
|
|
|
});
|
2006-05-22 21:12:30 +00:00
|
|
|
ast_mutex_unlock(&jinglelock);
|
|
|
|
} else {
|
|
|
|
ast_log(LOG_WARNING, "Unable to lock the monitor\n");
|
|
|
|
return -1;
|
|
|
|
}
|
2007-10-16 10:29:33 +00:00
|
|
|
ASTOBJ_CONTAINER_DESTROYALL(&jingle_list, jingle_member_destroy);
|
|
|
|
ASTOBJ_CONTAINER_DESTROY(&jingle_list);
|
2011-02-03 16:22:10 +00:00
|
|
|
|
|
|
|
global_capability = ast_format_cap_destroy(global_capability);
|
2006-05-22 21:12:30 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-07-20 19:35:02 +00:00
|
|
|
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Jingle Channel Driver",
|
2006-08-21 02:11:39 +00:00
|
|
|
.load = load_module,
|
|
|
|
.unload = unload_module,
|
|
|
|
.reload = reload,
|
2010-07-20 19:35:02 +00:00
|
|
|
.load_pri = AST_MODPRI_CHANNEL_DRIVER,
|
2006-08-21 02:11:39 +00:00
|
|
|
);
|