Merge 192.168.0.100:/repos/git/asterisk
This commit is contained in:
commit
84c94e92c1
61
CHANGES
61
CHANGES
|
@ -12,9 +12,23 @@
|
|||
--- Functionality changes from Asterisk 1.8 to Asterisk 1.10 -----------------
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
Text Messaging
|
||||
--------------
|
||||
* Asterisk now has protocol independent support for processing text messages
|
||||
outside of a call. Messages are routed through the Asterisk dialplan.
|
||||
SIP MESSAGE and XMPP are currently supported. There are options in
|
||||
jabber.conf and sip.conf to allow enabling these features.
|
||||
-> jabber.conf: see the "sendtodialplan" and "context" options.
|
||||
-> sip.conf: see the "accept_outofcall_message" and "auth_message_requests"
|
||||
options.
|
||||
The MESSAGE() dialplan function and MessageSend() application have been
|
||||
added to go along with this functionality. More detailed usage information
|
||||
can be found on the Asterisk wiki (http://wiki.asterisk.org/).
|
||||
|
||||
Parking
|
||||
-------
|
||||
* parkedmusicclass can now be set for non-default parking lots.
|
||||
* ParkedCall application can now specify a specific parkinglot.
|
||||
|
||||
Asterisk Manager Interface
|
||||
--------------------------
|
||||
|
@ -23,6 +37,10 @@ Asterisk Manager Interface
|
|||
for chan_dahdi ISDN channels.
|
||||
* Added new action MeetmeListRooms to list active conferences (shows same
|
||||
data as "meetme list" at the CLI).
|
||||
* DAHDIShowChannels, SIPshowpeer, SIPpeers, and IAXpeers now contains a
|
||||
Description field that is set by 'description' in the channel configuration
|
||||
file.
|
||||
* Added Uniqueid header to UserEvent.
|
||||
|
||||
Asterisk HTTP Server
|
||||
--------------------------
|
||||
|
@ -41,6 +59,9 @@ CLI Changes
|
|||
alternate configuration file to use.
|
||||
* 'dialplan add extension' command will now automatically create a context if
|
||||
the specified context does not exist with a message indicated it did so.
|
||||
* 'sip show peers', 'iax show peers', and 'dahdi show peers' now contains a
|
||||
Description field which can be populated with 'description' in the channel
|
||||
configuration files (sip.conf, iax2.conf, and chan_dahdi.conf).
|
||||
|
||||
CDR
|
||||
--------------------------
|
||||
|
@ -52,6 +73,13 @@ CODECS
|
|||
* Ability to define custom SILK formats in codecs.conf.
|
||||
* Addition of speex32 audio format with translation.
|
||||
|
||||
ConfBridge
|
||||
--------------------------
|
||||
* New highly optimized and customizable ConfBridge application capable of
|
||||
mixing audio at sample rates ranging from 8khz-96khz.
|
||||
* CONFBRIDGE dialplan function capable of creating dynamic ConfBridge user
|
||||
and bridge profiles on a channel.
|
||||
|
||||
Dialplan Variables
|
||||
------------------
|
||||
* Added ASTETCDIR, ASTMODDIR, ASTVARLIBDIR, ASTDBDIR, ASTKEYDIR, ASTDATADIR,
|
||||
|
@ -60,8 +88,16 @@ Dialplan Variables
|
|||
|
||||
Dialplan Functions
|
||||
------------------
|
||||
* Addition of the JITTERBUFFER dialplan function. This function allows
|
||||
for jitterbuffering to occur on the read side of a channel. By using
|
||||
this function conference applications such as ConfBridge and MeetMe can
|
||||
have the rx streams jitterbuffered before conference mixing occurs.
|
||||
* Added DB_KEYS, which lists the next set of keys in the Asterisk database
|
||||
hierarchy.
|
||||
* Added STRREPLACE function. This function let's the user search a variable
|
||||
for a given string to replace with another string as many times as the
|
||||
user specifies or just throughout the whole string.
|
||||
* Added option to CHANNEL(pickupgroup) allow reading and setting the pickupgroup of channel.
|
||||
|
||||
libpri channel driver (chan_dahdi) DAHDI changes
|
||||
--------------------------
|
||||
|
@ -76,6 +112,8 @@ Calendaring
|
|||
--------------------------
|
||||
* Added setvar option to calendar.conf to allow setting channel variables on
|
||||
notification channels.
|
||||
* Added "calendar show types" CLI command to list registered calendar
|
||||
connectors.
|
||||
|
||||
MixMonitor
|
||||
--------------------------
|
||||
|
@ -91,6 +129,24 @@ FollowMe
|
|||
compatability for a FollowMe call with certain dialplan apps, options, and
|
||||
functions.
|
||||
|
||||
CEL
|
||||
--------------------------
|
||||
* cel_pgsql now supports the 'extra' column for data added using the
|
||||
CELGenUserEvent() application.
|
||||
|
||||
pbx_lua
|
||||
--------------------------
|
||||
* Support for defining hints has been added to pbx_lua. See the 'hints' table
|
||||
in the sample extensions.lua file for syntax details.
|
||||
* Applications that perform jumps in the dialplan such as Goto will now
|
||||
execute properly. When pbx_lua detects that the context, extension, or
|
||||
priority we are executing on has changed it will immediatly return control
|
||||
to the asterisk PBX engine. Currently the engine cannot detect a Goto to
|
||||
the priority after the currently executing priority.
|
||||
* An autoservice is now started by default for pbx_lua channels. It can be
|
||||
stopped and restarted using the autoservice_stop() and autoservice_start()
|
||||
functions.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
--- Functionality changes from Asterisk 1.6.2 to Asterisk 1.8 ----------------
|
||||
------------------------------------------------------------------------------
|
||||
|
@ -160,6 +216,7 @@ SIP Changes
|
|||
res_stun_monitor module support in chan_sip.
|
||||
* Addition of the 'auth_options_requests' option for turning on and off
|
||||
authentication for OPTIONS requests in chan_sip.
|
||||
* Add T38 support for REJECTED state where T.38 Negotiation is explicitly rejected.
|
||||
|
||||
|
||||
IAX2 Changes
|
||||
|
@ -266,6 +323,8 @@ Applications
|
|||
* Added 'D' command to ExternalIVR full details in doc/externalivr.txt
|
||||
* Added 'v' option to MeetMe to play voicemail greetings when a user joins/leaves
|
||||
a MeetMe conference
|
||||
* Added ability to include '@parkinglot' to ParkedCall extension in order to specify
|
||||
a specific parkinglot on which to search the extension.
|
||||
|
||||
Dialplan Functions
|
||||
------------------
|
||||
|
@ -521,6 +580,8 @@ Asterisk Manager Interface
|
|||
* Added a new eventfilter option per user to allow whitelisting and blacklisting
|
||||
of events.
|
||||
* Added optional parkinglot variable for park command.
|
||||
* Added ConnectedLineNum and ConnectedLineName headers to AMI events/responses
|
||||
if CallerIDNum and CallerIDName headers are also present.
|
||||
|
||||
Channel Event Logging
|
||||
---------------------
|
||||
|
|
2
CREDITS
2
CREDITS
|
@ -222,6 +222,8 @@ ClearIT AB, Sweden - res_mutestream, queue_exists and various other patches (dev
|
|||
Despegar.com, Argentina - AstData API implementation, also sponsored by Google as part of the
|
||||
gsoc/2009 program (developed by Eliel)
|
||||
|
||||
Philippe Lindheimer - DEV_STATE additions to CCSS
|
||||
|
||||
=== OTHER CONTRIBUTIONS ===
|
||||
John Todd - Monkey sounds and associated teletorture prompt
|
||||
Michael Jerris - bug marshaling
|
||||
|
|
3
Makefile
3
Makefile
|
@ -545,7 +545,6 @@ installdirs:
|
|||
$(INSTALL) -d "$(DESTDIR)$(ASTLOGDIR)"
|
||||
$(INSTALL) -d "$(DESTDIR)$(ASTLOGDIR)/cdr-csv"
|
||||
$(INSTALL) -d "$(DESTDIR)$(ASTLOGDIR)/cdr-custom"
|
||||
$(INSTALL) -d "$(DESTDIR)$(ASTLOGDIR)/cel-csv"
|
||||
$(INSTALL) -d "$(DESTDIR)$(ASTLOGDIR)/cel-custom"
|
||||
$(INSTALL) -d "$(DESTDIR)$(ASTDATADIR)"
|
||||
$(INSTALL) -d "$(DESTDIR)$(ASTDATADIR)/documentation"
|
||||
|
@ -925,7 +924,7 @@ menuselect/nmenuselect: menuselect/makeopts
|
|||
menuselect/makeopts: makeopts
|
||||
+$(MAKE_MENUSELECT) makeopts
|
||||
|
||||
menuselect-tree: $(foreach dir,$(filter-out main,$(MOD_SUBDIRS)),$(wildcard $(dir)/*.c) $(wildcard $(dir)/*.cc)) build_tools/cflags.xml build_tools/cflags-devmode.xml sounds/sounds.xml build_tools/embed_modules.xml utils/utils.xml agi/agi.xml configure
|
||||
menuselect-tree: $(foreach dir,$(filter-out main,$(MOD_SUBDIRS)),$(wildcard $(dir)/*.c) $(wildcard $(dir)/*.cc)) build_tools/cflags.xml build_tools/cflags-devmode.xml sounds/sounds.xml build_tools/embed_modules.xml utils/utils.xml agi/agi.xml configure makeopts
|
||||
@echo "Generating input for menuselect ..."
|
||||
@echo "<?xml version=\"1.0\"?>" > $@
|
||||
@echo >> $@
|
||||
|
|
|
@ -133,6 +133,14 @@ From 1.6.2 to 1.8:
|
|||
* The default value for the pedantic option in sip.conf has been changed
|
||||
from "no" to "yes".
|
||||
|
||||
* The ConnectedLineNum and ConnectedLineName headers were added to many AMI
|
||||
events/responses if the CallerIDNum/CallerIDName headers were also present.
|
||||
The addition of connected line support changes the behavior of the channel
|
||||
caller ID somewhat. The channel caller ID value no longer time shares with
|
||||
the connected line ID on outgoing call legs. The timing of some AMI
|
||||
events/responses output the connected line ID as caller ID. These party ID's
|
||||
are now separate.
|
||||
|
||||
From 1.6.1 to 1.6.2:
|
||||
|
||||
* SIP no longer sends the 183 progress message for early media by
|
||||
|
|
16
UPGRADE.txt
16
UPGRADE.txt
|
@ -21,6 +21,14 @@
|
|||
|
||||
From 1.8 to 1.10:
|
||||
|
||||
cel_pgsql:
|
||||
- This module now expects an 'extra' column in the database for data added
|
||||
using the CELGenUserEvent() application.
|
||||
|
||||
ConfBridge
|
||||
- ConfBridge's dialplan arguments have changed and are not
|
||||
backwards compatible.
|
||||
|
||||
HTTP:
|
||||
- A bindaddr must be specified in order for the HTTP server
|
||||
to run. Previous versions would default to 0.0.0.0 if no
|
||||
|
@ -34,5 +42,13 @@ chan_dahdi:
|
|||
- The mohinterpret=passthrough setting is deprecated in favor of
|
||||
moh_signaling=notify.
|
||||
|
||||
pbx_lua:
|
||||
- Execution no longer continues after applications that do dialplan jumps
|
||||
(such as app.goto). Now when an application such as app.goto() is called,
|
||||
control is returned back to the pbx engine and the current extension
|
||||
function stops executing.
|
||||
- the autoservice now defaults to being on by default
|
||||
- autoservice_start() and autoservice_start() no longer return a value.
|
||||
|
||||
===========================================================
|
||||
===========================================================
|
||||
|
|
|
@ -546,7 +546,10 @@ static int MYSQL_exec(struct ast_channel *chan, const char *data)
|
|||
result = 0;
|
||||
|
||||
if (autoclear) {
|
||||
struct ast_datastore *mysql_store = ast_channel_datastore_find(chan, &mysql_ds_info, NULL);
|
||||
struct ast_datastore *mysql_store = NULL;
|
||||
|
||||
ast_channel_lock(chan);
|
||||
mysql_store = ast_channel_datastore_find(chan, &mysql_ds_info, NULL);
|
||||
if (!mysql_store) {
|
||||
if (!(mysql_store = ast_datastore_alloc(&mysql_ds_info, NULL))) {
|
||||
ast_log(LOG_WARNING, "Unable to allocate new datastore.\n");
|
||||
|
@ -555,6 +558,7 @@ static int MYSQL_exec(struct ast_channel *chan, const char *data)
|
|||
ast_channel_datastore_add(chan, mysql_store);
|
||||
}
|
||||
}
|
||||
ast_channel_unlock(chan);
|
||||
}
|
||||
ast_mutex_lock(&_mysql_mutex);
|
||||
|
||||
|
|
|
@ -325,7 +325,7 @@ db_reconnect:
|
|||
ast_str_make_space(&escape, (valsz = strlen(value)) * 2 + 1);
|
||||
mysql_real_escape_string(&mysql, ast_str_buffer(escape), value, valsz);
|
||||
|
||||
ast_str_append(&sql1, 0, "%s", entry->name);
|
||||
ast_str_append(&sql1, 0, "`%s`", entry->name);
|
||||
ast_str_append(&sql2, 0, "'%s'", ast_str_buffer(escape));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1185,7 +1185,7 @@ static int mbl_devicestate(void *data)
|
|||
int res = AST_DEVICE_INVALID;
|
||||
struct mbl_pvt *pvt;
|
||||
|
||||
device = ast_strdupa(S_OR(data, ""));
|
||||
device = ast_strdupa(S_OR((char *) data, ""));
|
||||
|
||||
ast_debug(1, "Checking device state for device %s\n", device);
|
||||
|
||||
|
|
|
@ -143,7 +143,7 @@ static struct ooh323_pvt {
|
|||
int faxmode;
|
||||
int t38_tx_enable;
|
||||
int t38_init;
|
||||
struct sockaddr_in udptlredirip;
|
||||
struct ast_sockaddr udptlredirip;
|
||||
time_t lastTxT38;
|
||||
int chmodepend;
|
||||
|
||||
|
@ -212,7 +212,7 @@ struct ooh323_user{
|
|||
int t38support;
|
||||
int rtptimeout;
|
||||
int mUseIP; /* Use IP address or H323-ID to search user */
|
||||
char mIP[20];
|
||||
char mIP[4*8+7+2]; /* Max for IPv6 - 2 brackets, 8 4hex, 7 - : */
|
||||
struct OOH323Regex *rtpmask;
|
||||
char rtpmaskstr[120];
|
||||
int rtdrcount, rtdrinterval;
|
||||
|
@ -235,7 +235,7 @@ struct ooh323_peer{
|
|||
int dtmfcodec;
|
||||
int t38support;
|
||||
int mFriend; /* indicates defined as friend */
|
||||
char ip[20];
|
||||
char ip[4*8+7+2]; /* Max for IPv6 - 2 brackets, 8 4hex, 7 - : */
|
||||
int port;
|
||||
char *h323id; /* H323-ID alias, which asterisk will register with gk to reach this peer*/
|
||||
char *email; /* Email alias, which asterisk will register with gk to reach this peer*/
|
||||
|
@ -286,7 +286,9 @@ void onModeChanged(ooCallData *call, int t38mode);
|
|||
|
||||
static char gLogFile[256] = DEFAULT_LOGFILE;
|
||||
static int gPort = 1720;
|
||||
static char gIP[20];
|
||||
static char gIP[2+8*4+7]; /* Max for IPv6 addr */
|
||||
struct ast_sockaddr bindaddr;
|
||||
int v6mode = 0;
|
||||
static char gCallerID[AST_MAX_EXTENSION] = "";
|
||||
static struct ooAliases *gAliasList;
|
||||
static struct ast_format_cap *gCap;
|
||||
|
@ -373,10 +375,6 @@ static struct ast_channel *ooh323_new(struct ooh323_pvt *i, int state,
|
|||
ast_format_copy(&ch->rawwriteformat, &tmpfmt);
|
||||
ast_format_copy(&ch->rawreadformat, &tmpfmt);
|
||||
|
||||
ast_channel_set_fd(ch, 0, ast_rtp_instance_fd(i->rtp, 0));
|
||||
ast_channel_set_fd(ch, 1, ast_rtp_instance_fd(i->rtp, 1));
|
||||
ast_channel_set_fd(ch, 5, ast_udptl_fd(i->udptl));
|
||||
|
||||
ast_jb_configure(ch, &global_jbconf);
|
||||
|
||||
if (state == AST_STATE_RING)
|
||||
|
@ -468,9 +466,7 @@ static struct ast_channel *ooh323_new(struct ooh323_pvt *i, int state,
|
|||
static struct ooh323_pvt *ooh323_alloc(int callref, char *callToken)
|
||||
{
|
||||
struct ooh323_pvt *pvt = NULL;
|
||||
struct sockaddr_in ouraddr;
|
||||
struct ast_sockaddr tmp;
|
||||
struct in_addr ipAddr;
|
||||
|
||||
if (gH323Debug)
|
||||
ast_verbose("--- ooh323_alloc\n");
|
||||
|
||||
|
@ -487,40 +483,6 @@ static struct ooh323_pvt *ooh323_alloc(int callref, char *callToken)
|
|||
ast_mutex_init(&pvt->lock);
|
||||
ast_mutex_lock(&pvt->lock);
|
||||
|
||||
|
||||
if (!inet_aton(gIP, &ipAddr)) {
|
||||
ast_log(LOG_ERROR, "Invalid OOH323 driver ip address\n");
|
||||
ast_mutex_unlock(&pvt->lock);
|
||||
ast_mutex_destroy(&pvt->lock);
|
||||
ast_free(pvt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ouraddr.sin_family = AF_INET;
|
||||
ouraddr.sin_addr = ipAddr;
|
||||
ast_sockaddr_from_sin(&tmp, &ouraddr);
|
||||
if (!(pvt->rtp = ast_rtp_instance_new("asterisk", sched, &tmp, NULL))) {
|
||||
ast_log(LOG_WARNING, "Unable to create RTP session: %s\n",
|
||||
strerror(errno));
|
||||
ast_mutex_unlock(&pvt->lock);
|
||||
ast_mutex_destroy(&pvt->lock);
|
||||
ast_free(pvt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ast_rtp_instance_set_qos(pvt->rtp, gTOS, 0, "ooh323-rtp");
|
||||
|
||||
if (!(pvt->udptl = ast_udptl_new_with_bindaddr(sched, io, 0, &tmp))) {
|
||||
ast_log(LOG_WARNING, "Unable to create UDPTL session: %s\n",
|
||||
strerror(errno));
|
||||
ast_mutex_unlock(&pvt->lock);
|
||||
ast_mutex_destroy(&pvt->lock);
|
||||
ast_free(pvt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ast_udptl_set_error_correction_scheme(pvt->udptl, UDPTL_ERROR_CORRECTION_NONE);
|
||||
ast_udptl_set_far_max_datagram(pvt->udptl, 144);
|
||||
pvt->faxmode = 0;
|
||||
pvt->t38support = gT38Support;
|
||||
pvt->rtptimeout = gRTPTimeout;
|
||||
|
@ -1046,13 +1008,13 @@ static int ooh323_hangup(struct ast_channel *ast)
|
|||
|
||||
if (gH323Debug)
|
||||
ast_verbose(" hanging %s with cause: %d\n", p->username, q931cause);
|
||||
ast->tech_pvt = NULL;
|
||||
ast->tech_pvt = NULL;
|
||||
if (!ast_test_flag(p, H323_ALREADYGONE)) {
|
||||
ooHangCall(p->callToken,
|
||||
ooHangCall(p->callToken,
|
||||
ooh323_convert_hangupcause_asteriskToH323(q931cause), q931cause);
|
||||
ast_set_flag(p, H323_ALREADYGONE);
|
||||
/* ast_mutex_unlock(&p->lock); */
|
||||
} else
|
||||
} else
|
||||
ast_set_flag(p, H323_NEEDDESTROY);
|
||||
/* detach channel here */
|
||||
if (p->owner) {
|
||||
|
@ -1068,11 +1030,11 @@ static int ooh323_hangup(struct ast_channel *ast)
|
|||
|
||||
/* Notify the module monitors that use count for resource has changed */
|
||||
ast_update_use_count();
|
||||
|
||||
|
||||
} else {
|
||||
ast_debug(1, "No call to hangup\n" );
|
||||
}
|
||||
|
||||
|
||||
if (gH323Debug)
|
||||
ast_verbose("+++ ooh323_hangup\n");
|
||||
|
||||
|
@ -1082,6 +1044,7 @@ static int ooh323_hangup(struct ast_channel *ast)
|
|||
static int ooh323_answer(struct ast_channel *ast)
|
||||
{
|
||||
struct ooh323_pvt *p = ast->tech_pvt;
|
||||
char *callToken = (char *)NULL;
|
||||
|
||||
if (gH323Debug)
|
||||
ast_verbose("--- ooh323_answer\n");
|
||||
|
@ -1089,10 +1052,21 @@ static int ooh323_answer(struct ast_channel *ast)
|
|||
if (p) {
|
||||
|
||||
ast_mutex_lock(&p->lock);
|
||||
callToken = (p->callToken ? strdup(p->callToken) : NULL);
|
||||
if (ast->_state != AST_STATE_UP) {
|
||||
ast_channel_lock(ast);
|
||||
if (!p->alertsent) {
|
||||
if (gH323Debug) {
|
||||
ast_debug(1, "Sending forced ringback for %s, res = %d\n",
|
||||
callToken, ooManualRingback(callToken));
|
||||
} else {
|
||||
ooManualRingback(callToken);
|
||||
}
|
||||
p->alertsent = 1;
|
||||
}
|
||||
ast_setstate(ast, AST_STATE_UP);
|
||||
ast_debug(1, "ooh323_answer(%s)\n", ast->name);
|
||||
if (option_debug)
|
||||
ast_debug(1, "ooh323_answer(%s)\n", ast->name);
|
||||
ast_channel_unlock(ast);
|
||||
ooAnswerCall(p->callToken);
|
||||
}
|
||||
|
@ -1141,10 +1115,11 @@ static int ooh323_write(struct ast_channel *ast, struct ast_frame *f)
|
|||
return res;
|
||||
}
|
||||
|
||||
|
||||
if (f->frametype == AST_FRAME_VOICE) {
|
||||
/* sending progress for first */
|
||||
if (!ast_test_flag(p, H323_OUTGOING) && !p->progsent &&
|
||||
p->callToken) {
|
||||
p->callToken) {
|
||||
ooManualProgress(p->callToken);
|
||||
p->progsent = 1;
|
||||
}
|
||||
|
@ -1209,39 +1184,39 @@ static int ooh323_indicate(struct ast_channel *ast, int condition, const void *d
|
|||
|
||||
if (gH323Debug)
|
||||
ast_verbose("----- ooh323_indicate %d on call %s\n", condition, callToken);
|
||||
|
||||
ast_mutex_lock(&p->lock);
|
||||
|
||||
ast_mutex_lock(&p->lock);
|
||||
switch (condition) {
|
||||
case AST_CONTROL_CONGESTION:
|
||||
if (!ast_test_flag(p, H323_ALREADYGONE)) {
|
||||
ooHangCall(callToken, OO_REASON_LOCAL_CONGESTED,
|
||||
ooHangCall(callToken, OO_REASON_LOCAL_CONGESTED,
|
||||
AST_CAUSE_SWITCH_CONGESTION);
|
||||
ast_set_flag(p, H323_ALREADYGONE);
|
||||
}
|
||||
break;
|
||||
case AST_CONTROL_BUSY:
|
||||
if (!ast_test_flag(p, H323_ALREADYGONE)) {
|
||||
ooHangCall(callToken, OO_REASON_LOCAL_BUSY, AST_CAUSE_USER_BUSY);
|
||||
ooHangCall(callToken, OO_REASON_LOCAL_BUSY, AST_CAUSE_USER_BUSY);
|
||||
ast_set_flag(p, H323_ALREADYGONE);
|
||||
}
|
||||
break;
|
||||
case AST_CONTROL_HOLD:
|
||||
ast_moh_start(ast, data, NULL);
|
||||
ast_moh_start(ast, data, NULL);
|
||||
break;
|
||||
case AST_CONTROL_UNHOLD:
|
||||
ast_moh_stop(ast);
|
||||
break;
|
||||
case AST_CONTROL_PROGRESS:
|
||||
if (ast->_state != AST_STATE_UP) {
|
||||
if (!p->progsent) {
|
||||
if (gH323Debug) {
|
||||
if (!p->progsent) {
|
||||
if (gH323Debug) {
|
||||
ast_debug(1, "Sending manual progress for %s, res = %d\n", callToken,
|
||||
ooManualProgress(callToken));
|
||||
ooManualProgress(callToken));
|
||||
} else {
|
||||
ooManualProgress(callToken);
|
||||
ooManualProgress(callToken);
|
||||
}
|
||||
p->progsent = 1;
|
||||
}
|
||||
p->progsent = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AST_CONTROL_RINGING:
|
||||
|
@ -1256,6 +1231,7 @@ static int ooh323_indicate(struct ast_channel *ast, int condition, const void *d
|
|||
}
|
||||
p->alertsent = 1;
|
||||
}
|
||||
p->alertsent = 1;
|
||||
}
|
||||
break;
|
||||
case AST_CONTROL_SRCUPDATE:
|
||||
|
@ -1393,8 +1369,8 @@ static int ooh323_queryoption(struct ast_channel *ast, int option, void *data, i
|
|||
|
||||
if (gH323Debug)
|
||||
ast_verbose("+++++ ooh323_queryoption %d on channel %s\n", option, ast->name);
|
||||
|
||||
ast_mutex_unlock(&p->lock);
|
||||
|
||||
ast_mutex_unlock(&p->lock);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
@ -1438,9 +1414,9 @@ void ooh323_set_write_format(ooCallData *call, struct ast_format *fmt, int txfra
|
|||
char formats[FORMAT_STRING_SIZE];
|
||||
|
||||
if (gH323Debug)
|
||||
ast_verbose("--- ooh323_update_writeformat %s/%d\n",
|
||||
ast_verbose("--- ooh323_update_writeformat %s/%d\n",
|
||||
ast_getformatname(fmt), txframes);
|
||||
|
||||
|
||||
p = find_call(call);
|
||||
if (!p) {
|
||||
ast_log(LOG_ERROR, "No matching call found for %s\n", call->callToken);
|
||||
|
@ -1453,7 +1429,7 @@ void ooh323_set_write_format(ooCallData *call, struct ast_format *fmt, int txfra
|
|||
|
||||
if (p->owner) {
|
||||
while (p->owner && ast_channel_trylock(p->owner)) {
|
||||
ast_debug(1, "Failed to grab lock, trying again\n");
|
||||
ast_debug(1,"Failed to grab lock, trying again\n");
|
||||
DEADLOCK_AVOIDANCE(&p->lock);
|
||||
}
|
||||
if (!p->owner) {
|
||||
|
@ -1462,7 +1438,7 @@ void ooh323_set_write_format(ooCallData *call, struct ast_format *fmt, int txfra
|
|||
return;
|
||||
}
|
||||
if (gH323Debug)
|
||||
ast_verbose("Writeformat before update %s/%s\n",
|
||||
ast_verbose("Writeformat before update %s/%s\n",
|
||||
ast_getformatname(&p->owner->writeformat),
|
||||
ast_getformatname_multiple(formats, sizeof(formats), p->owner->nativeformats));
|
||||
if (txframes)
|
||||
|
@ -1498,7 +1474,7 @@ void ooh323_set_read_format(ooCallData *call, struct ast_format *fmt)
|
|||
if (gH323Debug)
|
||||
ast_verbose("--- ooh323_update_readformat %s\n",
|
||||
ast_getformatname(fmt));
|
||||
|
||||
|
||||
p = find_call(call);
|
||||
if (!p) {
|
||||
ast_log(LOG_ERROR, "No matching call found for %s\n", call->callToken);
|
||||
|
@ -1511,7 +1487,7 @@ void ooh323_set_read_format(ooCallData *call, struct ast_format *fmt)
|
|||
|
||||
if (p->owner) {
|
||||
while (p->owner && ast_channel_trylock(p->owner)) {
|
||||
ast_debug(1, "Failed to grab lock, trying again\n");
|
||||
ast_debug(1,"Failed to grab lock, trying again\n");
|
||||
DEADLOCK_AVOIDANCE(&p->lock);
|
||||
}
|
||||
if (!p->owner) {
|
||||
|
@ -1521,12 +1497,12 @@ void ooh323_set_read_format(ooCallData *call, struct ast_format *fmt)
|
|||
}
|
||||
|
||||
if (gH323Debug)
|
||||
ast_verbose("Readformat before update %s\n",
|
||||
ast_verbose("Readformat before update %s\n",
|
||||
ast_getformatname(&p->owner->readformat));
|
||||
ast_format_cap_set(p->owner->nativeformats, fmt);
|
||||
ast_set_read_format(p->owner, &p->owner->readformat);
|
||||
ast_set_read_format(p->owner, &p->owner->readformat);
|
||||
ast_channel_unlock(p->owner);
|
||||
} else
|
||||
} else
|
||||
ast_log(LOG_ERROR, "No owner found\n");
|
||||
|
||||
ast_mutex_unlock(&p->lock);
|
||||
|
@ -1544,12 +1520,12 @@ int onAlerting(ooCallData *call)
|
|||
if (gH323Debug)
|
||||
ast_verbose("--- onAlerting %s\n", call->callToken);
|
||||
|
||||
p = find_call(call);
|
||||
p = find_call(call);
|
||||
|
||||
if(!p) {
|
||||
if(!p) {
|
||||
ast_log(LOG_ERROR, "No matching call found\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
ast_mutex_lock(&p->lock);
|
||||
if (!p->owner) {
|
||||
ast_mutex_unlock(&p->lock);
|
||||
|
@ -1600,12 +1576,12 @@ int onProgress(ooCallData *call)
|
|||
if (gH323Debug)
|
||||
ast_verbose("--- onProgress %s\n", call->callToken);
|
||||
|
||||
p = find_call(call);
|
||||
p = find_call(call);
|
||||
|
||||
if(!p) {
|
||||
if(!p) {
|
||||
ast_log(LOG_ERROR, "No matching call found\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
ast_mutex_lock(&p->lock);
|
||||
if (!p->owner) {
|
||||
ast_mutex_unlock(&p->lock);
|
||||
|
@ -1639,8 +1615,8 @@ int onProgress(ooCallData *call)
|
|||
ast_setstate(c, AST_STATE_RINGING);
|
||||
|
||||
ast_queue_control(c, AST_CONTROL_PROGRESS);
|
||||
ast_channel_unlock(c);
|
||||
ast_mutex_unlock(&p->lock);
|
||||
ast_channel_unlock(c);
|
||||
ast_mutex_unlock(&p->lock);
|
||||
|
||||
if (gH323Debug)
|
||||
ast_verbose("+++ onProgress %s\n", call->callToken);
|
||||
|
@ -1819,10 +1795,14 @@ int ooh323_onReceivedSetup(ooCallData *call, Q931Message *pmsg)
|
|||
} else {
|
||||
ast_mutex_unlock(&p->lock);
|
||||
ast_log(LOG_ERROR, "Unacceptable ip %s\n", call->remoteIP);
|
||||
if (!user)
|
||||
if (!user) {
|
||||
ooHangCall(call->callToken, ooh323_convert_hangupcause_asteriskToH323(AST_CAUSE_CALL_REJECTED), AST_CAUSE_CALL_REJECTED);
|
||||
else
|
||||
call->callEndReason = OO_REASON_REMOTE_REJECTED;
|
||||
}
|
||||
else {
|
||||
ooHangCall(call->callToken, ooh323_convert_hangupcause_asteriskToH323(AST_CAUSE_NORMAL_CIRCUIT_CONGESTION), AST_CAUSE_NORMAL_CIRCUIT_CONGESTION);
|
||||
call->callEndReason = OO_REASON_REMOTE_REJECTED;
|
||||
}
|
||||
ast_set_flag(p, H323_NEEDDESTROY);
|
||||
return -1;
|
||||
}
|
||||
|
@ -1830,15 +1810,19 @@ int ooh323_onReceivedSetup(ooCallData *call, Q931Message *pmsg)
|
|||
|
||||
ooh323c_set_capability_for_call(call, &p->prefs, p->cap, p->dtmfmode, p->dtmfcodec,
|
||||
p->t38support, p->g729onlyA);
|
||||
configure_local_rtp(p, call);
|
||||
|
||||
/* Incoming call */
|
||||
c = ooh323_new(p, AST_STATE_RING, p->username, 0, NULL);
|
||||
if(!c) {
|
||||
ast_mutex_unlock(&p->lock);
|
||||
ast_log(LOG_ERROR, "Could not create ast_channel\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (!configure_local_rtp(p, call)) {
|
||||
ast_mutex_unlock(&p->lock);
|
||||
ast_log(LOG_ERROR, "Couldn't create rtp structure\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ast_mutex_unlock(&p->lock);
|
||||
|
||||
if (gH323Debug)
|
||||
|
@ -1909,6 +1893,11 @@ int onOutgoingCall(ooCallData *call)
|
|||
ast_copy_string(call->rtpMaskStr, p->rtpmaskstr, sizeof(call->rtpMaskStr));
|
||||
}
|
||||
|
||||
if (!configure_local_rtp(p, call)) {
|
||||
ast_mutex_unlock(&p->lock);
|
||||
return OO_FAILED;
|
||||
}
|
||||
|
||||
ast_mutex_unlock(&p->lock);
|
||||
}
|
||||
|
||||
|
@ -1998,7 +1987,7 @@ int onNewCallCreated(ooCallData *call)
|
|||
ooh323c_set_capability_for_call(call, &p->prefs, p->cap,
|
||||
p->dtmfmode, p->dtmfcodec, p->t38support, p->g729onlyA);
|
||||
|
||||
configure_local_rtp(p, call);
|
||||
/* configure_local_rtp(p, call); */
|
||||
ast_mutex_unlock(&p->lock);
|
||||
}
|
||||
|
||||
|
@ -2021,14 +2010,14 @@ int onCallEstablished(ooCallData *call)
|
|||
return -1;
|
||||
}
|
||||
|
||||
if(ast_test_flag(p, H323_OUTGOING)) {
|
||||
if(ast_test_flag(p, H323_OUTGOING)) {
|
||||
ast_mutex_lock(&p->lock);
|
||||
if (!p->owner) {
|
||||
ast_mutex_unlock(&p->lock);
|
||||
ast_log(LOG_ERROR, "Channel has no owner\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
while (p->owner && ast_channel_trylock(p->owner)) {
|
||||
ast_debug(1, "Failed to grab lock, trying again\n");
|
||||
DEADLOCK_AVOIDANCE(&p->lock);
|
||||
|
@ -2050,7 +2039,7 @@ int onCallEstablished(ooCallData *call)
|
|||
}
|
||||
|
||||
ast_queue_control(c, AST_CONTROL_ANSWER);
|
||||
ast_channel_unlock(p->owner);
|
||||
ast_channel_unlock(p->owner);
|
||||
manager_event(EVENT_FLAG_SYSTEM,"ChannelUpdate","Channel: %s\r\nChanneltype: %s\r\n"
|
||||
"CallRef: %d\r\n", c->name, "OOH323", p->call_reference);
|
||||
}
|
||||
|
@ -2075,42 +2064,42 @@ int onCallCleared(ooCallData *call)
|
|||
|
||||
if ((p = find_call(call))) {
|
||||
ast_mutex_lock(&p->lock);
|
||||
|
||||
|
||||
while (p->owner) {
|
||||
if (ast_channel_trylock(p->owner)) {
|
||||
ooTrace(OOTRCLVLINFO, "Failed to grab lock, trying again\n");
|
||||
ast_debug(1, "Failed to grab lock, trying again\n");
|
||||
ast_debug(1, "Failed to grab lock, trying again\n");
|
||||
DEADLOCK_AVOIDANCE(&p->lock);
|
||||
} else {
|
||||
ownerLock = 1; break;
|
||||
ownerLock = 1; break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ownerLock) {
|
||||
if (!ast_test_flag(p, H323_ALREADYGONE)) {
|
||||
if (!ast_test_flag(p, H323_ALREADYGONE)) {
|
||||
|
||||
ast_set_flag(p, H323_ALREADYGONE);
|
||||
p->owner->hangupcause = call->q931cause;
|
||||
p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
|
||||
ast_queue_hangup_with_cause(p->owner,call->q931cause);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(p->owner) {
|
||||
p->owner->tech_pvt = NULL;
|
||||
if(p->owner) {
|
||||
p->owner->tech_pvt = NULL;
|
||||
ast_channel_unlock(p->owner);
|
||||
p->owner = NULL;
|
||||
p->owner = NULL;
|
||||
ast_module_unref(myself);
|
||||
}
|
||||
|
||||
ast_set_flag(p, H323_NEEDDESTROY);
|
||||
|
||||
ooh323c_stop_call_thread(call);
|
||||
ooh323c_stop_call_thread(call);
|
||||
|
||||
ast_mutex_unlock(&p->lock);
|
||||
ast_mutex_lock(&usecnt_lock);
|
||||
usecnt--;
|
||||
ast_mutex_unlock(&usecnt_lock);
|
||||
ast_mutex_lock(&usecnt_lock);
|
||||
usecnt--;
|
||||
ast_mutex_unlock(&usecnt_lock);
|
||||
|
||||
}
|
||||
|
||||
|
@ -2265,12 +2254,14 @@ static struct ooh323_user *build_user(const char *name, struct ast_variable *v)
|
|||
user->cap, tcodecs, 1);
|
||||
} else if (!strcasecmp(v->name, "amaflags")) {
|
||||
user->amaflags = ast_cdr_amaflags2int(v->value);
|
||||
} else if (!strcasecmp(v->name, "ip")) {
|
||||
strncpy(user->mIP, v->value, sizeof(user->mIP)-1);
|
||||
} else if (!strcasecmp(v->name, "ip") || !strcasecmp(v->name, "host")) {
|
||||
struct ast_sockaddr p;
|
||||
if (!ast_parse_arg(v->value, PARSE_ADDR, &p)) {
|
||||
ast_copy_string(user->mIP, ast_sockaddr_stringify_addr(&p), sizeof(user->mIP)-1);
|
||||
} else {
|
||||
ast_copy_string(user->mIP, v->value, sizeof(user->mIP)-1);
|
||||
}
|
||||
user->mUseIP = 1;
|
||||
} else if (!strcasecmp(v->name, "host")) {
|
||||
strncpy(user->mIP, v->value, sizeof(user->mIP)-1);
|
||||
user->mUseIP = 1;
|
||||
} else if (!strcasecmp(v->name, "dtmfmode")) {
|
||||
if (!strcasecmp(v->value, "rfc2833"))
|
||||
user->dtmfmode = H323_DTMF_RFC2833;
|
||||
|
@ -2371,10 +2362,14 @@ static struct ooh323_peer *build_peer(const char *name, struct ast_variable *v,
|
|||
}
|
||||
} else if (!strcasecmp(v->name, "port")) {
|
||||
peer->port = atoi(v->value);
|
||||
} else if (!strcasecmp(v->name, "ip")) {
|
||||
ast_copy_string(peer->ip, v->value, sizeof(peer->ip));
|
||||
} else if (!strcasecmp(v->name, "host")) {
|
||||
ast_copy_string(peer->ip, v->value, sizeof(peer->ip));
|
||||
} else if (!strcasecmp(v->name, "host") || !strcasecmp(v->name, "ip")) {
|
||||
struct ast_sockaddr p;
|
||||
if (!ast_parse_arg(v->value, PARSE_ADDR, &p)) {
|
||||
ast_copy_string(peer->ip, ast_sockaddr_stringify_host(&p), sizeof(peer->ip));
|
||||
} else {
|
||||
ast_copy_string(peer->ip, v->value, sizeof(peer->ip));
|
||||
}
|
||||
|
||||
} else if (!strcasecmp(v->name, "outgoinglimit")) {
|
||||
peer->outgoinglimit = atoi(v->value);
|
||||
if (peer->outgoinglimit < 0)
|
||||
|
@ -2583,6 +2578,13 @@ int reload_config(int reload)
|
|||
gPort = (int)strtol(v->value, NULL, 10);
|
||||
} else if (!strcasecmp(v->name, "bindaddr")) {
|
||||
ast_copy_string(gIP, v->value, sizeof(gIP));
|
||||
if (ast_parse_arg(v->value, PARSE_ADDR, &bindaddr)) {
|
||||
ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
|
||||
return 1;
|
||||
}
|
||||
if (ast_sockaddr_is_ipv6(&bindaddr)) {
|
||||
v6mode = 1;
|
||||
}
|
||||
} else if (!strcasecmp(v->name, "h225portrange")) {
|
||||
char* endlimit = 0;
|
||||
char temp[512];
|
||||
|
@ -2802,7 +2804,7 @@ int reload_config(int reload)
|
|||
/* Determine ip address if neccessary */
|
||||
if (ast_strlen_zero(gIP)) {
|
||||
ooGetLocalIPAddress(gIP);
|
||||
if (!strcmp(gIP, "127.0.0.1")) {
|
||||
if (!strcmp(gIP, "127.0.0.1") || !strcmp(gIP, "::1")) {
|
||||
ast_log(LOG_NOTICE, "Failed to determine local ip address. Please "
|
||||
"specify it in ooh323.conf. OOH323 Disabled\n");
|
||||
return 1;
|
||||
|
@ -3320,6 +3322,9 @@ static int load_module(void)
|
|||
ooH323EpSetH225MsgCallbacks(h225Callbacks);
|
||||
ooH323EpSetTraceLevel(gTRCLVL);
|
||||
ooH323EpSetLocalAddress(gIP, gPort);
|
||||
if (v6mode) {
|
||||
ast_debug(1, "OOH323 channel is in IP6 mode\n");
|
||||
}
|
||||
ooH323EpSetCallerID(gCallerID);
|
||||
|
||||
if(ooH323EpSetTCPPortRange(ooconfig.mTCPPortStart,
|
||||
|
@ -3557,7 +3562,7 @@ int ooh323_destroy(struct ooh323_pvt *p)
|
|||
free(cur->callerid_name);
|
||||
cur->callerid_name = 0;
|
||||
}
|
||||
|
||||
|
||||
if (cur->callerid_num) {
|
||||
free(cur->callerid_num);
|
||||
cur->callerid_num = 0;
|
||||
|
@ -3572,20 +3577,20 @@ int ooh323_destroy(struct ooh323_pvt *p)
|
|||
ast_udptl_destroy(cur->udptl);
|
||||
cur->udptl = NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Unlink us from the owner if we have one */
|
||||
if (cur->owner) {
|
||||
while(ast_channel_trylock(cur->owner)) {
|
||||
ast_debug(1, "Failed to grab lock, trying again\n");
|
||||
while(ast_channel_trylock(cur->owner)) {
|
||||
ast_debug(1, "Failed to grab lock, trying again\n");
|
||||
DEADLOCK_AVOIDANCE(&cur->lock);
|
||||
}
|
||||
}
|
||||
ast_debug(1, "Detaching from %s\n", cur->owner->name);
|
||||
cur->owner->tech_pvt = NULL;
|
||||
ast_channel_unlock(cur->owner);
|
||||
cur->owner = NULL;
|
||||
ast_module_unref(myself);
|
||||
}
|
||||
|
||||
|
||||
if (cur->vad) {
|
||||
ast_dsp_free(cur->vad);
|
||||
cur->vad = NULL;
|
||||
|
@ -3910,8 +3915,6 @@ static int ooh323_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance
|
|||
{
|
||||
/* XXX Deal with Video */
|
||||
struct ooh323_pvt *p;
|
||||
struct sockaddr_in them;
|
||||
struct sockaddr_in us;
|
||||
struct ast_sockaddr tmp;
|
||||
int mode;
|
||||
|
||||
|
@ -3929,10 +3932,13 @@ static int ooh323_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance
|
|||
return -1;
|
||||
}
|
||||
ast_rtp_instance_get_remote_address(rtp, &tmp);
|
||||
ast_sockaddr_to_sin(&tmp, &them);
|
||||
ast_rtp_instance_get_local_address(rtp, &tmp);
|
||||
ast_sockaddr_to_sin(&tmp, &us);
|
||||
return 0;
|
||||
|
||||
/* May 20101003 */
|
||||
/* What we should to do here? */
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -3940,7 +3946,7 @@ static int ooh323_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance
|
|||
|
||||
int configure_local_rtp(struct ooh323_pvt *p, ooCallData *call)
|
||||
{
|
||||
struct sockaddr_in us;
|
||||
char lhost[INET6_ADDRSTRLEN], *lport=NULL;
|
||||
struct ast_sockaddr tmp;
|
||||
ooMediaInfo mediaInfo;
|
||||
int x;
|
||||
|
@ -3951,6 +3957,46 @@ int configure_local_rtp(struct ooh323_pvt *p, ooCallData *call)
|
|||
if (gH323Debug)
|
||||
ast_verbose("--- configure_local_rtp\n");
|
||||
|
||||
|
||||
if (ast_parse_arg(call->localIP, PARSE_ADDR, &tmp)) {
|
||||
ast_sockaddr_copy(&tmp, &bindaddr);
|
||||
}
|
||||
if (!(p->rtp = ast_rtp_instance_new("asterisk", sched, &tmp, NULL))) {
|
||||
ast_log(LOG_WARNING, "Unable to create RTP session: %s\n",
|
||||
strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
ast_rtp_instance_set_qos(p->rtp, gTOS, 0, "ooh323-rtp");
|
||||
|
||||
if (!(p->udptl = ast_udptl_new_with_bindaddr(sched, io, 0, &tmp))) {
|
||||
ast_log(LOG_WARNING, "Unable to create UDPTL session: %s\n",
|
||||
strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
ast_udptl_set_far_max_datagram(p->udptl, 144);
|
||||
|
||||
if (p->owner) {
|
||||
while (p->owner && ast_channel_trylock(p->owner)) {
|
||||
ast_debug(1,"Failed to grab lock, trying again\n");
|
||||
DEADLOCK_AVOIDANCE(&p->lock);
|
||||
}
|
||||
if (!p->owner) {
|
||||
ast_mutex_unlock(&p->lock);
|
||||
ast_log(LOG_ERROR, "Channel has no owner\n");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
ast_log(LOG_ERROR, "Channel has no owner\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ast_channel_set_fd(p->owner, 0, ast_rtp_instance_fd(p->rtp, 0));
|
||||
ast_channel_set_fd(p->owner, 1, ast_rtp_instance_fd(p->rtp, 1));
|
||||
ast_channel_set_fd(p->owner, 5, ast_udptl_fd(p->udptl));
|
||||
|
||||
ast_channel_unlock(p->owner);
|
||||
|
||||
if (p->rtp) {
|
||||
ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(p->rtp), p->rtp, &p->prefs);
|
||||
if (p->dtmfmode & H323_DTMF_RFC2833 && p->dtmfcodec) {
|
||||
|
@ -3965,7 +4011,8 @@ int configure_local_rtp(struct ooh323_pvt *p, ooCallData *call)
|
|||
}
|
||||
/* figure out our local RTP port and tell the H.323 stack about it*/
|
||||
ast_rtp_instance_get_local_address(p->rtp, &tmp);
|
||||
ast_sockaddr_to_sin(&tmp, &us);
|
||||
strncpy(lhost, ast_sockaddr_stringify_addr(&tmp), sizeof(lhost));
|
||||
lport = ast_sockaddr_stringify_port(&tmp);
|
||||
|
||||
if (p->rtptimeout) {
|
||||
ast_rtp_instance_set_timeout(p->rtp, p->rtptimeout);
|
||||
|
@ -3982,8 +4029,8 @@ int configure_local_rtp(struct ooh323_pvt *p, ooCallData *call)
|
|||
}
|
||||
|
||||
|
||||
ast_copy_string(mediaInfo.lMediaIP, ast_inet_ntoa(us.sin_addr), sizeof(mediaInfo.lMediaIP));
|
||||
mediaInfo.lMediaPort = ntohs(us.sin_port);
|
||||
ast_copy_string(mediaInfo.lMediaIP, lhost, sizeof(mediaInfo.lMediaIP));
|
||||
mediaInfo.lMediaPort = atoi(lport);
|
||||
mediaInfo.lMediaCntrlPort = mediaInfo.lMediaPort +1;
|
||||
for (x = 0; ast_codec_pref_index(&p->prefs, x, &tmpfmt); x++) {
|
||||
strcpy(mediaInfo.dir, "transmit");
|
||||
|
@ -4007,19 +4054,18 @@ int configure_local_rtp(struct ooh323_pvt *p, ooCallData *call)
|
|||
}
|
||||
|
||||
if (p->udptl) {
|
||||
struct ast_sockaddr us_tmp;
|
||||
ast_sockaddr_from_sin(&us_tmp, &us);
|
||||
ast_udptl_get_us(p->udptl, &us_tmp);
|
||||
ast_sockaddr_to_sin(&us_tmp, &us);
|
||||
ast_udptl_get_us(p->udptl, &tmp);
|
||||
strncpy(lhost, ast_sockaddr_stringify_addr(&tmp), sizeof(lhost));
|
||||
lport = ast_sockaddr_stringify_port(&tmp);
|
||||
ast_copy_string(mediaInfo.lMediaIP, lhost, sizeof(mediaInfo.lMediaIP));
|
||||
mediaInfo.lMediaPort = atoi(lport);
|
||||
mediaInfo.lMediaCntrlPort = mediaInfo.lMediaPort +1;
|
||||
mediaInfo.cap = OO_T38;
|
||||
strcpy(mediaInfo.dir, "transmit");
|
||||
ooAddMediaInfo(call, mediaInfo);
|
||||
strcpy(mediaInfo.dir, "receive");
|
||||
ooAddMediaInfo(call, mediaInfo);
|
||||
}
|
||||
ast_copy_string(mediaInfo.lMediaIP, ast_inet_ntoa(us.sin_addr), sizeof(mediaInfo.lMediaIP));
|
||||
mediaInfo.lMediaPort = ntohs(us.sin_port);
|
||||
mediaInfo.lMediaCntrlPort = mediaInfo.lMediaPort +1;
|
||||
mediaInfo.cap = OO_T38;
|
||||
strcpy(mediaInfo.dir, "transmit");
|
||||
ooAddMediaInfo(call, mediaInfo);
|
||||
strcpy(mediaInfo.dir, "receive");
|
||||
ooAddMediaInfo(call, mediaInfo);
|
||||
|
||||
if (gH323Debug)
|
||||
ast_verbose("+++ configure_local_rtp\n");
|
||||
|
@ -4031,7 +4077,6 @@ void setup_rtp_connection(ooCallData *call, const char *remoteIp,
|
|||
int remotePort)
|
||||
{
|
||||
struct ooh323_pvt *p = NULL;
|
||||
struct sockaddr_in them;
|
||||
struct ast_sockaddr tmp;
|
||||
|
||||
if (gH323Debug)
|
||||
|
@ -4045,10 +4090,8 @@ void setup_rtp_connection(ooCallData *call, const char *remoteIp,
|
|||
return;
|
||||
}
|
||||
|
||||
them.sin_family = AF_INET;
|
||||
them.sin_addr.s_addr = inet_addr(remoteIp); /* only works for IPv4 */
|
||||
them.sin_port = htons(remotePort);
|
||||
ast_sockaddr_from_sin(&tmp, &them);
|
||||
ast_parse_arg(remoteIp, PARSE_ADDR, &tmp);
|
||||
ast_sockaddr_set_port(&tmp, remotePort);
|
||||
ast_rtp_instance_set_remote_address(p->rtp, &tmp);
|
||||
|
||||
if (p->writeformat.id == AST_FORMAT_G726_AAL2)
|
||||
|
@ -4114,10 +4157,9 @@ static int ooh323_set_udptl_peer(struct ast_channel *chan, struct ast_udptl *udp
|
|||
if (!p)
|
||||
return -1;
|
||||
ast_mutex_lock(&p->lock);
|
||||
|
||||
if (udptl) {
|
||||
struct ast_sockaddr udptl_addr;
|
||||
ast_udptl_get_peer(udptl, &udptl_addr);
|
||||
ast_sockaddr_to_sin(&udptl_addr, &p->udptlredirip);
|
||||
ast_udptl_get_peer(udptl, &p->udptlredirip);
|
||||
} else
|
||||
memset(&p->udptlredirip, 0, sizeof(p->udptlredirip));
|
||||
|
||||
|
@ -4130,14 +4172,13 @@ void setup_udptl_connection(ooCallData *call, const char *remoteIp,
|
|||
int remotePort)
|
||||
{
|
||||
struct ooh323_pvt *p = NULL;
|
||||
struct sockaddr_in them;
|
||||
struct ast_sockaddr them_addr;
|
||||
struct ast_sockaddr them;
|
||||
|
||||
if (gH323Debug)
|
||||
ast_verbose("--- setup_udptl_connection\n");
|
||||
|
||||
/* Find the call or allocate a private structure if call not found */
|
||||
p = find_call(call);
|
||||
p = find_call(call);
|
||||
|
||||
if (!p) {
|
||||
ast_log(LOG_ERROR, "Something is wrong: rtp\n");
|
||||
|
@ -4161,11 +4202,10 @@ void setup_udptl_connection(ooCallData *call, const char *remoteIp,
|
|||
return;
|
||||
}
|
||||
|
||||
them.sin_family = AF_INET;
|
||||
them.sin_addr.s_addr = inet_addr(remoteIp); /* only works for IPv4 */
|
||||
them.sin_port = htons(remotePort);
|
||||
ast_sockaddr_from_sin(&them_addr, &them);
|
||||
ast_udptl_set_peer(p->udptl, &them_addr);
|
||||
ast_parse_arg(remoteIp, PARSE_ADDR, &them);
|
||||
ast_sockaddr_set_port(&them, remotePort);
|
||||
|
||||
ast_udptl_set_peer(p->udptl, &them);
|
||||
ast_udptl_set_tag(p->udptl, "%s", p->owner->name);
|
||||
p->t38_tx_enable = 1;
|
||||
p->lastTxT38 = time(NULL);
|
||||
|
@ -4177,8 +4217,8 @@ void setup_udptl_connection(ooCallData *call, const char *remoteIp,
|
|||
ast_queue_control_data(p->owner, AST_CONTROL_T38_PARAMETERS, ¶meters, sizeof(parameters));
|
||||
}
|
||||
if (gH323Debug)
|
||||
ast_debug(1, "Receiving UDPTL %s:%d\n", ast_inet_ntoa(them.sin_addr),
|
||||
ntohs(them.sin_port));
|
||||
ast_debug(1, "Receiving UDPTL %s:%s\n", ast_sockaddr_stringify_host(&them),
|
||||
ast_sockaddr_stringify_port(&them));
|
||||
|
||||
ast_channel_unlock(p->owner);
|
||||
ast_mutex_unlock(&p->lock);
|
||||
|
@ -4193,12 +4233,12 @@ void close_udptl_connection(ooCallData *call)
|
|||
{
|
||||
struct ooh323_pvt *p = NULL;
|
||||
|
||||
if(gH323Debug)
|
||||
if(gH323Debug)
|
||||
ast_verbose("--- close_udptl_connection\n");
|
||||
|
||||
p = find_call(call);
|
||||
if (!p) {
|
||||
ast_log(LOG_ERROR, "Couldn't find matching call to close udptl "
|
||||
ast_log(LOG_ERROR, "Couldn't find matching call to close udptl "
|
||||
"connection\n");
|
||||
return;
|
||||
}
|
||||
|
@ -4287,7 +4327,7 @@ struct ast_frame *ooh323_rtp_read(struct ast_channel *ast, struct ooh323_pvt *p)
|
|||
case 5:
|
||||
f = ast_udptl_read(p->udptl); /* UDPTL t.38 data */
|
||||
if (gH323Debug) {
|
||||
ast_debug(1, "Got UDPTL %d/%d len %d for %s\n",
|
||||
ast_debug(1, "Got UDPTL %d/%d len %d for %s\n",
|
||||
f->frametype, f->subclass.integer, f->datalen, ast->name);
|
||||
}
|
||||
break;
|
||||
|
@ -4300,7 +4340,7 @@ struct ast_frame *ooh323_rtp_read(struct ast_channel *ast, struct ooh323_pvt *p)
|
|||
/* We already hold the channel lock */
|
||||
if (f->frametype == AST_FRAME_VOICE && !p->faxmode) {
|
||||
if (!(ast_format_cap_iscompatible(p->owner->nativeformats, &f->subclass.format))) {
|
||||
ast_debug(1, "Oooh, voice format changed to %s\n", ast_getformatname(&f->subclass.format));
|
||||
ast_debug(1, "Oooh, voice format changed to %s\n", ast_getformatname(&f->subclass.format));
|
||||
ast_format_cap_set(p->owner->nativeformats, &f->subclass.format);
|
||||
ast_set_read_format(p->owner, &p->owner->readformat);
|
||||
ast_set_write_format(p->owner, &p->owner->writeformat);
|
||||
|
@ -4310,8 +4350,8 @@ struct ast_frame *ooh323_rtp_read(struct ast_channel *ast, struct ooh323_pvt *p)
|
|||
(f->subclass.format.id == AST_FORMAT_SLINEAR || f->subclass.format.id == AST_FORMAT_ALAW ||
|
||||
f->subclass.format.id == AST_FORMAT_ULAW)) {
|
||||
f = ast_dsp_process(p->owner, p->vad, f);
|
||||
if (f && (f->frametype == AST_FRAME_DTMF)) {
|
||||
ast_debug(1, "* Detected inband DTMF '%c'\n", f->subclass.integer);
|
||||
if (f && (f->frametype == AST_FRAME_DTMF)) {
|
||||
ast_debug(1, "* Detected inband DTMF '%c'\n", f->subclass.integer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4330,15 +4370,13 @@ void onModeChanged(ooCallData *call, int t38mode) {
|
|||
|
||||
ast_mutex_lock(&p->lock);
|
||||
|
||||
if (gH323Debug) {
|
||||
ast_debug(1, "change mode to %d for %s\n", t38mode, call->callToken);
|
||||
}
|
||||
if (gH323Debug)
|
||||
ast_debug(1, "change mode to %d for %s\n", t38mode, call->callToken);
|
||||
|
||||
if (t38mode == p->faxmode) {
|
||||
if (gH323Debug) {
|
||||
if (gH323Debug)
|
||||
ast_debug(1, "mode for %s is already %d\n", call->callToken,
|
||||
t38mode);
|
||||
}
|
||||
ast_mutex_unlock(&p->lock);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -97,7 +97,7 @@ typedef struct OOMediaInfo{
|
|||
int cap;
|
||||
int lMediaPort;
|
||||
int lMediaCntrlPort;
|
||||
char lMediaIP[20];
|
||||
char lMediaIP[2+8*4+7];
|
||||
struct OOMediaInfo *next;
|
||||
} OOMediaInfo;
|
||||
|
||||
|
@ -179,12 +179,13 @@ typedef struct OOH323CallData {
|
|||
int dtmfcodec;
|
||||
OOMediaInfo *mediaInfo;
|
||||
OOCallFwdData *pCallFwdData;
|
||||
char localIP[20];/* Local IP address */
|
||||
char localIP[2+8*4+7];/* Local IP address */
|
||||
int versionIP; /* IP Address family 6 or 4 */
|
||||
OOH323Channel* pH225Channel;
|
||||
OOH323Channel* pH245Channel;
|
||||
OOSOCKET *h245listener;
|
||||
int *h245listenport;
|
||||
char remoteIP[20];/* Remote IP address */
|
||||
char remoteIP[2+8*4+7];/* Remote IP address */
|
||||
int remotePort;
|
||||
int remoteH245Port;
|
||||
char *remoteDisplayName;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
*/
|
||||
#include "asterisk.h"
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/netsock2.h"
|
||||
|
||||
#include "ooGkClient.h"
|
||||
#include "ootypes.h"
|
||||
|
@ -261,7 +262,7 @@ int ooGkClientCreateChannel(ooGkClient *pGkClient)
|
|||
int ret=0;
|
||||
OOIPADDR ipaddrs;
|
||||
/* Create socket */
|
||||
if((ret=ooSocketCreateUDP(&pGkClient->rasSocket))!=ASN_OK)
|
||||
if((ret=ooSocketCreateUDP(&pGkClient->rasSocket, 4))!=ASN_OK)
|
||||
{
|
||||
OOTRACEERR1("Failed to create RAS socket\n");
|
||||
pGkClient->state = GkClientFailed;
|
||||
|
@ -269,7 +270,7 @@ int ooGkClientCreateChannel(ooGkClient *pGkClient)
|
|||
}
|
||||
if(pGkClient->localRASPort)
|
||||
{
|
||||
ret= ooSocketStrToAddr (pGkClient->localRASIP, &ipaddrs);
|
||||
inet_pton(AF_INET, pGkClient->localRASIP, &ipaddrs);
|
||||
if( (ret=ooSocketBind( pGkClient->rasSocket, ipaddrs,
|
||||
pGkClient->localRASPort))!=ASN_OK )
|
||||
{
|
||||
|
@ -295,7 +296,7 @@ int ooGkClientCreateChannel(ooGkClient *pGkClient)
|
|||
OOTRACEDBGA1("Determining ip address for RAS channel "
|
||||
"multihomed mode. \n");
|
||||
ret = ooSocketGetIpAndPort(pGkClient->rasSocket, pGkClient->localRASIP,
|
||||
20, &pGkClient->localRASPort);
|
||||
20, &pGkClient->localRASPort, NULL);
|
||||
if(ret != ASN_OK)
|
||||
{
|
||||
OOTRACEERR1("Error:Failed to retrieve local ip and port from "
|
||||
|
@ -666,7 +667,7 @@ int ooGkClientSendGRQ(ooGkClient *pGkClient)
|
|||
}
|
||||
|
||||
|
||||
ooSocketConvertIpToNwAddr(pGkClient->localRASIP, pRasAddress->ip.data);
|
||||
inet_pton(AF_INET, pGkClient->localRASIP, pRasAddress->ip.data);
|
||||
|
||||
pRasAddress->ip.numocts = 4;
|
||||
pRasAddress->port = pGkClient->localRASPort;
|
||||
|
@ -932,7 +933,7 @@ int ooGkClientSendRRQ(ooGkClient *pGkClient, ASN1BOOL keepAlive)
|
|||
}
|
||||
pTransportAddress->t = T_H225TransportAddress_ipAddress;
|
||||
pTransportAddress->u.ipAddress = pIpAddress;
|
||||
ooSocketConvertIpToNwAddr(pGkClient->localRASIP, pIpAddress->ip.data);
|
||||
inet_pton(AF_INET, pGkClient->localRASIP, pIpAddress->ip.data);
|
||||
pIpAddress->ip.numocts = 4;
|
||||
pIpAddress->port = gH323ep.listenPort;
|
||||
|
||||
|
@ -960,7 +961,7 @@ int ooGkClientSendRRQ(ooGkClient *pGkClient, ASN1BOOL keepAlive)
|
|||
pTransportAddress->t = T_H225TransportAddress_ipAddress;
|
||||
pTransportAddress->u.ipAddress = pIpAddress;
|
||||
|
||||
ooSocketConvertIpToNwAddr(pGkClient->localRASIP, pIpAddress->ip.data);
|
||||
inet_pton(AF_INET, pGkClient->localRASIP, pIpAddress->ip.data);
|
||||
|
||||
pIpAddress->ip.numocts = 4;
|
||||
pIpAddress->port = pGkClient->localRASPort;
|
||||
|
@ -1430,7 +1431,7 @@ int ooGkClientSendURQ(ooGkClient *pGkClient, ooAliases *aliases)
|
|||
}
|
||||
pTransportAddress->t = T_H225TransportAddress_ipAddress;
|
||||
pTransportAddress->u.ipAddress = pIpAddress;
|
||||
ooSocketConvertIpToNwAddr(pGkClient->localRASIP, pIpAddress->ip.data);
|
||||
inet_pton(AF_INET, pGkClient->localRASIP, pIpAddress->ip.data);
|
||||
pIpAddress->ip.numocts = 4;
|
||||
pIpAddress->port = gH323ep.listenPort;
|
||||
|
||||
|
@ -1645,14 +1646,14 @@ int ooGkClientSendAdmissionRequest
|
|||
ast_mutex_unlock(&pGkClient->Lock);
|
||||
return OO_FAILED;
|
||||
}
|
||||
ooSocketConvertIpToNwAddr(pGkClient->localRASIP, pIpAddressLocal->ip.data);
|
||||
inet_pton(AF_INET, pGkClient->localRASIP, pIpAddressLocal->ip.data);
|
||||
|
||||
pIpAddressLocal->ip.numocts = 4;
|
||||
pIpAddressLocal->port = gH323ep.listenPort;
|
||||
|
||||
if(!ooUtilsIsStrEmpty(call->remoteIP))
|
||||
{
|
||||
ooSocketConvertIpToNwAddr(call->remoteIP, pIpAddressRemote->ip.data);
|
||||
inet_pton(AF_INET, call->remoteIP, pIpAddressRemote->ip.data);
|
||||
pIpAddressRemote->ip.numocts = 4;
|
||||
pIpAddressRemote->port = call->remotePort;
|
||||
}
|
||||
|
@ -2153,7 +2154,7 @@ int ooGkClientSendIRR
|
|||
ast_mutex_unlock(&pGkClient->Lock);
|
||||
return OO_FAILED;
|
||||
}
|
||||
ooSocketConvertIpToNwAddr(pGkClient->localRASIP, pIpAddressLocal->ip.data);
|
||||
inet_pton(AF_INET, pGkClient->localRASIP, pIpAddressLocal->ip.data);
|
||||
|
||||
pIpAddressLocal->ip.numocts = 4;
|
||||
pIpAddressLocal->port = gH323ep.listenPort;
|
||||
|
@ -2184,7 +2185,7 @@ int ooGkClientSendIRR
|
|||
|
||||
pIpRasAddress->ip.numocts = 4;
|
||||
pIpRasAddress->port = pGkClient->localRASPort;
|
||||
ooSocketConvertIpToNwAddr(pGkClient->localRASIP, pIpRasAddress->ip.data);
|
||||
inet_pton(AF_INET, pGkClient->localRASIP, pIpRasAddress->ip.data);
|
||||
|
||||
pIRR->rasAddress.u.ipAddress = pIpRasAddress;
|
||||
pIRR->rasAddress.t=T_H225TransportAddress_ipAddress; /* IPv4 address */
|
||||
|
@ -2283,11 +2284,11 @@ int ooGkClientSendIRR
|
|||
return OO_FAILED;
|
||||
}
|
||||
pLocalAddr->ip.numocts = 4;
|
||||
ooSocketConvertIpToNwAddr(call->localIP, pLocalAddr->ip.data);
|
||||
inet_pton(AF_INET, call->localIP, pLocalAddr->ip.data);
|
||||
pLocalAddr->port = (call->pH225Channel->port) ? call->pH225Channel->port : gH323ep.listenPort;
|
||||
|
||||
pRemoteAddr->ip.numocts = 4;
|
||||
ooSocketConvertIpToNwAddr(call->remoteIP, pRemoteAddr->ip.data);
|
||||
inet_pton(AF_INET, call->remoteIP, pRemoteAddr->ip.data);
|
||||
pRemoteAddr->port = call->remotePort;
|
||||
|
||||
perCallInfo->callSignaling.m.sendAddressPresent = TRUE;
|
||||
|
|
|
@ -47,7 +47,7 @@ extern "C" {
|
|||
|
||||
|
||||
|
||||
#define MAX_IP_LEN 18
|
||||
#define MAX_IP_LEN 2+8*4+7
|
||||
#define DEFAULT_GKPORT 1719
|
||||
#define MULTICAST_GKADDRESS "224.0.1.41"
|
||||
#define MULTICAST_GKPORT 1718
|
||||
|
@ -181,9 +181,9 @@ typedef struct ooGkClient{
|
|||
OOCTXT msgCtxt;
|
||||
OOSOCKET rasSocket;
|
||||
int localRASPort;
|
||||
char localRASIP[20];
|
||||
char gkRasIP[20];
|
||||
char gkCallSignallingIP[20];
|
||||
char localRASIP[2+8*4+7];
|
||||
char gkRasIP[2+8*4+7];
|
||||
char gkCallSignallingIP[2+8*4+7];
|
||||
RasGatekeeperInfo gkInfo;
|
||||
int gkRasPort;
|
||||
int gkCallSignallingPort;
|
||||
|
|
|
@ -82,7 +82,7 @@ OOLogicalChannel* ooAddNewLogicalChannel(OOH323CallData *call, int channelNo,
|
|||
/* If user application has not specified a specific ip and is using
|
||||
multihomed mode, substitute appropriate ip.
|
||||
*/
|
||||
if(!strcmp(pMediaInfo->lMediaIP, "0.0.0.0"))
|
||||
if(!strcmp(pMediaInfo->lMediaIP, "0.0.0.0") || !strcmp(pMediaInfo->lMediaIP, "::"))
|
||||
strcpy(pNewChannel->localIP, call->localIP);
|
||||
else
|
||||
strcpy(pNewChannel->localIP, pMediaInfo->lMediaIP);
|
||||
|
|
|
@ -53,12 +53,12 @@ typedef struct OOLogicalChannel {
|
|||
int sessionID;
|
||||
enum OOCapType type;
|
||||
char dir[10]; /* receive/transmit */
|
||||
char remoteIP[20];
|
||||
char remoteIP[2+8*4+7];
|
||||
int remoteMediaPort;
|
||||
int remoteMediaControlPort;
|
||||
int localRtpPort;
|
||||
int localRtcpPort;
|
||||
char localIP[20];
|
||||
char localIP[2+8*4+7];
|
||||
OOLogicalChannelState state;
|
||||
struct ooH323EpCapability *chanCap;
|
||||
struct OOLogicalChannel *next;
|
||||
|
|
|
@ -21,9 +21,16 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
|||
#include "asterisk/lock.h"
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/network.h"
|
||||
#include "asterisk/netsock2.h"
|
||||
#include "asterisk/config.h"
|
||||
|
||||
#include "ooSocket.h"
|
||||
#include "ootrace.h"
|
||||
#include "ooh323ep.h"
|
||||
|
||||
/** Global endpoint structure */
|
||||
extern OOH323EndPoint gH323ep;
|
||||
|
||||
#if defined(_WIN32_WCE)
|
||||
static int inited = 0;
|
||||
#define SEND_FLAGS 0
|
||||
|
@ -188,17 +195,25 @@ typedef int OOSOCKLEN;
|
|||
typedef socklen_t OOSOCKLEN;
|
||||
#endif
|
||||
|
||||
int ooSocketCreate (OOSOCKET* psocket)
|
||||
int ooSocketCreate (OOSOCKET* psocket, int family)
|
||||
{
|
||||
int on;
|
||||
OOSOCKET sock;
|
||||
int keepalive = 1;
|
||||
#ifdef __linux__
|
||||
int keepcnt = 24, keepidle = 120, keepintvl = 30;
|
||||
#endif
|
||||
struct linger linger;
|
||||
OOSOCKET sock = socket (AF_INET,
|
||||
SOCK_STREAM,
|
||||
0);
|
||||
|
||||
if (family == 6) {
|
||||
sock = socket (AF_INET6,
|
||||
SOCK_STREAM,
|
||||
0);
|
||||
} else {
|
||||
sock = socket (AF_INET,
|
||||
SOCK_STREAM,
|
||||
0);
|
||||
}
|
||||
|
||||
if (sock == OOSOCKET_INVALID){
|
||||
OOTRACEERR1("Error:Failed to create TCP socket\n");
|
||||
|
@ -231,12 +246,18 @@ int ooSocketCreate (OOSOCKET* psocket)
|
|||
return ASN_OK;
|
||||
}
|
||||
|
||||
int ooSocketCreateUDP (OOSOCKET* psocket)
|
||||
int ooSocketCreateUDP (OOSOCKET* psocket, int family)
|
||||
{
|
||||
int on;
|
||||
struct linger linger;
|
||||
OOSOCKET sock;
|
||||
|
||||
OOSOCKET sock = socket (AF_INET,
|
||||
if (family == 6)
|
||||
sock = socket (AF_INET6,
|
||||
SOCK_DGRAM,
|
||||
0);
|
||||
else
|
||||
sock = socket (AF_INET,
|
||||
SOCK_DGRAM,
|
||||
0);
|
||||
|
||||
|
@ -272,7 +293,10 @@ int ooSocketClose (OOSOCKET socket)
|
|||
|
||||
int ooSocketBind (OOSOCKET socket, OOIPADDR addr, int port)
|
||||
{
|
||||
struct sockaddr_in m_addr;
|
||||
struct ast_sockaddr m_addr;
|
||||
|
||||
memset(&m_addr, 0, sizeof(m_addr));
|
||||
|
||||
|
||||
if (socket == OOSOCKET_INVALID)
|
||||
{
|
||||
|
@ -280,14 +304,10 @@ int ooSocketBind (OOSOCKET socket, OOIPADDR addr, int port)
|
|||
return ASN_E_INVSOCKET;
|
||||
}
|
||||
|
||||
memset (&m_addr, 0, sizeof (m_addr));
|
||||
m_addr.sin_family = AF_INET;
|
||||
m_addr.sin_addr.s_addr = (addr == 0) ? INADDR_ANY : htonl (addr);
|
||||
m_addr.sin_port = htons ((unsigned short)port);
|
||||
ast_sockaddr_copy(&m_addr, &addr);
|
||||
ast_sockaddr_set_port(&m_addr, port);
|
||||
|
||||
if (bind (socket, (struct sockaddr *) (void*) &m_addr,
|
||||
sizeof (m_addr)) == -1)
|
||||
{
|
||||
if (ast_bind(socket, &m_addr) < 0) {
|
||||
if (errno != EADDRINUSE) {
|
||||
perror ("bind");
|
||||
OOTRACEERR2("Error:Bind failed, error: %d\n", errno);
|
||||
|
@ -311,20 +331,17 @@ int ooSocketGetSockName(OOSOCKET socket, struct sockaddr_in *name, socklen_t *si
|
|||
}
|
||||
}
|
||||
|
||||
int ooSocketGetIpAndPort(OOSOCKET socket, char *ip, int len, int *port)
|
||||
int ooSocketGetIpAndPort(OOSOCKET socket, char *ip, int len, int *port, int *family)
|
||||
{
|
||||
int ret=ASN_OK;
|
||||
socklen_t size;
|
||||
struct sockaddr_in addr;
|
||||
struct ast_sockaddr addr;
|
||||
const char *host=NULL;
|
||||
|
||||
size = sizeof(addr);
|
||||
|
||||
ret = ooSocketGetSockName(socket, &addr, &size);
|
||||
ret = ast_getsockname(socket, &addr);
|
||||
if(ret != 0)
|
||||
return ASN_E_INVSOCKET;
|
||||
|
||||
host = ast_inet_ntoa(addr.sin_addr);
|
||||
host = ast_sockaddr_stringify_addr(&addr);
|
||||
|
||||
if(host && strlen(host) < (unsigned)len)
|
||||
strcpy(ip, host);
|
||||
|
@ -333,8 +350,14 @@ int ooSocketGetIpAndPort(OOSOCKET socket, char *ip, int len, int *port)
|
|||
"ooSocketGetIpAndPort\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
*port = addr.sin_port;
|
||||
*port = ast_sockaddr_port(&addr);
|
||||
|
||||
if (family) {
|
||||
if (ast_sockaddr_is_ipv6(&addr) && !ast_sockaddr_is_ipv4_mapped(&addr))
|
||||
*family = 6;
|
||||
else
|
||||
*family = 4;
|
||||
}
|
||||
|
||||
return ASN_OK;
|
||||
}
|
||||
|
@ -350,29 +373,30 @@ int ooSocketListen (OOSOCKET socket, int maxConnection)
|
|||
}
|
||||
|
||||
int ooSocketAccept (OOSOCKET socket, OOSOCKET *pNewSocket,
|
||||
OOIPADDR* destAddr, int* destPort)
|
||||
char* destAddr, int* destPort)
|
||||
{
|
||||
struct sockaddr_in m_addr;
|
||||
OOSOCKLEN addr_length = sizeof (m_addr);
|
||||
struct ast_sockaddr addr;
|
||||
char* host = NULL;
|
||||
|
||||
if (socket == OOSOCKET_INVALID) return ASN_E_INVSOCKET;
|
||||
if (pNewSocket == 0) return ASN_E_INVPARAM;
|
||||
|
||||
*pNewSocket = accept (socket, (struct sockaddr *) (void*) &m_addr,
|
||||
&addr_length);
|
||||
*pNewSocket = ast_accept (socket, &addr);
|
||||
if (*pNewSocket <= 0) return ASN_E_INVSOCKET;
|
||||
|
||||
if (destAddr != 0)
|
||||
*destAddr = ntohl (m_addr.sin_addr.s_addr);
|
||||
if (destAddr != 0) {
|
||||
if ((host = ast_sockaddr_stringify_addr(&addr)) != NULL);
|
||||
strncpy(destAddr, host, strlen(host));
|
||||
}
|
||||
if (destPort != 0)
|
||||
*destPort = ntohs (m_addr.sin_port);
|
||||
*destPort = ast_sockaddr_port(&addr);
|
||||
|
||||
return ASN_OK;
|
||||
}
|
||||
|
||||
int ooSocketConnect (OOSOCKET socket, const char* host, int port)
|
||||
{
|
||||
struct sockaddr_in m_addr;
|
||||
struct ast_sockaddr m_addr;
|
||||
|
||||
if (socket == OOSOCKET_INVALID)
|
||||
{
|
||||
|
@ -380,13 +404,10 @@ int ooSocketConnect (OOSOCKET socket, const char* host, int port)
|
|||
}
|
||||
|
||||
memset (&m_addr, 0, sizeof (m_addr));
|
||||
ast_parse_arg(host, PARSE_ADDR, &m_addr);
|
||||
ast_sockaddr_set_port(&m_addr, port);
|
||||
|
||||
m_addr.sin_family = AF_INET;
|
||||
m_addr.sin_port = htons ((unsigned short)port);
|
||||
m_addr.sin_addr.s_addr = inet_addr (host);
|
||||
|
||||
if (connect (socket, (struct sockaddr *) (void*) &m_addr,
|
||||
sizeof (struct sockaddr_in)) == -1)
|
||||
if (ast_connect(socket, &m_addr))
|
||||
{
|
||||
return ASN_E_INVSOCKET;
|
||||
}
|
||||
|
@ -522,10 +543,18 @@ int ooGetLocalIPAddress(char * pIPAddrs)
|
|||
ret = gethostname(hostname, 100);
|
||||
if(ret == 0)
|
||||
{
|
||||
if (!(hp = ast_gethostbyname(hostname, &phost))) {
|
||||
struct in_addr i;
|
||||
memcpy(&i, hp->h_addr, sizeof(i));
|
||||
strcpy(pIPAddrs, (ast_inet_ntoa(i) == NULL) ? "127.0.0.1" : ast_inet_ntoa(i));
|
||||
if ((hp = ast_gethostbyname(hostname, &phost))) {
|
||||
if (hp->h_addrtype == AF_INET6) {
|
||||
struct in6_addr i;
|
||||
memcpy(&i, hp->h_addr, sizeof(i));
|
||||
strcpy(pIPAddrs, (inet_ntop(AF_INET6, &i,
|
||||
hostname, sizeof(hostname))) == NULL ? "::1" :
|
||||
inet_ntop(AF_INET6, &i, hostname, sizeof(hostname)));
|
||||
} else {
|
||||
struct in_addr i;
|
||||
memcpy(&i, hp->h_addr, sizeof(i));
|
||||
strcpy(pIPAddrs, (ast_inet_ntoa(i) == NULL) ? "127.0.0.1" : ast_inet_ntoa(i));
|
||||
}
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
@ -536,7 +565,7 @@ int ooGetLocalIPAddress(char * pIPAddrs)
|
|||
return ASN_OK;
|
||||
}
|
||||
|
||||
int ooSocketStrToAddr (const char* pIPAddrStr, OOIPADDR* pIPAddr)
|
||||
/* int ooSocketStrToAddr (const char* pIPAddrStr, OOIPADDR* pIPAddr)
|
||||
{
|
||||
int b1, b2, b3, b4;
|
||||
int rv = sscanf (pIPAddrStr, "%d.%d.%d.%d", &b1, &b2, &b3, &b4);
|
||||
|
@ -589,7 +618,7 @@ int ooSocketAddrToStr (OOIPADDR ipAddr, char* pbuf, int bufsize)
|
|||
return ASN_E_BUFOVFLW;
|
||||
sprintf (pbuf, "%s.%s.%s.%s", buf1, buf2, buf3, buf4);
|
||||
return ASN_OK;
|
||||
}
|
||||
} */
|
||||
|
||||
int ooSocketsCleanup (void)
|
||||
{
|
||||
|
@ -623,7 +652,7 @@ int ooSocketGetInterfaceList(OOCTXT *pctxt, OOInterface **ifList)
|
|||
struct sockaddr_in sin;
|
||||
|
||||
OOTRACEDBGA1("Retrieving local interfaces\n");
|
||||
if(ooSocketCreateUDP(&sock)!= ASN_OK)
|
||||
if(ooSocketCreateUDP(&sock, 4)!= ASN_OK)
|
||||
{
|
||||
OOTRACEERR1("Error:Failed to create udp socket - "
|
||||
"ooSocketGetInterfaceList\n");
|
||||
|
|
|
@ -81,7 +81,8 @@ typedef int OOSOCKET; /**< Socket's handle */
|
|||
* address. The least significant 8 bits represent the last number of the IP
|
||||
* address.
|
||||
*/
|
||||
typedef unsigned long OOIPADDR;
|
||||
/* typedef unsigned long OOIPADDR; */
|
||||
typedef struct ast_sockaddr OOIPADDR;
|
||||
|
||||
#define OOIPADDR_ANY ((OOIPADDR)0)
|
||||
#define OOIPADDR_LOCAL ((OOIPADDR)0x7f000001UL) /* 127.0.0.1 */
|
||||
|
@ -115,7 +116,7 @@ typedef struct OOInterface{
|
|||
* negative return value is error.
|
||||
*/
|
||||
EXTERN int ooSocketAccept (OOSOCKET socket, OOSOCKET *pNewSocket,
|
||||
OOIPADDR* destAddr, int* destPort);
|
||||
char* destAddr, int* destPort);
|
||||
|
||||
/**
|
||||
* This function converts an IP address to its string representation.
|
||||
|
@ -177,10 +178,11 @@ EXTERN int ooSocketConnect (OOSOCKET socket, const char* host, int port);
|
|||
*
|
||||
* @param psocket The pointer to the socket's handle variable to receive
|
||||
* the handle of new socket.
|
||||
* @param family Which family socket will created
|
||||
* @return Completion status of operation: 0 (ASN_OK) = success,
|
||||
* negative return value is error.
|
||||
*/
|
||||
EXTERN int ooSocketCreate (OOSOCKET* psocket);
|
||||
EXTERN int ooSocketCreate (OOSOCKET* psocket, int family);
|
||||
|
||||
/**
|
||||
* This function creates a UDP datagram socket.
|
||||
|
@ -190,7 +192,7 @@ EXTERN int ooSocketCreate (OOSOCKET* psocket);
|
|||
* @return Completion status of operation: 0 (ASN_OK) = success,
|
||||
* negative return value is error.
|
||||
*/
|
||||
EXTERN int ooSocketCreateUDP (OOSOCKET* psocket);
|
||||
EXTERN int ooSocketCreateUDP (OOSOCKET* psocket, int family);
|
||||
|
||||
/**
|
||||
* This function initiates use of sockets by an application. This function must
|
||||
|
@ -351,7 +353,7 @@ EXTERN int ooPDWrite(struct pollfd *pfds, int nfds, int fd);
|
|||
* @return Completion status of operation: 0 (ASN_OK) = success,
|
||||
* negative return value is error.
|
||||
*/
|
||||
EXTERN int ooSocketStrToAddr (const char* pIPAddrStr, OOIPADDR* pIPAddr);
|
||||
/* EXTERN int ooSocketStrToAddr (const char* pIPAddrStr, OOIPADDR* pIPAddr); */
|
||||
|
||||
/**
|
||||
* This function converts an internet dotted ip address to network address
|
||||
|
@ -364,7 +366,7 @@ EXTERN int ooSocketStrToAddr (const char* pIPAddrStr, OOIPADDR* pIPAddr);
|
|||
* @return Completion status of operation: 0 (ASN_OK) = success,
|
||||
* negative return value is error.
|
||||
*/
|
||||
EXTERN int ooSocketConvertIpToNwAddr(char *inetIp, unsigned char *netIp);
|
||||
/* EXTERN int ooSocketConvertIpToNwAddr(char *inetIp, unsigned char *netIp); */
|
||||
|
||||
/**
|
||||
* This function retrives the IP address of the local host.
|
||||
|
@ -393,10 +395,11 @@ EXTERN short ooSocketHTONS(short val);
|
|||
* @param ip Buffer in which ip address will be returned.
|
||||
* @param len Length of the ip address buffer.
|
||||
* @param port Pointer to integer in which port number will be returned.
|
||||
* @param family Pointer to integer in which IP family (4 or 6) will be returned
|
||||
*
|
||||
* @return ASN_OK, on success; -ve on failed.
|
||||
*/
|
||||
EXTERN int ooSocketGetIpAndPort(OOSOCKET socket, char *ip, int len, int *port);
|
||||
EXTERN int ooSocketGetIpAndPort(OOSOCKET socket, char *ip, int len, int *port, int *family);
|
||||
|
||||
|
||||
EXTERN int ooSocketGetInterfaceList(OOCTXT *pctxt, OOInterface **ifList);
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
#include "asterisk.h"
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/poll-compat.h"
|
||||
#include "asterisk/config.h"
|
||||
#include "asterisk/netsock2.h"
|
||||
|
||||
#include "ooports.h"
|
||||
#include "oochannels.h"
|
||||
|
@ -31,6 +33,7 @@
|
|||
#include "ooh323ep.h"
|
||||
#include "ooStackCmds.h"
|
||||
#include "ooCmdChannel.h"
|
||||
#include "ooSocket.h"
|
||||
#include "ootypes.h"
|
||||
|
||||
|
||||
|
@ -60,7 +63,7 @@ int ooCreateH245Listener(OOH323CallData *call)
|
|||
int ret=0;
|
||||
OOSOCKET channelSocket=0;
|
||||
OOTRACEINFO1("Creating H245 listener\n");
|
||||
if((ret=ooSocketCreate (&channelSocket))!=ASN_OK)
|
||||
if((ret=ooSocketCreate (&channelSocket, call->versionIP))!=ASN_OK)
|
||||
{
|
||||
OOTRACEERR3("ERROR: Failed to create socket for H245 listener "
|
||||
"(%s, %s)\n", call->callType, call->callToken);
|
||||
|
@ -97,7 +100,7 @@ int ooCreateH245Connection(OOH323CallData *call)
|
|||
ooTimerCallback *cbData=NULL;
|
||||
|
||||
OOTRACEINFO1("Creating H245 Connection\n");
|
||||
if((ret=ooSocketCreate (&channelSocket))!=ASN_OK)
|
||||
if((ret=ooSocketCreate (&channelSocket, call->versionIP))!=ASN_OK)
|
||||
{
|
||||
OOTRACEERR3("ERROR:Failed to create socket for H245 connection "
|
||||
"(%s, %s)\n", call->callType, call->callToken);
|
||||
|
@ -241,7 +244,7 @@ int ooCreateH225Connection(OOH323CallData *call)
|
|||
int ret=0, i;
|
||||
OOSOCKET channelSocket=0;
|
||||
for (i=0;i<3;i++) {
|
||||
if((ret=ooSocketCreate (&channelSocket))!=ASN_OK)
|
||||
if((ret=ooSocketCreate (&channelSocket, call->versionIP))!=ASN_OK)
|
||||
{
|
||||
OOTRACEERR3("Failed to create socket for transmit H2250 channel (%s, %s)"
|
||||
"\n", call->callType, call->callToken);
|
||||
|
@ -285,9 +288,9 @@ int ooCreateH225Connection(OOH323CallData *call)
|
|||
}
|
||||
call->pH225Channel->port = ret;
|
||||
|
||||
OOTRACEINFO5("Trying to connect to remote endpoint(%s:%d) to setup "
|
||||
OOTRACEINFO6("Trying to connect to remote endpoint(%s:%d) (IPv%d) to setup "
|
||||
"H2250 channel (%s, %s)\n", call->remoteIP,
|
||||
call->remotePort, call->callType, call->callToken);
|
||||
call->remotePort, call->versionIP, call->callType, call->callToken);
|
||||
|
||||
if((ret=ooSocketConnect(channelSocket, call->remoteIP,
|
||||
call->remotePort))==ASN_OK)
|
||||
|
@ -298,13 +301,13 @@ int ooCreateH225Connection(OOH323CallData *call)
|
|||
"(%s, %s)\n", call->callType, call->callToken);
|
||||
|
||||
/* If multihomed, get ip from socket */
|
||||
if(!strcmp(call->localIP, "0.0.0.0"))
|
||||
if(!strcmp(call->localIP, "0.0.0.0") || !strcmp(call->localIP, "::"))
|
||||
{
|
||||
OOTRACEDBGA3("Determining IP address for outgoing call in "
|
||||
"multihomed mode. (%s, %s)\n", call->callType,
|
||||
call->callToken);
|
||||
ret = ooSocketGetIpAndPort(channelSocket, call->localIP, 20,
|
||||
&call->pH225Channel->port);
|
||||
ret = ooSocketGetIpAndPort(channelSocket, call->localIP, 2+8*4+7,
|
||||
&call->pH225Channel->port, NULL);
|
||||
if(ret != ASN_OK)
|
||||
{
|
||||
OOTRACEERR3("ERROR:Failed to retrieve local ip and port from "
|
||||
|
@ -367,12 +370,13 @@ int ooCreateH323Listener()
|
|||
OOIPADDR ipaddrs;
|
||||
|
||||
/* Create socket */
|
||||
if((ret=ooSocketCreate (&channelSocket))!=ASN_OK)
|
||||
ret = ast_parse_arg(gH323ep.signallingIP, PARSE_ADDR, &ipaddrs);
|
||||
if((ret=ooSocketCreate (&channelSocket, ast_sockaddr_is_ipv6(&ipaddrs) ? 6 : 4))
|
||||
!=ASN_OK)
|
||||
{
|
||||
OOTRACEERR1("Failed to create socket for H323 Listener\n");
|
||||
return OO_FAILED;
|
||||
}
|
||||
ret= ooSocketStrToAddr (gH323ep.signallingIP, &ipaddrs);
|
||||
if((ret=ooSocketBind (channelSocket, ipaddrs,
|
||||
gH323ep.listenPort))==ASN_OK)
|
||||
{
|
||||
|
@ -397,9 +401,12 @@ int ooAcceptH225Connection()
|
|||
OOH323CallData * call;
|
||||
int ret;
|
||||
char callToken[20];
|
||||
char remoteIP[2+8*4+7];
|
||||
OOSOCKET h225Channel=0;
|
||||
|
||||
memset(remoteIP, 0, sizeof(remoteIP));
|
||||
ret = ooSocketAccept (*(gH323ep.listener), &h225Channel,
|
||||
NULL, NULL);
|
||||
remoteIP, NULL);
|
||||
if(ret != ASN_OK)
|
||||
{
|
||||
OOTRACEERR1("Error:Accepting h225 connection\n");
|
||||
|
@ -421,29 +428,33 @@ int ooAcceptH225Connection()
|
|||
call->pH225Channel->sock = h225Channel;
|
||||
|
||||
/* If multihomed, get ip from socket */
|
||||
if(!strcmp(call->localIP, "0.0.0.0"))
|
||||
if(!strcmp(call->localIP, "0.0.0.0") || !strcmp(call->localIP,"::"))
|
||||
{
|
||||
OOTRACEDBGA3("Determining IP address for incoming call in multihomed "
|
||||
"mode (%s, %s)\n", call->callType, call->callToken);
|
||||
|
||||
ret = ooSocketGetIpAndPort(h225Channel, call->localIP, 20,
|
||||
&call->pH225Channel->port);
|
||||
if(ret != ASN_OK)
|
||||
{
|
||||
OOTRACEERR3("Error:Failed to retrieve local ip and port from "
|
||||
"socket for multihomed mode.(%s, %s)\n",
|
||||
call->callType, call->callToken);
|
||||
if(call->callState < OO_CALL_CLEAR)
|
||||
{ /* transport failure */
|
||||
call->callState = OO_CALL_CLEAR;
|
||||
call->callEndReason = OO_REASON_TRANSPORTFAILURE;
|
||||
}
|
||||
ast_mutex_unlock(&call->Lock);
|
||||
return OO_FAILED;
|
||||
}
|
||||
ret = ooSocketGetIpAndPort(h225Channel, call->localIP, 2+8*4+7,
|
||||
&call->pH225Channel->port, &call->versionIP);
|
||||
if(ret != ASN_OK)
|
||||
{
|
||||
OOTRACEERR3("Error:Failed to retrieve local ip and port from "
|
||||
"socket for multihomed mode.(%s, %s)\n",
|
||||
call->callType, call->callToken);
|
||||
if(call->callState < OO_CALL_CLEAR)
|
||||
{ /* transport failure */
|
||||
call->callState = OO_CALL_CLEAR;
|
||||
call->callEndReason = OO_REASON_TRANSPORTFAILURE;
|
||||
}
|
||||
OOTRACEDBGA4("Using Local IP address %s for incoming call in multihomed "
|
||||
"mode. (%s, %s)\n", call->localIP, call->callType,
|
||||
call->callToken);
|
||||
ast_mutex_unlock(&call->Lock);
|
||||
return OO_FAILED;
|
||||
}
|
||||
OOTRACEDBGA5("Using Local IP address %s (IPv%d) for incoming call "
|
||||
"(%s, %s)\n", call->localIP, call->versionIP, call->callType,
|
||||
call->callToken);
|
||||
|
||||
if (remoteIP[0]) {
|
||||
strncpy(call->remoteIP, remoteIP, strlen(remoteIP));
|
||||
}
|
||||
|
||||
ast_mutex_unlock(&call->Lock);
|
||||
|
@ -658,7 +669,7 @@ int ooProcessCallFDSETsAndTimers
|
|||
"(%s, %s)\n", call->callType, call->callToken);
|
||||
if(call->callState < OO_CALL_CLEAR)
|
||||
{
|
||||
call->callEndReason = OO_REASON_INVALIDMESSAGE;
|
||||
if (!call->callEndReason) call->callEndReason = OO_REASON_INVALIDMESSAGE;
|
||||
call->callState = OO_CALL_CLEAR;
|
||||
}
|
||||
}
|
||||
|
@ -671,10 +682,11 @@ int ooProcessCallFDSETsAndTimers
|
|||
|
||||
if (0 != call->pH245Channel && 0 != call->pH245Channel->sock)
|
||||
{
|
||||
if(call->pH245Channel->outQueue.count>0)
|
||||
{
|
||||
if(ooPDWrite(pfds, nfds, call->pH245Channel->sock))
|
||||
ooSendMsg(call, OOH245MSG);
|
||||
if(ooPDWrite(pfds, nfds, call->pH245Channel->sock)) {
|
||||
while (call->pH245Channel->outQueue.count>0) {
|
||||
if (ooSendMsg(call, OOH245MSG) != OO_OK)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(call->h245listener)
|
||||
|
@ -691,20 +703,23 @@ int ooProcessCallFDSETsAndTimers
|
|||
{
|
||||
if(ooPDWrite(pfds, nfds, call->pH225Channel->sock))
|
||||
{
|
||||
if(call->pH225Channel->outQueue.count>0)
|
||||
while (call->pH225Channel->outQueue.count>0)
|
||||
{
|
||||
OOTRACEDBGC3("Sending H225 message (%s, %s)\n",
|
||||
call->callType, call->callToken);
|
||||
ooSendMsg(call, OOQ931MSG);
|
||||
if (ooSendMsg(call, OOQ931MSG) != OO_OK)
|
||||
break;
|
||||
}
|
||||
if(call->pH245Channel &&
|
||||
call->pH245Channel->outQueue.count>0 &&
|
||||
OO_TESTFLAG (call->flags, OO_M_TUNNELING))
|
||||
{
|
||||
OO_TESTFLAG (call->flags, OO_M_TUNNELING)) {
|
||||
while (call->pH245Channel->outQueue.count>0) {
|
||||
OOTRACEDBGC3("H245 message needs to be tunneled. "
|
||||
"(%s, %s)\n", call->callType,
|
||||
call->callToken);
|
||||
ooSendMsg(call, OOH245MSG);
|
||||
if (ooSendMsg(call, OOH245MSG) != OO_OK)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1319,7 +1334,7 @@ int ooSendMsg(OOH323CallData *call, int type)
|
|||
{
|
||||
OOTRACEDBGA3("Warning:Call marked for cleanup. Can not send message."
|
||||
"(%s, %s)\n", call->callType, call->callToken);
|
||||
return OO_OK;
|
||||
return OO_FAILED;
|
||||
}
|
||||
|
||||
if(type == OOQ931MSG)
|
||||
|
@ -1393,7 +1408,8 @@ int ooSendMsg(OOH323CallData *call, int type)
|
|||
{
|
||||
call->callEndReason = OO_REASON_TRANSPORTFAILURE;
|
||||
call->callState = OO_CALL_CLEAR;
|
||||
}
|
||||
} else if (call->callState == OO_CALL_CLEAR)
|
||||
call->callState = OO_CALL_CLEAR_RELEASESENT;
|
||||
return OO_FAILED;
|
||||
}
|
||||
}/* end of type==OOQ931MSG */
|
||||
|
|
|
@ -1559,7 +1559,8 @@ int ooHandleOpenLogicalChannel_helper(OOH323CallData *call,
|
|||
H245H2250LogicalChannelAckParameters *h2250lcap=NULL;
|
||||
OOCTXT *pctxt;
|
||||
H245UnicastAddress *unicastAddrs, *unicastAddrs1;
|
||||
H245UnicastAddress_iPAddress *iPAddress, *iPAddress1;
|
||||
H245UnicastAddress_iPAddress *iPAddress = NULL, *iPAddress1 = NULL;
|
||||
H245UnicastAddress_iP6Address *iP6Address = NULL, *iP6Address1 = NULL;
|
||||
ooLogicalChannel *pLogicalChannel = NULL;
|
||||
H245H2250LogicalChannelParameters *h2250lcp=NULL;
|
||||
H245OpenLogicalChannel_forwardLogicalChannelParameters *flcp =
|
||||
|
@ -1637,11 +1638,20 @@ int ooHandleOpenLogicalChannel_helper(OOH323CallData *call,
|
|||
|
||||
unicastAddrs = h2250lcap->mediaChannel.u.unicastAddress;
|
||||
memset(unicastAddrs, 0, sizeof(H245UnicastAddress));
|
||||
unicastAddrs->t = T_H245UnicastAddress_iPAddress;
|
||||
unicastAddrs->u.iPAddress = (H245UnicastAddress_iPAddress*)
|
||||
|
||||
if (call->versionIP == 6) {
|
||||
unicastAddrs->t = T_H245UnicastAddress_iP6Address;
|
||||
unicastAddrs->u.iP6Address = (H245UnicastAddress_iP6Address*)
|
||||
memAlloc(pctxt, sizeof(H245UnicastAddress_iP6Address));
|
||||
iP6Address = unicastAddrs->u.iP6Address;
|
||||
memset(iP6Address, 0, sizeof(H245UnicastAddress_iP6Address));
|
||||
} else {
|
||||
unicastAddrs->t = T_H245UnicastAddress_iPAddress;
|
||||
unicastAddrs->u.iPAddress = (H245UnicastAddress_iPAddress*)
|
||||
memAlloc(pctxt, sizeof(H245UnicastAddress_iPAddress));
|
||||
iPAddress = unicastAddrs->u.iPAddress;
|
||||
memset(iPAddress, 0, sizeof(H245UnicastAddress_iPAddress));
|
||||
iPAddress = unicastAddrs->u.iPAddress;
|
||||
memset(iPAddress, 0, sizeof(H245UnicastAddress_iPAddress));
|
||||
}
|
||||
|
||||
pLogicalChannel = ooAddNewLogicalChannel(call,
|
||||
olc->forwardLogicalChannelNumber, h2250lcap->sessionID,
|
||||
|
@ -1652,10 +1662,16 @@ int ooHandleOpenLogicalChannel_helper(OOH323CallData *call,
|
|||
"(%s, %s)\n", call->callType, call->callToken);
|
||||
return OO_FAILED;
|
||||
}
|
||||
ooSocketConvertIpToNwAddr(call->localIP, iPAddress->network.data);
|
||||
|
||||
iPAddress->network.numocts = 4;
|
||||
iPAddress->tsapIdentifier = pLogicalChannel->localRtpPort;
|
||||
if (call->versionIP == 6) {
|
||||
inet_pton(AF_INET6, call->localIP, iP6Address->network.data);
|
||||
iP6Address->network.numocts = 16;
|
||||
iP6Address->tsapIdentifier = pLogicalChannel->localRtpPort;
|
||||
} else {
|
||||
inet_pton(AF_INET, call->localIP, iPAddress->network.data);
|
||||
iPAddress->network.numocts = 4;
|
||||
iPAddress->tsapIdentifier = pLogicalChannel->localRtpPort;
|
||||
}
|
||||
|
||||
/* media contrcol channel */
|
||||
h2250lcap->mediaControlChannel.t =
|
||||
|
@ -1664,17 +1680,28 @@ int ooHandleOpenLogicalChannel_helper(OOH323CallData *call,
|
|||
ASN1MALLOC(pctxt, sizeof(H245UnicastAddress));
|
||||
|
||||
unicastAddrs1 = h2250lcap->mediaControlChannel.u.unicastAddress;
|
||||
|
||||
memset(unicastAddrs1, 0, sizeof(H245UnicastAddress));
|
||||
unicastAddrs1->t = T_H245UnicastAddress_iPAddress;
|
||||
unicastAddrs1->u.iPAddress = (H245UnicastAddress_iPAddress*)
|
||||
memAlloc(pctxt, sizeof(H245UnicastAddress_iPAddress));
|
||||
iPAddress1 = unicastAddrs1->u.iPAddress;
|
||||
memset(iPAddress1, 0, sizeof(H245UnicastAddress_iPAddress));
|
||||
if (call->versionIP == 6) {
|
||||
unicastAddrs1->t = T_H245UnicastAddress_iP6Address;
|
||||
unicastAddrs1->u.iP6Address = (H245UnicastAddress_iP6Address*)
|
||||
memAlloc(pctxt, sizeof(H245UnicastAddress_iP6Address));
|
||||
iP6Address1 = unicastAddrs1->u.iP6Address;
|
||||
memset(iP6Address1, 0, sizeof(H245UnicastAddress_iP6Address));
|
||||
inet_pton(AF_INET6, call->localIP, iP6Address1->network.data);
|
||||
iP6Address1->network.numocts = 16;
|
||||
iP6Address1->tsapIdentifier = pLogicalChannel->localRtcpPort;
|
||||
} else {
|
||||
unicastAddrs1->t = T_H245UnicastAddress_iPAddress;
|
||||
unicastAddrs1->u.iPAddress = (H245UnicastAddress_iPAddress*)
|
||||
memAlloc(pctxt, sizeof(H245UnicastAddress_iPAddress));
|
||||
iPAddress1 = unicastAddrs1->u.iPAddress;
|
||||
memset(iPAddress1, 0, sizeof(H245UnicastAddress_iPAddress));
|
||||
|
||||
ooSocketConvertIpToNwAddr(call->localIP, iPAddress1->network.data);
|
||||
|
||||
iPAddress1->network.numocts = 4;
|
||||
iPAddress1->tsapIdentifier = pLogicalChannel->localRtcpPort;
|
||||
inet_pton(AF_INET, call->localIP, iPAddress1->network.data);
|
||||
iPAddress1->network.numocts = 4;
|
||||
iPAddress1->tsapIdentifier = pLogicalChannel->localRtcpPort;
|
||||
}
|
||||
|
||||
OOTRACEDBGA3("Built OpenLogicalChannelAck (%s, %s)\n", call->callType,
|
||||
call->callToken);
|
||||
|
@ -1765,14 +1792,16 @@ int ooSendOpenLogicalChannelReject
|
|||
int ooOnReceivedOpenLogicalChannelAck(OOH323CallData *call,
|
||||
H245OpenLogicalChannelAck *olcAck)
|
||||
{
|
||||
char remoteip[20];
|
||||
char remoteip[2+8*4+7];
|
||||
regmatch_t pmatch[1];
|
||||
ooLogicalChannel *pLogicalChannel;
|
||||
H245H2250LogicalChannelAckParameters *h2250lcap;
|
||||
H245UnicastAddress *unicastAddr;
|
||||
H245UnicastAddress_iPAddress *iPAddress;
|
||||
H245UnicastAddress_iPAddress *iPAddress = NULL;
|
||||
H245UnicastAddress_iP6Address *iP6Address = NULL;
|
||||
H245UnicastAddress *unicastAddr1;
|
||||
H245UnicastAddress_iPAddress *iPAddress1 = NULL;
|
||||
H245UnicastAddress_iP6Address *iP6Address1 = NULL;
|
||||
|
||||
if(!((olcAck->m.forwardMultiplexAckParametersPresent == 1) &&
|
||||
(olcAck->forwardMultiplexAckParameters.t ==
|
||||
|
@ -1802,19 +1831,28 @@ int ooOnReceivedOpenLogicalChannelAck(OOH323CallData *call,
|
|||
}
|
||||
|
||||
unicastAddr = h2250lcap->mediaChannel.u.unicastAddress;
|
||||
if(unicastAddr->t != T_H245UnicastAddress_iPAddress)
|
||||
{
|
||||
OOTRACEERR3("Error: Processing OpenLogicalChannelAck - media channel "
|
||||
if (call->versionIP == 6) {
|
||||
if(unicastAddr->t != T_H245UnicastAddress_iP6Address)
|
||||
{
|
||||
OOTRACEERR3("Error: Processing OpenLogicalChannelAck - media channel "
|
||||
"address type is not IP6 (%s, %s)\n", call->callType,
|
||||
call->callToken);
|
||||
return OO_FAILED;
|
||||
}
|
||||
iP6Address = unicastAddr->u.iP6Address;
|
||||
inet_ntop(AF_INET6, iP6Address->network.data, remoteip, sizeof(remoteip));
|
||||
|
||||
} else {
|
||||
if(unicastAddr->t != T_H245UnicastAddress_iPAddress)
|
||||
{
|
||||
OOTRACEERR3("Error: Processing OpenLogicalChannelAck - media channel "
|
||||
"address type is not IP (%s, %s)\n", call->callType,
|
||||
call->callToken);
|
||||
return OO_FAILED;
|
||||
return OO_FAILED;
|
||||
}
|
||||
iPAddress = unicastAddr->u.iPAddress;
|
||||
inet_ntop(AF_INET, iPAddress->network.data, remoteip, sizeof(remoteip));
|
||||
}
|
||||
iPAddress = unicastAddr->u.iPAddress;
|
||||
|
||||
sprintf(remoteip,"%d.%d.%d.%d", iPAddress->network.data[0],
|
||||
iPAddress->network.data[1],
|
||||
iPAddress->network.data[2],
|
||||
iPAddress->network.data[3]);
|
||||
|
||||
/* Extract media control channel address */
|
||||
if(h2250lcap->m.mediaControlChannelPresent == 1) {
|
||||
|
@ -1828,14 +1866,23 @@ int ooOnReceivedOpenLogicalChannelAck(OOH323CallData *call,
|
|||
}
|
||||
|
||||
unicastAddr1 = h2250lcap->mediaControlChannel.u.unicastAddress;
|
||||
if(unicastAddr1->t != T_H245UnicastAddress_iPAddress) {
|
||||
OOTRACEERR3("Error: Processing OpenLogicalChannelAck - media control "
|
||||
"channel address type is not IP (%s, %s)\n", call->callType,
|
||||
call->callToken);
|
||||
return OO_FAILED;
|
||||
}
|
||||
|
||||
iPAddress1 = unicastAddr1->u.iPAddress;
|
||||
if (call->versionIP == 6) {
|
||||
if(unicastAddr1->t != T_H245UnicastAddress_iP6Address) {
|
||||
OOTRACEERR3("Error: Processing OpenLogicalChannelAck - media control "
|
||||
"channel address type is not IP6 (%s, %s)\n", call->callType,
|
||||
call->callToken);
|
||||
return OO_FAILED;
|
||||
}
|
||||
iP6Address1 = unicastAddr1->u.iP6Address;
|
||||
} else {
|
||||
if(unicastAddr1->t != T_H245UnicastAddress_iPAddress) {
|
||||
OOTRACEERR3("Error: Processing OpenLogicalChannelAck - media control "
|
||||
"channel address type is not IP (%s, %s)\n", call->callType,
|
||||
call->callToken);
|
||||
return OO_FAILED;
|
||||
}
|
||||
iPAddress1 = unicastAddr1->u.iPAddress;
|
||||
}
|
||||
} else {
|
||||
OOTRACEDBGA3("Warning: Processing OpenLogicalChannelAck - Missing media "
|
||||
"control channel (%s, %s)\n", call->callType, call->callToken);
|
||||
|
@ -1870,10 +1917,15 @@ int ooOnReceivedOpenLogicalChannelAck(OOH323CallData *call,
|
|||
}
|
||||
|
||||
strcpy(pLogicalChannel->remoteIP, remoteip);
|
||||
pLogicalChannel->remoteMediaPort = iPAddress->tsapIdentifier;
|
||||
if (iPAddress1)
|
||||
pLogicalChannel->remoteMediaControlPort = iPAddress1->tsapIdentifier;
|
||||
|
||||
if (call->versionIP == 6) {
|
||||
pLogicalChannel->remoteMediaPort = iP6Address->tsapIdentifier;
|
||||
if (iP6Address1)
|
||||
pLogicalChannel->remoteMediaControlPort = iP6Address1->tsapIdentifier;
|
||||
} else {
|
||||
pLogicalChannel->remoteMediaPort = iPAddress->tsapIdentifier;
|
||||
if (iPAddress1)
|
||||
pLogicalChannel->remoteMediaControlPort = iPAddress1->tsapIdentifier;
|
||||
}
|
||||
if(pLogicalChannel->chanCap->startTransmitChannel)
|
||||
{
|
||||
pLogicalChannel->chanCap->startTransmitChannel(call, pLogicalChannel);
|
||||
|
@ -2074,6 +2126,8 @@ int ooHandleH245Command(OOH323CallData *call,
|
|||
ooClearAllLogicalChannels(call);
|
||||
}
|
||||
ooSendEndSessionCommand(call);
|
||||
if (call->callState < OO_CALL_CLEAR)
|
||||
call->callState = OO_CALL_CLEAR;
|
||||
}
|
||||
|
||||
|
||||
|
@ -3613,6 +3667,7 @@ int ooOpenChannel(OOH323CallData* call, ooH323EpCapability *epCap)
|
|||
H245H2250LogicalChannelParameters *h2250lcp = NULL;
|
||||
H245UnicastAddress *unicastAddrs = NULL;
|
||||
H245UnicastAddress_iPAddress *iPAddress = NULL;
|
||||
H245UnicastAddress_iP6Address *iP6Address = NULL;
|
||||
unsigned session_id=0;
|
||||
ooLogicalChannel *pLogicalChannel = NULL;
|
||||
|
||||
|
@ -3756,16 +3811,27 @@ int ooOpenChannel(OOH323CallData* call, ooH323EpCapability *epCap)
|
|||
|
||||
unicastAddrs = h2250lcp->mediaControlChannel.u.unicastAddress;
|
||||
memset(unicastAddrs, 0, sizeof(H245UnicastAddress));
|
||||
unicastAddrs->t = T_H245UnicastAddress_iPAddress;
|
||||
unicastAddrs->u.iPAddress = (H245UnicastAddress_iPAddress*)
|
||||
if (call->versionIP == 6) {
|
||||
unicastAddrs->t = T_H245UnicastAddress_iP6Address;
|
||||
unicastAddrs->u.iP6Address = (H245UnicastAddress_iP6Address*)
|
||||
ASN1MALLOC(pctxt, sizeof(H245UnicastAddress_iP6Address));
|
||||
iP6Address = unicastAddrs->u.iP6Address;
|
||||
memset(iP6Address, 0, sizeof(H245UnicastAddress_iP6Address));
|
||||
|
||||
inet_pton(AF_INET6, pLogicalChannel->localIP, iP6Address->network.data);
|
||||
iP6Address->network.numocts = 16;
|
||||
iP6Address->tsapIdentifier = pLogicalChannel->localRtcpPort;
|
||||
} else {
|
||||
unicastAddrs->t = T_H245UnicastAddress_iPAddress;
|
||||
unicastAddrs->u.iPAddress = (H245UnicastAddress_iPAddress*)
|
||||
ASN1MALLOC(pctxt, sizeof(H245UnicastAddress_iPAddress));
|
||||
iPAddress = unicastAddrs->u.iPAddress;
|
||||
memset(iPAddress, 0, sizeof(H245UnicastAddress_iPAddress));
|
||||
iPAddress = unicastAddrs->u.iPAddress;
|
||||
memset(iPAddress, 0, sizeof(H245UnicastAddress_iPAddress));
|
||||
|
||||
ooSocketConvertIpToNwAddr(pLogicalChannel->localIP,iPAddress->network.data);
|
||||
|
||||
iPAddress->network.numocts = 4;
|
||||
iPAddress->tsapIdentifier = pLogicalChannel->localRtcpPort;
|
||||
inet_pton(AF_INET, pLogicalChannel->localIP, iPAddress->network.data);
|
||||
iPAddress->network.numocts = 4;
|
||||
iPAddress->tsapIdentifier = pLogicalChannel->localRtcpPort;
|
||||
}
|
||||
pLogicalChannel->state = OO_LOGICALCHAN_PROPOSED;
|
||||
OOTRACEDBGA4("Built OpenLogicalChannel-%s (%s, %s)\n",
|
||||
ooGetCapTypeText(epCap->cap), call->callType,
|
||||
|
@ -3798,6 +3864,7 @@ int ooBuildFastStartOLC
|
|||
H245H2250LogicalChannelParameters *pH2250lcp1=NULL, *pH2250lcp2=NULL;
|
||||
H245UnicastAddress *pUnicastAddrs=NULL, *pUniAddrs=NULL;
|
||||
H245UnicastAddress_iPAddress *pIpAddrs=NULL, *pUniIpAddrs=NULL;
|
||||
H245UnicastAddress_iP6Address *pIp6Addrs=NULL, *pUniIp6Addrs=NULL;
|
||||
unsigned session_id = 0;
|
||||
ooLogicalChannel *pLogicalChannel = NULL;
|
||||
int outgoing=FALSE;
|
||||
|
@ -3880,17 +3947,29 @@ int ooBuildFastStartOLC
|
|||
sizeof(H245UnicastAddress));
|
||||
memset(pUniAddrs, 0, sizeof(H245UnicastAddress));
|
||||
pH2250lcp1->mediaChannel.u.unicastAddress = pUniAddrs;
|
||||
pUniAddrs->t = T_H245UnicastAddress_iPAddress;
|
||||
pUniIpAddrs = (H245UnicastAddress_iPAddress*) ASN1MALLOC(pctxt,
|
||||
sizeof(H245UnicastAddress_iPAddress));
|
||||
memset(pUniIpAddrs, 0, sizeof(H245UnicastAddress_iPAddress));
|
||||
pUniAddrs->u.iPAddress = pUniIpAddrs;
|
||||
if (call->versionIP == 6) {
|
||||
pUniAddrs->t = T_H245UnicastAddress_iP6Address;
|
||||
pUniIp6Addrs = (H245UnicastAddress_iP6Address*) ASN1MALLOC(pctxt,
|
||||
sizeof(H245UnicastAddress_iP6Address));
|
||||
memset(pUniIp6Addrs, 0, sizeof(H245UnicastAddress_iP6Address));
|
||||
pUniAddrs->u.iP6Address = pUniIp6Addrs;
|
||||
|
||||
ooSocketConvertIpToNwAddr(pLogicalChannel->localIP,
|
||||
pUniIpAddrs->network.data);
|
||||
inet_pton(AF_INET6, pLogicalChannel->localIP, pUniIp6Addrs->network.data);
|
||||
|
||||
pUniIpAddrs->network.numocts = 4;
|
||||
pUniIpAddrs->tsapIdentifier = pLogicalChannel->localRtpPort;
|
||||
pUniIp6Addrs->network.numocts = 16;
|
||||
pUniIp6Addrs->tsapIdentifier = pLogicalChannel->localRtpPort;
|
||||
} else {
|
||||
pUniAddrs->t = T_H245UnicastAddress_iPAddress;
|
||||
pUniIpAddrs = (H245UnicastAddress_iPAddress*) ASN1MALLOC(pctxt,
|
||||
sizeof(H245UnicastAddress_iPAddress));
|
||||
memset(pUniIpAddrs, 0, sizeof(H245UnicastAddress_iPAddress));
|
||||
pUniAddrs->u.iPAddress = pUniIpAddrs;
|
||||
|
||||
inet_pton(AF_INET, pLogicalChannel->localIP, pUniIpAddrs->network.data);
|
||||
|
||||
pUniIpAddrs->network.numocts = 4;
|
||||
pUniIpAddrs->tsapIdentifier = pLogicalChannel->localRtpPort;
|
||||
}
|
||||
}
|
||||
pH2250lcp1->m.mediaControlChannelPresent = 1;
|
||||
pH2250lcp1->mediaControlChannel.t =
|
||||
|
@ -3899,17 +3978,30 @@ int ooBuildFastStartOLC
|
|||
sizeof(H245UnicastAddress));
|
||||
memset(pUnicastAddrs, 0, sizeof(H245UnicastAddress));
|
||||
pH2250lcp1->mediaControlChannel.u.unicastAddress = pUnicastAddrs;
|
||||
pUnicastAddrs->t = T_H245UnicastAddress_iPAddress;
|
||||
pIpAddrs = (H245UnicastAddress_iPAddress*) ASN1MALLOC(pctxt,
|
||||
sizeof(H245UnicastAddress_iPAddress));
|
||||
memset(pIpAddrs, 0, sizeof(H245UnicastAddress_iPAddress));
|
||||
pUnicastAddrs->u.iPAddress = pIpAddrs;
|
||||
if (call->versionIP == 6) {
|
||||
pUnicastAddrs->t = T_H245UnicastAddress_iP6Address;
|
||||
pIp6Addrs = (H245UnicastAddress_iP6Address*) ASN1MALLOC(pctxt,
|
||||
sizeof(H245UnicastAddress_iP6Address));
|
||||
memset(pIp6Addrs, 0, sizeof(H245UnicastAddress_iP6Address));
|
||||
pUnicastAddrs->u.iP6Address = pIp6Addrs;
|
||||
|
||||
ooSocketConvertIpToNwAddr(pLogicalChannel->localIP,
|
||||
pIpAddrs->network.data);
|
||||
inet_pton(AF_INET6, pLogicalChannel->localIP, pIp6Addrs->network.data);
|
||||
|
||||
pIp6Addrs->network.numocts = 16;
|
||||
pIp6Addrs->tsapIdentifier = pLogicalChannel->localRtcpPort;
|
||||
} else {
|
||||
pUnicastAddrs->t = T_H245UnicastAddress_iPAddress;
|
||||
pIpAddrs = (H245UnicastAddress_iPAddress*) ASN1MALLOC(pctxt,
|
||||
sizeof(H245UnicastAddress_iPAddress));
|
||||
memset(pIpAddrs, 0, sizeof(H245UnicastAddress_iPAddress));
|
||||
pUnicastAddrs->u.iPAddress = pIpAddrs;
|
||||
|
||||
inet_pton(AF_INET, pLogicalChannel->localIP, pIpAddrs->network.data);
|
||||
|
||||
pIpAddrs->network.numocts = 4;
|
||||
pIpAddrs->tsapIdentifier = pLogicalChannel->localRtcpPort;
|
||||
}
|
||||
|
||||
pIpAddrs->network.numocts = 4;
|
||||
pIpAddrs->tsapIdentifier = pLogicalChannel->localRtcpPort;
|
||||
if(!outgoing)
|
||||
{
|
||||
if(epCap->startReceiveChannel)
|
||||
|
@ -3972,18 +4064,33 @@ int ooBuildFastStartOLC
|
|||
sizeof(H245UnicastAddress));
|
||||
memset(pUnicastAddrs, 0, sizeof(H245UnicastAddress));
|
||||
pH2250lcp2->mediaChannel.u.unicastAddress = pUnicastAddrs;
|
||||
|
||||
/* May 20101022 */
|
||||
|
||||
pUnicastAddrs->t = T_H245UnicastAddress_iPAddress;
|
||||
pIpAddrs = (H245UnicastAddress_iPAddress*) memAlloc(pctxt,
|
||||
if (call->versionIP == 6) {
|
||||
pUnicastAddrs->t = T_H245UnicastAddress_iP6Address;
|
||||
pIp6Addrs = (H245UnicastAddress_iP6Address*) ASN1MALLOC(pctxt,
|
||||
sizeof(H245UnicastAddress_iP6Address));
|
||||
memset(pIp6Addrs, 0, sizeof(H245UnicastAddress_iP6Address));
|
||||
pUnicastAddrs->u.iP6Address = pIp6Addrs;
|
||||
|
||||
inet_pton(AF_INET6, pLogicalChannel->localIP, pIp6Addrs->network.data);
|
||||
|
||||
pIp6Addrs->network.numocts = 16;
|
||||
pIp6Addrs->tsapIdentifier = pLogicalChannel->localRtpPort;
|
||||
} else {
|
||||
pUnicastAddrs->t = T_H245UnicastAddress_iPAddress;
|
||||
pIpAddrs = (H245UnicastAddress_iPAddress*) ASN1MALLOC(pctxt,
|
||||
sizeof(H245UnicastAddress_iPAddress));
|
||||
memset(pIpAddrs, 0, sizeof(H245UnicastAddress_iPAddress));
|
||||
pUnicastAddrs->u.iPAddress = pIpAddrs;
|
||||
memset(pIpAddrs, 0, sizeof(H245UnicastAddress_iPAddress));
|
||||
pUnicastAddrs->u.iPAddress = pIpAddrs;
|
||||
|
||||
inet_pton(AF_INET, pLogicalChannel->localIP, pIpAddrs->network.data);
|
||||
|
||||
ooSocketConvertIpToNwAddr(pLogicalChannel->localIP,
|
||||
pIpAddrs->network.data);
|
||||
pIpAddrs->network.numocts = 4;
|
||||
pIpAddrs->tsapIdentifier = pLogicalChannel->localRtpPort;
|
||||
}
|
||||
|
||||
pIpAddrs->network.numocts = 4;
|
||||
pIpAddrs->tsapIdentifier = pLogicalChannel->localRtpPort;
|
||||
}
|
||||
pH2250lcp2->m.mediaControlChannelPresent = 1;
|
||||
pH2250lcp2->mediaControlChannel.t =
|
||||
|
@ -3993,17 +4100,32 @@ int ooBuildFastStartOLC
|
|||
memset(pUniAddrs, 0, sizeof(H245UnicastAddress));
|
||||
pH2250lcp2->mediaControlChannel.u.unicastAddress = pUniAddrs;
|
||||
|
||||
/* May 20101023 */
|
||||
|
||||
pUniAddrs->t = T_H245UnicastAddress_iPAddress;
|
||||
pUniIpAddrs = (H245UnicastAddress_iPAddress*) ASN1MALLOC(pctxt, sizeof(H245UnicastAddress_iPAddress));
|
||||
memset(pUniIpAddrs, 0, sizeof(H245UnicastAddress_iPAddress));
|
||||
pUniAddrs->u.iPAddress = pUniIpAddrs;
|
||||
if (call->versionIP == 6) {
|
||||
pUniAddrs->t = T_H245UnicastAddress_iP6Address;
|
||||
pUniIp6Addrs = (H245UnicastAddress_iP6Address*) ASN1MALLOC(pctxt,
|
||||
sizeof(H245UnicastAddress_iP6Address));
|
||||
memset(pUniIp6Addrs, 0, sizeof(H245UnicastAddress_iP6Address));
|
||||
pUniAddrs->u.iP6Address = pUniIp6Addrs;
|
||||
|
||||
inet_pton(AF_INET6, pLogicalChannel->localIP, pUniIp6Addrs->network.data);
|
||||
|
||||
pUniIp6Addrs->network.numocts = 16;
|
||||
pUniIp6Addrs->tsapIdentifier = pLogicalChannel->localRtcpPort;
|
||||
} else {
|
||||
pUniAddrs->t = T_H245UnicastAddress_iPAddress;
|
||||
pUniIpAddrs = (H245UnicastAddress_iPAddress*) ASN1MALLOC(pctxt,
|
||||
sizeof(H245UnicastAddress_iPAddress));
|
||||
memset(pUniIpAddrs, 0, sizeof(H245UnicastAddress_iPAddress));
|
||||
pUniAddrs->u.iPAddress = pUniIpAddrs;
|
||||
|
||||
inet_pton(AF_INET, pLogicalChannel->localIP, pUniIpAddrs->network.data);
|
||||
|
||||
pUniIpAddrs->network.numocts = 4;
|
||||
pUniIpAddrs->tsapIdentifier = pLogicalChannel->localRtcpPort;
|
||||
}
|
||||
|
||||
ooSocketConvertIpToNwAddr(pLogicalChannel->localIP,
|
||||
pUniIpAddrs->network.data);
|
||||
pUniIpAddrs->network.numocts = 4;
|
||||
pUniIpAddrs->tsapIdentifier = pLogicalChannel->localRtcpPort;
|
||||
|
||||
/*
|
||||
In case of fast start, the local endpoint need to be ready to
|
||||
receive all the media types proposed in the fast connect, before
|
||||
|
@ -4201,6 +4323,7 @@ int ooGetIpPortFromH245TransportAddress
|
|||
{
|
||||
H245UnicastAddress *unicastAddress = NULL;
|
||||
H245UnicastAddress_iPAddress *ipAddress = NULL;
|
||||
H245UnicastAddress_iP6Address *ip6Address = NULL;
|
||||
regmatch_t pmatch[1];
|
||||
|
||||
if(h245Address->t != T_H245TransportAddress_unicastAddress)
|
||||
|
@ -4211,7 +4334,17 @@ int ooGetIpPortFromH245TransportAddress
|
|||
}
|
||||
|
||||
unicastAddress = h245Address->u.unicastAddress;
|
||||
if(unicastAddress->t != T_H245UnicastAddress_iPAddress)
|
||||
if (call->versionIP == 6) {
|
||||
if (unicastAddress->t != T_H245UnicastAddress_iP6Address) {
|
||||
OOTRACEERR3("ERROR:H245 Address type is not IP6"
|
||||
"(%s, %s)\n", call->callType, call->callToken);
|
||||
return OO_FAILED;
|
||||
}
|
||||
ip6Address = unicastAddress->u.iP6Address;
|
||||
*port = ip6Address->tsapIdentifier;
|
||||
inet_ntop(AF_INET6, ip6Address->network.data, ip, INET6_ADDRSTRLEN);
|
||||
|
||||
} else { if(unicastAddress->t != T_H245UnicastAddress_iPAddress)
|
||||
{
|
||||
OOTRACEERR3("ERROR:H245 Address type is not IP"
|
||||
"(%s, %s)\n", call->callType, call->callToken);
|
||||
|
@ -4220,11 +4353,8 @@ int ooGetIpPortFromH245TransportAddress
|
|||
ipAddress = unicastAddress->u.iPAddress;
|
||||
|
||||
*port = ipAddress->tsapIdentifier;
|
||||
|
||||
sprintf(ip, "%d.%d.%d.%d", ipAddress->network.data[0],
|
||||
ipAddress->network.data[1],
|
||||
ipAddress->network.data[2],
|
||||
ipAddress->network.data[3]);
|
||||
inet_ntop(AF_INET, ipAddress->network.data, ip, INET_ADDRSTRLEN);
|
||||
}
|
||||
if (call->rtpMaskStr[0]) {
|
||||
if (regexec(&call->rtpMask->regex, ip, 1, pmatch, 0)) {
|
||||
OOTRACEERR5("ERROR:H245 Address is not matched with filter %s/%s"
|
||||
|
@ -4232,7 +4362,6 @@ int ooGetIpPortFromH245TransportAddress
|
|||
return OO_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
return OO_OK;
|
||||
}
|
||||
|
||||
|
@ -4247,6 +4376,7 @@ int ooPrepareFastStartResponseOLC
|
|||
H245H2250LogicalChannelParameters *pH2250lcp1=NULL, *pH2250lcp2=NULL;
|
||||
H245UnicastAddress *pUnicastAddrs=NULL, *pUniAddrs=NULL;
|
||||
H245UnicastAddress_iPAddress *pIpAddrs=NULL, *pUniIpAddrs=NULL;
|
||||
H245UnicastAddress_iP6Address *pIp6Addrs=NULL, *pUniIp6Addrs=NULL;
|
||||
unsigned session_id = 0;
|
||||
ooLogicalChannel *pLogicalChannel = NULL;
|
||||
|
||||
|
@ -4292,53 +4422,82 @@ int ooPrepareFastStartResponseOLC
|
|||
|
||||
pH2250lcp1->m.mediaChannelPresent = 1;
|
||||
pH2250lcp1->mediaChannel.t = T_H245TransportAddress_unicastAddress;
|
||||
pUniAddrs = (H245UnicastAddress*) memAlloc(pctxt,
|
||||
pUniAddrs = (H245UnicastAddress*) memAllocZ(pctxt,
|
||||
sizeof(H245UnicastAddress));
|
||||
pUniIpAddrs = (H245UnicastAddress_iPAddress*) memAlloc(pctxt,
|
||||
pH2250lcp1->mediaChannel.u.unicastAddress = pUniAddrs;
|
||||
if (call->versionIP == 6) {
|
||||
pUniIp6Addrs = (H245UnicastAddress_iP6Address*) memAllocZ(pctxt,
|
||||
sizeof(H245UnicastAddress_iP6Address));
|
||||
if(!pUniAddrs || !pUniIpAddrs) {
|
||||
OOTRACEERR3("Error:Memory - ooPrepareFastStartResponseOLC - pUniAddrs"
|
||||
"/pUniIpAddrs (%s, %s)\n", call->callType,
|
||||
call->callToken);
|
||||
return OO_FAILED;
|
||||
}
|
||||
|
||||
pUniAddrs->t = T_H245UnicastAddress_iP6Address;
|
||||
pUniAddrs->u.iP6Address = pUniIp6Addrs;
|
||||
inet_pton(AF_INET6, pLogicalChannel->localIP, pUniIp6Addrs->network.data);
|
||||
|
||||
pUniIp6Addrs->network.numocts = 16;
|
||||
pUniIp6Addrs->tsapIdentifier = pLogicalChannel->localRtpPort;
|
||||
|
||||
} else {
|
||||
pUniIpAddrs = (H245UnicastAddress_iPAddress*) memAllocZ(pctxt,
|
||||
sizeof(H245UnicastAddress_iPAddress));
|
||||
if(!pUniAddrs || !pUniIpAddrs)
|
||||
{
|
||||
if(!pUniAddrs || !pUniIpAddrs) {
|
||||
OOTRACEERR3("Error:Memory - ooPrepareFastStartResponseOLC - pUniAddrs"
|
||||
"/pUniIpAddrs (%s, %s)\n", call->callType,
|
||||
call->callToken);
|
||||
return OO_FAILED;
|
||||
}
|
||||
|
||||
pUniAddrs->t = T_H245UnicastAddress_iPAddress;
|
||||
pUniAddrs->u.iPAddress = pUniIpAddrs;
|
||||
inet_pton(AF_INET, pLogicalChannel->localIP, pUniIpAddrs->network.data);
|
||||
|
||||
pUniIpAddrs->network.numocts = 4;
|
||||
pUniIpAddrs->tsapIdentifier = pLogicalChannel->localRtpPort;
|
||||
}
|
||||
|
||||
pH2250lcp1->mediaChannel.u.unicastAddress = pUniAddrs;
|
||||
pUniAddrs->t = T_H245UnicastAddress_iPAddress;
|
||||
pUniAddrs->u.iPAddress = pUniIpAddrs;
|
||||
|
||||
ooSocketConvertIpToNwAddr(pLogicalChannel->localIP,
|
||||
pUniIpAddrs->network.data);
|
||||
|
||||
pUniIpAddrs->network.numocts = 4;
|
||||
pUniIpAddrs->tsapIdentifier = pLogicalChannel->localRtpPort;
|
||||
|
||||
pH2250lcp1->m.mediaControlChannelPresent = 1;
|
||||
pH2250lcp1->mediaControlChannel.t =
|
||||
T_H245TransportAddress_unicastAddress;
|
||||
pUnicastAddrs = (H245UnicastAddress*) memAlloc(pctxt,
|
||||
pUnicastAddrs = (H245UnicastAddress*) memAllocZ(pctxt,
|
||||
sizeof(H245UnicastAddress));
|
||||
pIpAddrs = (H245UnicastAddress_iPAddress*) memAlloc(pctxt,
|
||||
sizeof(H245UnicastAddress_iPAddress));
|
||||
if(!pUnicastAddrs || !pIpAddrs)
|
||||
{
|
||||
pH2250lcp1->mediaControlChannel.u.unicastAddress = pUnicastAddrs;
|
||||
|
||||
if (call->versionIP == 6) {
|
||||
pIp6Addrs = (H245UnicastAddress_iP6Address*) memAllocZ(pctxt,
|
||||
sizeof(H245UnicastAddress_iP6Address));
|
||||
if(!pUnicastAddrs || !pIp6Addrs) {
|
||||
OOTRACEERR3("Error:Memory - ooPrepareFastStartResponseOLC - "
|
||||
"pUnicastAddrs/pIpAddrs (%s, %s)\n", call->callType,
|
||||
call->callToken);
|
||||
return OO_FAILED;
|
||||
}
|
||||
memset(pUnicastAddrs, 0, sizeof(H245UnicastAddress));
|
||||
pH2250lcp1->mediaControlChannel.u.unicastAddress = pUnicastAddrs;
|
||||
pUnicastAddrs->t = T_H245UnicastAddress_iPAddress;
|
||||
|
||||
pUnicastAddrs->u.iPAddress = pIpAddrs;
|
||||
|
||||
ooSocketConvertIpToNwAddr(pLogicalChannel->localIP,
|
||||
pIpAddrs->network.data);
|
||||
}
|
||||
pUnicastAddrs->t = T_H245UnicastAddress_iP6Address;
|
||||
pUnicastAddrs->u.iP6Address = pIp6Addrs;
|
||||
inet_pton(AF_INET6, pLogicalChannel->localIP, pIp6Addrs->network.data);
|
||||
pIp6Addrs->network.numocts = 16;
|
||||
pIp6Addrs->tsapIdentifier = pLogicalChannel->localRtcpPort;
|
||||
} else {
|
||||
|
||||
pIpAddrs->network.numocts = 4;
|
||||
pIpAddrs->tsapIdentifier = pLogicalChannel->localRtcpPort;
|
||||
pIpAddrs = (H245UnicastAddress_iPAddress*) memAllocZ(pctxt,
|
||||
sizeof(H245UnicastAddress_iPAddress));
|
||||
if(!pUnicastAddrs || !pIpAddrs) {
|
||||
OOTRACEERR3("Error:Memory - ooPrepareFastStartResponseOLC - "
|
||||
"pUnicastAddrs/pIpAddrs (%s, %s)\n", call->callType,
|
||||
call->callToken);
|
||||
return OO_FAILED;
|
||||
}
|
||||
pUnicastAddrs->t = T_H245UnicastAddress_iPAddress;
|
||||
pUnicastAddrs->u.iPAddress = pIpAddrs;
|
||||
inet_pton(AF_INET, pLogicalChannel->localIP, pIpAddrs->network.data);
|
||||
pIpAddrs->network.numocts = 4;
|
||||
pIpAddrs->tsapIdentifier = pLogicalChannel->localRtcpPort;
|
||||
}
|
||||
}
|
||||
|
||||
if(reverse)
|
||||
|
@ -4357,26 +4516,42 @@ int ooPrepareFastStartResponseOLC
|
|||
T_H245TransportAddress_unicastAddress;
|
||||
pUniAddrs = (H245UnicastAddress*) memAlloc(pctxt,
|
||||
sizeof(H245UnicastAddress));
|
||||
pUniIpAddrs = (H245UnicastAddress_iPAddress*) memAlloc(pctxt,
|
||||
sizeof(H245UnicastAddress_iPAddress));
|
||||
if(!pUniAddrs || !pUniIpAddrs)
|
||||
{
|
||||
OOTRACEERR3("Error:Memory - ooPrepareFastStartResponseOLC - "
|
||||
pH2250lcp2->mediaControlChannel.u.unicastAddress = pUniAddrs;
|
||||
|
||||
if (call->versionIP == 6) {
|
||||
pUniIp6Addrs = (H245UnicastAddress_iP6Address*) memAlloc(pctxt,
|
||||
sizeof(H245UnicastAddress_iP6Address));
|
||||
if(!pUniAddrs || !pUniIp6Addrs) {
|
||||
OOTRACEERR3("Error:Memory - ooPrepareFastStartResponseOLC - "
|
||||
"pUniAddrs/pUniIpAddrs (%s, %s)\n", call->callType,
|
||||
call->callToken);
|
||||
return OO_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
pH2250lcp2->mediaControlChannel.u.unicastAddress = pUniAddrs;
|
||||
|
||||
pUniAddrs->t = T_H245UnicastAddress_iPAddress;
|
||||
pUniAddrs->t = T_H245UnicastAddress_iP6Address;
|
||||
pUniAddrs->u.iP6Address = pUniIp6Addrs;
|
||||
inet_pton(AF_INET6, pLogicalChannel->localIP, pUniIp6Addrs->network.data);
|
||||
pUniIp6Addrs->network.numocts = 16;
|
||||
pUniIp6Addrs->tsapIdentifier = pLogicalChannel->localRtcpPort;
|
||||
} else {
|
||||
pUniIpAddrs = (H245UnicastAddress_iPAddress*) memAlloc(pctxt,
|
||||
sizeof(H245UnicastAddress_iPAddress));
|
||||
if(!pUniAddrs || !pUniIpAddrs) {
|
||||
OOTRACEERR3("Error:Memory - ooPrepareFastStartResponseOLC - "
|
||||
"pUniAddrs/pUniIpAddrs (%s, %s)\n", call->callType,
|
||||
call->callToken);
|
||||
return OO_FAILED;
|
||||
}
|
||||
|
||||
pUniAddrs->u.iPAddress = pUniIpAddrs;
|
||||
|
||||
ooSocketConvertIpToNwAddr(pLogicalChannel->localIP,
|
||||
pUniIpAddrs->network.data);
|
||||
pUniIpAddrs->network.numocts = 4;
|
||||
pUniIpAddrs->tsapIdentifier = pLogicalChannel->localRtcpPort;
|
||||
pH2250lcp2->mediaControlChannel.u.unicastAddress = pUniAddrs;
|
||||
|
||||
pUniAddrs->t = T_H245UnicastAddress_iPAddress;
|
||||
pUniAddrs->u.iPAddress = pUniIpAddrs;
|
||||
inet_pton(AF_INET, pLogicalChannel->localIP, pUniIpAddrs->network.data);
|
||||
pUniIpAddrs->network.numocts = 4;
|
||||
pUniIpAddrs->tsapIdentifier = pLogicalChannel->localRtcpPort;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -226,7 +226,7 @@ int ooHandleFastStart(OOH323CallData *call, H225Facility_UUIE *facility)
|
|||
if(ret != OO_OK)
|
||||
{
|
||||
OOTRACEERR3("Error: Unknown H245 address type in received "
|
||||
"CallProceeding message (%s, %s)", call->callType,
|
||||
"Facility message (%s, %s)", call->callType,
|
||||
call->callToken);
|
||||
/* Mark call for clearing */
|
||||
if(call->callState < OO_CALL_CLEAR)
|
||||
|
@ -368,8 +368,10 @@ int ooOnReceivedSetup(OOH323CallData *call, Q931Message *q931Msg)
|
|||
H245OpenLogicalChannel* olc;
|
||||
ASN1OCTET msgbuf[MAXMSGLEN];
|
||||
H225TransportAddress_ipAddress_ip *ip = NULL;
|
||||
H225TransportAddress_ip6Address_ip *ip6 = NULL;
|
||||
Q931InformationElement* pDisplayIE=NULL;
|
||||
OOAliases *pAlias=NULL;
|
||||
char remoteIP[2+8*4+7];
|
||||
|
||||
call->callReference = q931Msg->callReference;
|
||||
|
||||
|
@ -507,18 +509,26 @@ int ooOnReceivedSetup(OOH323CallData *call, Q931Message *q931Msg)
|
|||
"setup (%s, %s)\n", call->callType, call->callToken);
|
||||
}
|
||||
else{
|
||||
|
||||
if(setup->sourceCallSignalAddress.t != T_H225TransportAddress_ipAddress)
|
||||
{
|
||||
OOTRACEERR3("ERROR: Source call signalling address type not ip "
|
||||
if(setup->sourceCallSignalAddress.t == T_H225TransportAddress_ip6Address) {
|
||||
ip6 = &setup->sourceCallSignalAddress.u.ip6Address->ip;
|
||||
inet_ntop(AF_INET6, ip6->data, remoteIP, INET6_ADDRSTRLEN);
|
||||
call->remotePort = setup->sourceCallSignalAddress.u.ip6Address->port;
|
||||
} else if(setup->sourceCallSignalAddress.t == T_H225TransportAddress_ipAddress) {
|
||||
ip = &setup->sourceCallSignalAddress.u.ipAddress->ip;
|
||||
sprintf(remoteIP, "%d.%d.%d.%d", ip->data[0], ip->data[1],
|
||||
ip->data[2], ip->data[3]);
|
||||
call->remotePort = setup->sourceCallSignalAddress.u.ipAddress->port;
|
||||
} else {
|
||||
OOTRACEERR3("ERROR: Source call signalling address type not ip4 nor ip6 "
|
||||
"(%s, %s)\n", call->callType, call->callToken);
|
||||
return OO_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
ip = &setup->sourceCallSignalAddress.u.ipAddress->ip;
|
||||
sprintf(call->remoteIP, "%d.%d.%d.%d", ip->data[0], ip->data[1],
|
||||
ip->data[2], ip->data[3]);
|
||||
call->remotePort = setup->sourceCallSignalAddress.u.ipAddress->port;
|
||||
if (strncmp(remoteIP, call->remoteIP, strlen(remoteIP))) {
|
||||
OOTRACEERR5("ERROR: Security denial remote sig IP isn't a socket ip, %s not %s "
|
||||
"(%s, %s)\n", remoteIP, call->remoteIP, call->callType,
|
||||
call->callToken);
|
||||
}
|
||||
|
||||
/* check for fast start */
|
||||
|
@ -1814,6 +1824,7 @@ int ooOnReceivedFacility(OOH323CallData *call, Q931Message * pQ931Msg)
|
|||
H225Facility_UUIE * facility = NULL;
|
||||
int ret;
|
||||
H225TransportAddress_ipAddress_ip *ip = NULL;
|
||||
H225TransportAddress_ip6Address_ip *ip6 = NULL;
|
||||
OOTRACEDBGC3("Received Facility Message.(%s, %s)\n", call->callType,
|
||||
call->callToken);
|
||||
|
||||
|
@ -1899,6 +1910,21 @@ int ooOnReceivedFacility(OOH323CallData *call, Q931Message * pQ931Msg)
|
|||
call->pCallFwdData->aliases = NULL;
|
||||
if(facility->m.alternativeAddressPresent)
|
||||
{
|
||||
if (call->versionIP == 6) {
|
||||
if(facility->alternativeAddress.t !=
|
||||
T_H225TransportAddress_ip6Address)
|
||||
{
|
||||
OOTRACEERR3("ERROR: Source call signalling address type not ip6 "
|
||||
"(%s, %s)\n", call->callType, call->callToken);
|
||||
|
||||
return OO_FAILED;
|
||||
}
|
||||
|
||||
ip6 = &facility->alternativeAddress.u.ip6Address->ip;
|
||||
inet_ntop(AF_INET6, ip6->data, call->pCallFwdData->ip, INET6_ADDRSTRLEN);
|
||||
call->pCallFwdData->port =
|
||||
facility->alternativeAddress.u.ip6Address->port;
|
||||
} else {
|
||||
if(facility->alternativeAddress.t !=
|
||||
T_H225TransportAddress_ipAddress)
|
||||
{
|
||||
|
@ -1913,6 +1939,7 @@ int ooOnReceivedFacility(OOH323CallData *call, Q931Message * pQ931Msg)
|
|||
ip->data[1], ip->data[2], ip->data[3]);
|
||||
call->pCallFwdData->port =
|
||||
facility->alternativeAddress.u.ipAddress->port;
|
||||
}
|
||||
}
|
||||
|
||||
if(facility->m.alternativeAliasAddressPresent)
|
||||
|
@ -1969,6 +1996,7 @@ int ooHandleStartH245FacilityMessage
|
|||
(OOH323CallData *call, H225Facility_UUIE *facility)
|
||||
{
|
||||
H225TransportAddress_ipAddress *ipAddress = NULL;
|
||||
H225TransportAddress_ip6Address *ip6Address = NULL;
|
||||
int ret;
|
||||
|
||||
/* Extract H245 address */
|
||||
|
@ -1978,25 +2006,43 @@ int ooHandleStartH245FacilityMessage
|
|||
"address (%s, %s)\n", call->callType, call->callToken);
|
||||
return OO_FAILED;
|
||||
}
|
||||
if(facility->h245Address.t != T_H225TransportAddress_ipAddress)
|
||||
{
|
||||
if (call->versionIP == 6) {
|
||||
if(facility->h245Address.t != T_H225TransportAddress_ip6Address)
|
||||
{
|
||||
OOTRACEERR3("ERROR:Unknown H245 address type in received startH245 "
|
||||
"facility message (%s, %s)\n", call->callType, call->callToken);
|
||||
return OO_FAILED;
|
||||
}
|
||||
ipAddress = facility->h245Address.u.ipAddress;
|
||||
if(!ipAddress)
|
||||
{
|
||||
}
|
||||
ip6Address = facility->h245Address.u.ip6Address;
|
||||
if(!ip6Address)
|
||||
{
|
||||
OOTRACEERR3("ERROR:Invalid startH245 facility message. No H245 ip6 "
|
||||
"address found. (%s, %s)\n", call->callType, call->callToken);
|
||||
return OO_FAILED;
|
||||
}
|
||||
inet_ntop(AF_INET6, ip6Address->ip.data, call->remoteIP, INET6_ADDRSTRLEN);
|
||||
call->remoteH245Port = ip6Address->port;
|
||||
} else {
|
||||
if(facility->h245Address.t != T_H225TransportAddress_ipAddress)
|
||||
{
|
||||
OOTRACEERR3("ERROR:Unknown H245 address type in received startH245 "
|
||||
"facility message (%s, %s)\n", call->callType, call->callToken);
|
||||
return OO_FAILED;
|
||||
}
|
||||
ipAddress = facility->h245Address.u.ipAddress;
|
||||
if(!ipAddress)
|
||||
{
|
||||
OOTRACEERR3("ERROR:Invalid startH245 facility message. No H245 ip "
|
||||
"address found. (%s, %s)\n", call->callType, call->callToken);
|
||||
return OO_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
sprintf(call->remoteIP, "%d.%d.%d.%d", ipAddress->ip.data[0],
|
||||
sprintf(call->remoteIP, "%d.%d.%d.%d", ipAddress->ip.data[0],
|
||||
ipAddress->ip.data[1],
|
||||
ipAddress->ip.data[2],
|
||||
ipAddress->ip.data[3]);
|
||||
call->remoteH245Port = ipAddress->port;
|
||||
call->remoteH245Port = ipAddress->port;
|
||||
}
|
||||
|
||||
/* disable tunneling for this call */
|
||||
OO_CLRFLAG (call->flags, OO_M_TUNNELING);
|
||||
|
@ -2178,15 +2224,16 @@ int ooH323RetrieveAliases
|
|||
newAlias->value[strlen(pAliasAddress->u.url_ID)*sizeof(char)]='\0';
|
||||
break;
|
||||
case T_H225AliasAddress_transportID:
|
||||
newAlias->type = T_H225AliasAddress_transportID;
|
||||
pTransportAddrss = pAliasAddress->u.transportID;
|
||||
if(pTransportAddrss->t != T_H225TransportAddress_ipAddress)
|
||||
{
|
||||
OOTRACEERR3("Error:Alias transportID not an IP address"
|
||||
"(%s, %s)\n", call->callType, call->callToken);
|
||||
memFreePtr(call->pctxt, newAlias);
|
||||
break;
|
||||
}
|
||||
newAlias->type = T_H225AliasAddress_transportID;
|
||||
pTransportAddrss = pAliasAddress->u.transportID;
|
||||
if(pTransportAddrss->t == T_H225TransportAddress_ip6Address) {
|
||||
/* hopefully ip:port value can't exceed more than 30
|
||||
characters */
|
||||
newAlias->value = (char*)memAlloc(call->pctxt,
|
||||
INET6_ADDRSTRLEN*sizeof(char)*2);
|
||||
inet_ntop(AF_INET6, pTransportAddrss->u.ip6Address->ip.data, newAlias->value, INET6_ADDRSTRLEN);
|
||||
sprintf(newAlias->value+strlen(newAlias->value), ":%d", pTransportAddrss->u.ip6Address->port);
|
||||
} else if(pTransportAddrss->t == T_H225TransportAddress_ipAddress) {
|
||||
/* hopefully ip:port value can't exceed more than 30
|
||||
characters */
|
||||
newAlias->value = (char*)memAlloc(call->pctxt,
|
||||
|
@ -2197,7 +2244,12 @@ int ooH323RetrieveAliases
|
|||
pTransportAddrss->u.ipAddress->ip.data[2],
|
||||
pTransportAddrss->u.ipAddress->ip.data[3],
|
||||
pTransportAddrss->u.ipAddress->port);
|
||||
break;
|
||||
} else {
|
||||
OOTRACEERR3("Error:Alias transportID not an IP4 nor IP6 address"
|
||||
"(%s, %s)\n", call->callType, call->callToken);
|
||||
memFreePtr(call->pctxt, newAlias);
|
||||
}
|
||||
break;
|
||||
case T_H225AliasAddress_email_ID:
|
||||
newAlias->type = T_H225AliasAddress_email_ID;
|
||||
newAlias->value = (char*)memAlloc(call->pctxt,
|
||||
|
@ -2471,22 +2523,29 @@ OOAliases* ooH323AddAliasToList
|
|||
case T_H225AliasAddress_transportID:
|
||||
newAlias->type = T_H225AliasAddress_transportID;
|
||||
pTransportAddrss = pAliasAddress->u.transportID;
|
||||
if(pTransportAddrss->t != T_H225TransportAddress_ipAddress)
|
||||
{
|
||||
OOTRACEERR1("Error:Alias transportID not an IP address\n");
|
||||
memFreePtr(pctxt, newAlias);
|
||||
return NULL;
|
||||
}
|
||||
/* hopefully ip:port value can't exceed more than 30
|
||||
if(pTransportAddrss->t == T_H225TransportAddress_ip6Address) {
|
||||
/* hopefully ip:port value can't exceed more than 30
|
||||
characters */
|
||||
newAlias->value = (char*)memAlloc(pctxt,
|
||||
newAlias->value = (char*)memAlloc(pctxt,
|
||||
INET6_ADDRSTRLEN*sizeof(char)*2);
|
||||
inet_ntop(AF_INET6, pTransportAddrss->u.ip6Address->ip.data, newAlias->value, INET6_ADDRSTRLEN);
|
||||
sprintf(newAlias->value+strlen(newAlias->value), ":%d", pTransportAddrss->u.ip6Address->port);
|
||||
} else if(pTransportAddrss->t == T_H225TransportAddress_ipAddress) {
|
||||
/* hopefully ip:port value can't exceed more than 30
|
||||
characters */
|
||||
newAlias->value = (char*)memAlloc(pctxt,
|
||||
30*sizeof(char));
|
||||
sprintf(newAlias->value, "%d.%d.%d.%d:%d",
|
||||
sprintf(newAlias->value, "%d.%d.%d.%d:%d",
|
||||
pTransportAddrss->u.ipAddress->ip.data[0],
|
||||
pTransportAddrss->u.ipAddress->ip.data[1],
|
||||
pTransportAddrss->u.ipAddress->ip.data[2],
|
||||
pTransportAddrss->u.ipAddress->ip.data[3],
|
||||
pTransportAddrss->u.ipAddress->port);
|
||||
} else {
|
||||
OOTRACEERR1("Error:Alias transportID not an IP4 nor IP6 address\n");
|
||||
memFreePtr(pctxt, newAlias);
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
case T_H225AliasAddress_email_ID:
|
||||
newAlias->type = T_H225AliasAddress_email_ID;
|
||||
|
@ -2509,6 +2568,17 @@ OOAliases* ooH323AddAliasToList
|
|||
int ooH323GetIpPortFromH225TransportAddress(struct OOH323CallData *call,
|
||||
H225TransportAddress *h225Address, char *ip, int *port)
|
||||
{
|
||||
if (call->versionIP == 6) {
|
||||
if(h225Address->t != T_H225TransportAddress_ip6Address)
|
||||
{
|
||||
OOTRACEERR3("Error: Unknown H225 address type. (%s, %s)", call->callType,
|
||||
call->callToken);
|
||||
return OO_FAILED;
|
||||
}
|
||||
inet_ntop(AF_INET6, h225Address->u.ip6Address->ip.data, ip, INET6_ADDRSTRLEN);
|
||||
*port = h225Address->u.ip6Address->port;
|
||||
return OO_OK;
|
||||
}
|
||||
if(h225Address->t != T_H225TransportAddress_ipAddress)
|
||||
{
|
||||
OOTRACEERR3("Error: Unknown H225 address type. (%s, %s)", call->callType,
|
||||
|
|
|
@ -130,7 +130,7 @@ typedef struct OOH323EndPoint {
|
|||
int noOfCaps;
|
||||
OOH225MsgCallbacks h225Callbacks;
|
||||
OOH323CALLBACKS h323Callbacks;
|
||||
char signallingIP[20];
|
||||
char signallingIP[2+8*4+7];
|
||||
int listenPort;
|
||||
OOSOCKET *listener;
|
||||
OOH323CallData *callList;
|
||||
|
@ -148,6 +148,7 @@ typedef struct OOH323EndPoint {
|
|||
OOInterface *ifList; /* interface list for the host we are running on*/
|
||||
OOBOOL isGateway;
|
||||
OOSOCKET cmdSock;
|
||||
OOBOOL v6Mode;
|
||||
} OOH323EndPoint;
|
||||
|
||||
#define ooEndPoint OOH323EndPoint
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
#include "asterisk.h"
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/netsock2.h"
|
||||
#include "asterisk/config.h"
|
||||
|
||||
#include "ooports.h"
|
||||
#include "ooh323ep.h"
|
||||
|
@ -71,7 +73,7 @@ int ooBindPort (OOH323PortType type, OOSOCKET socket, char *ip)
|
|||
initialPort = ooGetNextPort (type);
|
||||
bindPort = initialPort;
|
||||
|
||||
ret= ooSocketStrToAddr (ip, &ipAddrs);
|
||||
ret=ast_parse_arg(ip, PARSE_ADDR, &ipAddrs);
|
||||
|
||||
while(1)
|
||||
{
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#include "asterisk.h"
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/config.h"
|
||||
#include "asterisk/netsock2.h"
|
||||
#include <time.h>
|
||||
|
||||
#include "ooq931.h"
|
||||
|
@ -854,7 +856,7 @@ int ooSetFastStartResponse(OOH323CallData *pCall, Q931Message *pQ931msg,
|
|||
/* OOCTXT *pctxt = &gH323ep.msgctxt; */
|
||||
OOCTXT *pctxt = pCall->msgctxt;
|
||||
int ret = 0, i=0, j=0, remoteMediaPort=0, remoteMediaControlPort = 0, dir=0;
|
||||
char remoteMediaIP[20], remoteMediaControlIP[20];
|
||||
char remoteMediaIP[2+8*4+7], remoteMediaControlIP[2+8*4+7];
|
||||
DListNode *pNode = NULL;
|
||||
H245OpenLogicalChannel *olc = NULL, printOlc;
|
||||
ooH323EpCapability *epCap = NULL;
|
||||
|
@ -1473,6 +1475,7 @@ int ooSendProgress(OOH323CallData *call)
|
|||
H225VendorIdentifier *vendor;
|
||||
Q931Message *q931msg=NULL;
|
||||
H225TransportAddress_ipAddress *h245IpAddr;
|
||||
H225TransportAddress_ip6Address *h245Ip6Addr;
|
||||
OOCTXT *pctxt = call->msgctxt;
|
||||
|
||||
ret = ooCreateQ931Message(pctxt, &q931msg, Q931ProgressMsg);
|
||||
|
@ -1569,6 +1572,23 @@ int ooSendProgress(OOH323CallData *call)
|
|||
!OO_TESTFLAG (call->flags, OO_M_TUNNELING) &&
|
||||
!call->h245listener && ooCreateH245Listener(call) == OO_OK)
|
||||
{
|
||||
if (call->versionIP == 6) {
|
||||
progress->m.h245AddressPresent = TRUE;
|
||||
progress->h245Address.t = T_H225TransportAddress_ip6Address;
|
||||
|
||||
h245Ip6Addr = (H225TransportAddress_ip6Address*)
|
||||
memAllocZ (pctxt, sizeof(H225TransportAddress_ip6Address));
|
||||
if(!h245Ip6Addr)
|
||||
{
|
||||
OOTRACEERR3("Error:Memory - ooSendProgress - h245Ip6Addr"
|
||||
"(%s, %s)\n", call->callType, call->callToken);
|
||||
return OO_FAILED;
|
||||
}
|
||||
inet_pton(AF_INET6, call->localIP, h245Ip6Addr->ip.data);
|
||||
h245Ip6Addr->ip.numocts=16;
|
||||
h245Ip6Addr->port = *(call->h245listenport);
|
||||
progress->h245Address.u.ip6Address = h245Ip6Addr;
|
||||
} else {
|
||||
progress->m.h245AddressPresent = TRUE;
|
||||
progress->h245Address.t = T_H225TransportAddress_ipAddress;
|
||||
|
||||
|
@ -1576,14 +1596,15 @@ int ooSendProgress(OOH323CallData *call)
|
|||
memAllocZ (pctxt, sizeof(H225TransportAddress_ipAddress));
|
||||
if(!h245IpAddr)
|
||||
{
|
||||
OOTRACEERR3("Error:Memory - ooAcceptCall - h245IpAddr"
|
||||
OOTRACEERR3("Error:Memory - ooSendProgress - h245IpAddr"
|
||||
"(%s, %s)\n", call->callType, call->callToken);
|
||||
return OO_FAILED;
|
||||
}
|
||||
ooSocketConvertIpToNwAddr(call->localIP, h245IpAddr->ip.data);
|
||||
inet_pton(AF_INET, call->localIP, h245IpAddr->ip.data);
|
||||
h245IpAddr->ip.numocts=4;
|
||||
h245IpAddr->port = *(call->h245listenport);
|
||||
progress->h245Address.u.ipAddress = h245IpAddr;
|
||||
}
|
||||
}
|
||||
|
||||
OOTRACEDBGA3("Built Progress (%s, %s)\n", call->callType, call->callToken);
|
||||
|
@ -1614,6 +1635,7 @@ int ooSendStartH245Facility(OOH323CallData *call)
|
|||
/* OOCTXT *pctxt = &gH323ep.msgctxt; */
|
||||
OOCTXT *pctxt = call->msgctxt;
|
||||
H225TransportAddress_ipAddress *h245IpAddr;
|
||||
H225TransportAddress_ip6Address *h245Ip6Addr;
|
||||
|
||||
OOTRACEDBGA3("Building Facility message (%s, %s)\n", call->callType,
|
||||
call->callToken);
|
||||
|
@ -1674,19 +1696,35 @@ int ooSendStartH245Facility(OOH323CallData *call)
|
|||
}
|
||||
|
||||
facility->m.h245AddressPresent = TRUE;
|
||||
facility->h245Address.t = T_H225TransportAddress_ipAddress;
|
||||
if (call->versionIP == 6) {
|
||||
facility->h245Address.t = T_H225TransportAddress_ip6Address;
|
||||
|
||||
h245IpAddr = (H225TransportAddress_ipAddress*)
|
||||
h245Ip6Addr = (H225TransportAddress_ip6Address*)
|
||||
memAllocZ (pctxt, sizeof(H225TransportAddress_ip6Address));
|
||||
if(!h245Ip6Addr) {
|
||||
OOTRACEERR3("Error:Memory - ooSendFacility - h245Ip6Addr"
|
||||
"(%s, %s)\n", call->callType, call->callToken);
|
||||
return OO_FAILED;
|
||||
}
|
||||
inet_pton(AF_INET6, call->localIP, h245Ip6Addr->ip.data);
|
||||
h245Ip6Addr->ip.numocts=16;
|
||||
h245Ip6Addr->port = *(call->h245listenport);
|
||||
facility->h245Address.u.ip6Address = h245Ip6Addr;
|
||||
} else {
|
||||
facility->h245Address.t = T_H225TransportAddress_ipAddress;
|
||||
|
||||
h245IpAddr = (H225TransportAddress_ipAddress*)
|
||||
memAllocZ (pctxt, sizeof(H225TransportAddress_ipAddress));
|
||||
if(!h245IpAddr) {
|
||||
if(!h245IpAddr) {
|
||||
OOTRACEERR3("Error:Memory - ooSendFacility - h245IpAddr"
|
||||
"(%s, %s)\n", call->callType, call->callToken);
|
||||
return OO_FAILED;
|
||||
}
|
||||
inet_pton(AF_INET, call->localIP, h245IpAddr->ip.data);
|
||||
h245IpAddr->ip.numocts=4;
|
||||
h245IpAddr->port = *(call->h245listenport);
|
||||
facility->h245Address.u.ipAddress = h245IpAddr;
|
||||
}
|
||||
ooSocketConvertIpToNwAddr(call->localIP, h245IpAddr->ip.data);
|
||||
h245IpAddr->ip.numocts=4;
|
||||
h245IpAddr->port = *(call->h245listenport);
|
||||
facility->h245Address.u.ipAddress = h245IpAddr;
|
||||
|
||||
OOTRACEDBGA3("Built Facility message to send (%s, %s)\n", call->callType,
|
||||
call->callToken);
|
||||
|
@ -1818,6 +1856,7 @@ int ooAcceptCall(OOH323CallData *call)
|
|||
int ret = 0, i=0;
|
||||
H225Connect_UUIE *connect;
|
||||
H225TransportAddress_ipAddress *h245IpAddr;
|
||||
H225TransportAddress_ip6Address *h245Ip6Addr;
|
||||
H225VendorIdentifier *vendor;
|
||||
Q931Message *q931msg=NULL;
|
||||
/* OOCTXT *pctxt = &gH323ep.msgctxt; */
|
||||
|
@ -1980,20 +2019,37 @@ int ooAcceptCall(OOH323CallData *call)
|
|||
!call->pH245Channel))
|
||||
{
|
||||
connect->m.h245AddressPresent = TRUE;
|
||||
connect->h245Address.t = T_H225TransportAddress_ipAddress;
|
||||
if (call->versionIP == 6) {
|
||||
connect->h245Address.t = T_H225TransportAddress_ip6Address;
|
||||
|
||||
h245IpAddr = (H225TransportAddress_ipAddress*)
|
||||
h245Ip6Addr = (H225TransportAddress_ip6Address*)
|
||||
memAllocZ (pctxt, sizeof(H225TransportAddress_ip6Address));
|
||||
if(!h245Ip6Addr)
|
||||
{
|
||||
OOTRACEERR3("Error:Memory - ooAcceptCall - h245Ip6Addr"
|
||||
"(%s, %s)\n", call->callType, call->callToken);
|
||||
return OO_FAILED;
|
||||
}
|
||||
inet_pton(AF_INET6, call->localIP, h245Ip6Addr->ip.data);
|
||||
h245Ip6Addr->ip.numocts=16;
|
||||
h245Ip6Addr->port = *(call->h245listenport);
|
||||
connect->h245Address.u.ip6Address = h245Ip6Addr;
|
||||
} else {
|
||||
connect->h245Address.t = T_H225TransportAddress_ipAddress;
|
||||
|
||||
h245IpAddr = (H225TransportAddress_ipAddress*)
|
||||
memAllocZ (pctxt, sizeof(H225TransportAddress_ipAddress));
|
||||
if(!h245IpAddr)
|
||||
{
|
||||
if(!h245IpAddr)
|
||||
{
|
||||
OOTRACEERR3("Error:Memory - ooAcceptCall - h245IpAddr"
|
||||
"(%s, %s)\n", call->callType, call->callToken);
|
||||
return OO_FAILED;
|
||||
}
|
||||
inet_pton(AF_INET, call->localIP, h245IpAddr->ip.data);
|
||||
h245IpAddr->ip.numocts=4;
|
||||
h245IpAddr->port = *(call->h245listenport);
|
||||
connect->h245Address.u.ipAddress = h245IpAddr;
|
||||
}
|
||||
ooSocketConvertIpToNwAddr(call->localIP, h245IpAddr->ip.data);
|
||||
h245IpAddr->ip.numocts=4;
|
||||
h245IpAddr->port = *(call->h245listenport);
|
||||
connect->h245Address.u.ipAddress = h245IpAddr;
|
||||
}
|
||||
|
||||
OOTRACEDBGA3("Built H.225 Connect message (%s, %s)\n", call->callType,
|
||||
|
@ -2126,10 +2182,11 @@ int ooH323MakeCall(char *dest, char *callToken, ooCallOptions *opts)
|
|||
OOCTXT *pctxt;
|
||||
OOH323CallData *call;
|
||||
int ret=OO_OK, i=0, irand=0;
|
||||
char tmp[30]="\0";
|
||||
char tmp[2+8*4+7]="\0";
|
||||
char *ip=NULL, *port = NULL;
|
||||
struct timeval tv;
|
||||
struct timespec ts;
|
||||
struct ast_sockaddr m_addr;
|
||||
|
||||
if(!dest)
|
||||
{
|
||||
|
@ -2173,7 +2230,7 @@ int ooH323MakeCall(char *dest, char *callToken, ooCallOptions *opts)
|
|||
}
|
||||
|
||||
|
||||
ret = ooParseDestination(call, dest, tmp, 24, &call->remoteAliases);
|
||||
ret = ooParseDestination(call, dest, tmp, 2+8*4+7, &call->remoteAliases);
|
||||
if(ret != OO_OK)
|
||||
{
|
||||
OOTRACEERR2("Error: Failed to parse the destination string %s for "
|
||||
|
@ -2185,10 +2242,15 @@ int ooH323MakeCall(char *dest, char *callToken, ooCallOptions *opts)
|
|||
/* Check whether we have ip address */
|
||||
if(!ooUtilsIsStrEmpty(tmp)) {
|
||||
ip = tmp;
|
||||
port = strchr(tmp, ':');
|
||||
port = strrchr(tmp, ':');
|
||||
*port = '\0';
|
||||
port++;
|
||||
strcpy(call->remoteIP, ip);
|
||||
ast_parse_arg(ip, PARSE_ADDR, &m_addr);
|
||||
if (ast_sockaddr_is_ipv6(&m_addr))
|
||||
call->versionIP = 6;
|
||||
else
|
||||
call->versionIP = 4;
|
||||
call->remotePort = atoi(port);
|
||||
}
|
||||
|
||||
|
@ -2261,7 +2323,16 @@ int ooH323CallAdmitted(OOH323CallData *call)
|
|||
|
||||
if(gH323ep.h323Callbacks.onOutgoingCall) {
|
||||
/* Outgoing call callback function */
|
||||
gH323ep.h323Callbacks.onOutgoingCall(call);
|
||||
if (gH323ep.h323Callbacks.onOutgoingCall(call) != OO_OK) {
|
||||
OOTRACEERR3("ERROR:Failed to setup media to (%s,%d)\n",
|
||||
call->callType, call->callToken);
|
||||
if(call->callState< OO_CALL_CLEAR)
|
||||
{
|
||||
call->callState = OO_CALL_CLEAR;
|
||||
call->callEndReason = OO_REASON_UNKNOWN;
|
||||
}
|
||||
return OO_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ooH323MakeCall_helper(call);
|
||||
|
@ -2294,9 +2365,8 @@ int ooH323MakeCall_helper(OOH323CallData *call)
|
|||
H225Setup_UUIE *setup;
|
||||
|
||||
ASN1DynOctStr *pFS=NULL;
|
||||
H225TransportAddress_ipAddress *destCallSignalIpAddress;
|
||||
|
||||
H225TransportAddress_ipAddress *srcCallSignalIpAddress;
|
||||
H225TransportAddress_ipAddress *destCallSignalIpAddress,*srcCallSignalIpAddress;
|
||||
H225TransportAddress_ip6Address *destCallSignalIp6Address,*srcCallSignalIp6Address;
|
||||
ooH323EpCapability *epCap=NULL;
|
||||
OOCTXT *pctxt = NULL;
|
||||
H245OpenLogicalChannel *olc, printOlc;
|
||||
|
@ -2465,41 +2535,77 @@ int ooH323MakeCall_helper(OOH323CallData *call)
|
|||
setup->sourceInfo.undefinedNode = FALSE;
|
||||
|
||||
/* Populate the destination Call Signal Address */
|
||||
setup->destCallSignalAddress.t=T_H225TransportAddress_ipAddress;
|
||||
destCallSignalIpAddress = (H225TransportAddress_ipAddress*)memAlloc(pctxt,
|
||||
setup->m.destCallSignalAddressPresent=TRUE;
|
||||
setup->activeMC=FALSE;
|
||||
if (call->versionIP == 6) {
|
||||
setup->destCallSignalAddress.t=T_H225TransportAddress_ip6Address;
|
||||
destCallSignalIp6Address = (H225TransportAddress_ip6Address*)memAlloc(pctxt,
|
||||
sizeof(H225TransportAddress_ip6Address));
|
||||
if(!destCallSignalIp6Address)
|
||||
{
|
||||
OOTRACEERR3("Error:Memory - ooH323MakeCall_helper - "
|
||||
"destCallSignal6Address. (%s, %s)\n", call->callType,
|
||||
call->callToken);
|
||||
return OO_FAILED;
|
||||
}
|
||||
inet_pton(AF_INET6, call->remoteIP, destCallSignalIp6Address->ip.data);
|
||||
|
||||
destCallSignalIp6Address->ip.numocts=16;
|
||||
destCallSignalIp6Address->port = call->remotePort;
|
||||
|
||||
setup->destCallSignalAddress.u.ip6Address = destCallSignalIp6Address;
|
||||
} else {
|
||||
setup->destCallSignalAddress.t=T_H225TransportAddress_ipAddress;
|
||||
destCallSignalIpAddress = (H225TransportAddress_ipAddress*)memAlloc(pctxt,
|
||||
sizeof(H225TransportAddress_ipAddress));
|
||||
if(!destCallSignalIpAddress)
|
||||
{
|
||||
if(!destCallSignalIpAddress)
|
||||
{
|
||||
OOTRACEERR3("Error:Memory - ooH323MakeCall_helper - "
|
||||
"destCallSignalAddress. (%s, %s)\n", call->callType,
|
||||
call->callToken);
|
||||
return OO_FAILED;
|
||||
}
|
||||
inet_pton(AF_INET, call->remoteIP, destCallSignalIpAddress->ip.data);
|
||||
|
||||
destCallSignalIpAddress->ip.numocts=4;
|
||||
destCallSignalIpAddress->port = call->remotePort;
|
||||
|
||||
setup->destCallSignalAddress.u.ipAddress = destCallSignalIpAddress;
|
||||
}
|
||||
ooSocketConvertIpToNwAddr(call->remoteIP, destCallSignalIpAddress->ip.data);
|
||||
|
||||
destCallSignalIpAddress->ip.numocts=4;
|
||||
destCallSignalIpAddress->port = call->remotePort;
|
||||
|
||||
setup->destCallSignalAddress.u.ipAddress = destCallSignalIpAddress;
|
||||
setup->m.destCallSignalAddressPresent=TRUE;
|
||||
setup->activeMC=FALSE;
|
||||
|
||||
/* Populate the source Call Signal Address */
|
||||
setup->sourceCallSignalAddress.t=T_H225TransportAddress_ipAddress;
|
||||
srcCallSignalIpAddress = (H225TransportAddress_ipAddress*)memAlloc(pctxt,
|
||||
setup->m.sourceCallSignalAddressPresent=TRUE;
|
||||
if (call->versionIP == 6) {
|
||||
setup->sourceCallSignalAddress.t=T_H225TransportAddress_ip6Address;
|
||||
srcCallSignalIp6Address = (H225TransportAddress_ip6Address*)memAlloc(pctxt,
|
||||
sizeof(H225TransportAddress_ip6Address));
|
||||
if(!srcCallSignalIp6Address)
|
||||
{
|
||||
OOTRACEERR3("Error:Memory - ooH323MakeCall_helper - srcCallSignal6Address"
|
||||
"(%s, %s)\n", call->callType, call->callToken);
|
||||
return OO_FAILED;
|
||||
}
|
||||
inet_pton(AF_INET6, call->localIP, srcCallSignalIp6Address->ip.data);
|
||||
|
||||
srcCallSignalIp6Address->ip.numocts=16;
|
||||
srcCallSignalIp6Address->port= call->pH225Channel->port;
|
||||
setup->sourceCallSignalAddress.u.ip6Address = srcCallSignalIp6Address;
|
||||
} else {
|
||||
setup->sourceCallSignalAddress.t=T_H225TransportAddress_ipAddress;
|
||||
srcCallSignalIpAddress = (H225TransportAddress_ipAddress*)memAlloc(pctxt,
|
||||
sizeof(H225TransportAddress_ipAddress));
|
||||
if(!srcCallSignalIpAddress)
|
||||
{
|
||||
if(!srcCallSignalIpAddress)
|
||||
{
|
||||
OOTRACEERR3("Error:Memory - ooH323MakeCall_helper - srcCallSignalAddress"
|
||||
"(%s, %s)\n", call->callType, call->callToken);
|
||||
return OO_FAILED;
|
||||
}
|
||||
ooSocketConvertIpToNwAddr(call->localIP, srcCallSignalIpAddress->ip.data);
|
||||
}
|
||||
inet_pton(AF_INET, call->localIP, srcCallSignalIpAddress->ip.data);
|
||||
|
||||
srcCallSignalIpAddress->ip.numocts=4;
|
||||
srcCallSignalIpAddress->port= call->pH225Channel->port;
|
||||
setup->sourceCallSignalAddress.u.ipAddress = srcCallSignalIpAddress;
|
||||
setup->m.sourceCallSignalAddressPresent=TRUE;
|
||||
srcCallSignalIpAddress->ip.numocts=4;
|
||||
srcCallSignalIpAddress->port= call->pH225Channel->port;
|
||||
setup->sourceCallSignalAddress.u.ipAddress = srcCallSignalIpAddress;
|
||||
}
|
||||
/* No fast start */
|
||||
if(!OO_TESTFLAG(call->flags, OO_M_FASTSTART))
|
||||
{
|
||||
|
@ -2845,8 +2951,9 @@ int ooH323ForwardCall(char* callToken, char *dest)
|
|||
H225Facility_UUIE *facility=NULL;
|
||||
OOCTXT *pctxt = &gH323ep.msgctxt;
|
||||
OOH323CallData *call;
|
||||
char ip[30]="\0", *pcPort=NULL;
|
||||
char ip[2+8*4+7]="\0", *pcPort=NULL;
|
||||
H225TransportAddress_ipAddress *fwdCallSignalIpAddress;
|
||||
H225TransportAddress_ip6Address *fwdCallSignalIp6Address;
|
||||
|
||||
call= ooFindCallByToken(callToken);
|
||||
if(!call)
|
||||
|
@ -2865,7 +2972,7 @@ int ooH323ForwardCall(char* callToken, char *dest)
|
|||
return OO_FAILED;
|
||||
}
|
||||
|
||||
ret = ooParseDestination(call, dest, ip, 20,
|
||||
ret = ooParseDestination(call, dest, ip, 2+8*4+7,
|
||||
&call->pCallFwdData->aliases);
|
||||
if(ret != OO_OK)
|
||||
{
|
||||
|
@ -2877,7 +2984,7 @@ int ooH323ForwardCall(char* callToken, char *dest)
|
|||
|
||||
if(!ooUtilsIsStrEmpty(ip))
|
||||
{
|
||||
pcPort = strchr(ip, ':');
|
||||
pcPort = strrchr(ip, ':');
|
||||
if(pcPort)
|
||||
{
|
||||
*pcPort = '\0';
|
||||
|
@ -2941,21 +3048,39 @@ int ooH323ForwardCall(char* callToken, char *dest)
|
|||
if(!ooUtilsIsStrEmpty(call->pCallFwdData->ip))
|
||||
{
|
||||
facility->m.alternativeAddressPresent = TRUE;
|
||||
facility->alternativeAddress.t=T_H225TransportAddress_ipAddress;
|
||||
fwdCallSignalIpAddress = (H225TransportAddress_ipAddress*)memAlloc(pctxt,
|
||||
if (call->versionIP == 6) {
|
||||
facility->alternativeAddress.t=T_H225TransportAddress_ip6Address;
|
||||
fwdCallSignalIp6Address = (H225TransportAddress_ip6Address*)memAlloc(pctxt,
|
||||
sizeof(H225TransportAddress_ip6Address));
|
||||
if(!fwdCallSignalIp6Address)
|
||||
{
|
||||
OOTRACEERR3("Error:Memory - ooH323ForwardCall - fwdCallSignal6Address"
|
||||
"(%s, %s)\n", call->callType, call->callToken);
|
||||
return OO_FAILED;
|
||||
}
|
||||
inet_pton(AF_INET6, call->pCallFwdData->ip,
|
||||
fwdCallSignalIp6Address->ip.data);
|
||||
|
||||
fwdCallSignalIp6Address->ip.numocts=16;
|
||||
fwdCallSignalIp6Address->port = call->pCallFwdData->port;
|
||||
facility->alternativeAddress.u.ip6Address = fwdCallSignalIp6Address;
|
||||
} else {
|
||||
facility->alternativeAddress.t=T_H225TransportAddress_ipAddress;
|
||||
fwdCallSignalIpAddress = (H225TransportAddress_ipAddress*)memAlloc(pctxt,
|
||||
sizeof(H225TransportAddress_ipAddress));
|
||||
if(!fwdCallSignalIpAddress)
|
||||
{
|
||||
if(!fwdCallSignalIpAddress)
|
||||
{
|
||||
OOTRACEERR3("Error:Memory - ooH323ForwardCall - fwdCallSignalAddress"
|
||||
"(%s, %s)\n", call->callType, call->callToken);
|
||||
return OO_FAILED;
|
||||
}
|
||||
ooSocketConvertIpToNwAddr(call->pCallFwdData->ip,
|
||||
}
|
||||
inet_pton(AF_INET, call->pCallFwdData->ip,
|
||||
fwdCallSignalIpAddress->ip.data);
|
||||
|
||||
fwdCallSignalIpAddress->ip.numocts=4;
|
||||
fwdCallSignalIpAddress->port = call->pCallFwdData->port;
|
||||
facility->alternativeAddress.u.ipAddress = fwdCallSignalIpAddress;
|
||||
fwdCallSignalIpAddress->ip.numocts=4;
|
||||
fwdCallSignalIpAddress->port = call->pCallFwdData->port;
|
||||
facility->alternativeAddress.u.ipAddress = fwdCallSignalIpAddress;
|
||||
}
|
||||
}
|
||||
|
||||
if(call->pCallFwdData->aliases)
|
||||
|
@ -3469,6 +3594,7 @@ int ooParseDestination
|
|||
char tmp[256], buf[30];
|
||||
char *alias=NULL;
|
||||
OOCTXT *pctxt = call->pctxt;
|
||||
struct ast_sockaddr tmpaddr;
|
||||
parsedIP[0] = '\0';
|
||||
|
||||
OOTRACEINFO2("Parsing destination %s\n", dest);
|
||||
|
@ -3498,6 +3624,19 @@ int ooParseDestination
|
|||
return OO_OK;
|
||||
}
|
||||
|
||||
if (!ast_parse_arg(dest, PARSE_ADDR, &tmpaddr)) {
|
||||
if(strlen(dest)+7>len)
|
||||
{
|
||||
OOTRACEERR1("Error:Insufficient buffer space for parsed ip - "
|
||||
"ooParseDestination\n");
|
||||
return OO_FAILED;
|
||||
}
|
||||
strcpy(parsedIP, ast_sockaddr_stringify_addr(&tmpaddr));
|
||||
strcat(parsedIP, ":");
|
||||
strcat(parsedIP, ast_sockaddr_stringify_port(&tmpaddr));
|
||||
return OO_OK;
|
||||
}
|
||||
|
||||
/* alias@host */
|
||||
strncpy(tmp, dest, sizeof(tmp)-1);
|
||||
tmp[sizeof(tmp)-1]='\0';
|
||||
|
|
|
@ -143,7 +143,7 @@ typedef enum OOCallClearReason {
|
|||
#define OOTERMTYPE 60
|
||||
|
||||
/** Maximum length of an IP address (xxx.xxx.xxx.xxx). */
|
||||
#define MAX_IP_LENGTH 15
|
||||
#define MAX_IP_LENGTH 2+8*4+7
|
||||
|
||||
/** Maximum length of a log file message */
|
||||
#define MAXLOGMSGLEN 2048
|
||||
|
|
|
@ -398,7 +398,7 @@ static struct ast_variable *realtime_mysql(const char *database, const char *tab
|
|||
} else if (ast_strlen_zero(row[i])) {
|
||||
row[i] = " ";
|
||||
}
|
||||
for (stringp = ast_strdupa(row[i]), chunk = strsep(&stringp, ";"); chunk; chunk = strsep(&stringp, ";")) {
|
||||
for (stringp = row[i], chunk = strsep(&stringp, ";"); chunk; chunk = strsep(&stringp, ";")) {
|
||||
if (prev) {
|
||||
if ((prev->next = ast_variable_new(fields[i].name, decode_chunk(chunk), ""))) {
|
||||
prev = prev->next;
|
||||
|
@ -524,7 +524,7 @@ static struct ast_config *realtime_multi_mysql(const char *database, const char
|
|||
for (i = 0; i < numFields; i++) {
|
||||
if (ast_strlen_zero(row[i]))
|
||||
continue;
|
||||
for (stringp = ast_strdupa(row[i]), chunk = strsep(&stringp, ";"); chunk; chunk = strsep(&stringp, ";")) {
|
||||
for (stringp = row[i], chunk = strsep(&stringp, ";"); chunk; chunk = strsep(&stringp, ";")) {
|
||||
if (chunk && !ast_strlen_zero(decode_chunk(ast_strip(chunk)))) {
|
||||
if (initfield && !strcmp(initfield, fields[i].name)) {
|
||||
ast_category_rename(cat, chunk);
|
||||
|
@ -608,7 +608,7 @@ static int update_mysql(const char *database, const char *tablename, const char
|
|||
If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
|
||||
|
||||
ESCAPE_STRING(buf, newval);
|
||||
ast_str_set(&sql, 0, "UPDATE %s SET %s = '%s'", tablename, newparam, ast_str_buffer(buf));
|
||||
ast_str_set(&sql, 0, "UPDATE %s SET `%s` = '%s'", tablename, newparam, ast_str_buffer(buf));
|
||||
|
||||
/* If the column length isn't long enough, give a chance to lengthen it. */
|
||||
if (strncmp(column->type, "char", 4) == 0 || strncmp(column->type, "varchar", 7) == 0) {
|
||||
|
@ -625,7 +625,7 @@ static int update_mysql(const char *database, const char *tablename, const char
|
|||
}
|
||||
|
||||
ESCAPE_STRING(buf, newval);
|
||||
ast_str_append(&sql, 0, ", %s = '%s'", newparam, ast_str_buffer(buf));
|
||||
ast_str_append(&sql, 0, ", `%s` = '%s'", newparam, ast_str_buffer(buf));
|
||||
|
||||
/* If the column length isn't long enough, give a chance to lengthen it. */
|
||||
if (strncmp(column->type, "char", 4) == 0 || strncmp(column->type, "varchar", 7) == 0) {
|
||||
|
@ -635,7 +635,7 @@ static int update_mysql(const char *database, const char *tablename, const char
|
|||
va_end(ap);
|
||||
|
||||
ESCAPE_STRING(buf, lookup);
|
||||
ast_str_append(&sql, 0, " WHERE %s = '%s'", keyfield, ast_str_buffer(buf));
|
||||
ast_str_append(&sql, 0, " WHERE `%s` = '%s'", keyfield, ast_str_buffer(buf));
|
||||
|
||||
ast_debug(1, "MySQL RealTime: Update SQL: %s\n", ast_str_buffer(sql));
|
||||
|
||||
|
@ -719,7 +719,7 @@ static int update2_mysql(const char *database, const char *tablename, va_list ap
|
|||
return -1;
|
||||
}
|
||||
ESCAPE_STRING(buf, newval);
|
||||
ast_str_append(&where, 0, "%s %s='%s'", first ? "" : " AND", newparam, ast_str_buffer(buf));
|
||||
ast_str_append(&where, 0, "%s `%s` = '%s'", first ? "" : " AND", newparam, ast_str_buffer(buf));
|
||||
first = 0;
|
||||
|
||||
/* If the column length isn't long enough, give a chance to lengthen it. */
|
||||
|
@ -744,7 +744,7 @@ static int update2_mysql(const char *database, const char *tablename, va_list ap
|
|||
}
|
||||
|
||||
ESCAPE_STRING(buf, newval);
|
||||
ast_str_append(&sql, 0, "%s %s = '%s'", first ? "" : ",", newparam, ast_str_buffer(buf));
|
||||
ast_str_append(&sql, 0, "%s `%s` = '%s'", first ? "" : ",", newparam, ast_str_buffer(buf));
|
||||
first = 0;
|
||||
|
||||
/* If the column length isn't long enough, give a chance to lengthen it. */
|
||||
|
@ -816,7 +816,7 @@ static int store_mysql(const char *database, const char *table, va_list ap)
|
|||
/* Create the first part of the query using the first parameter/value pairs we just extracted
|
||||
If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
|
||||
ESCAPE_STRING(buf, newval);
|
||||
ast_str_set(&sql, 0, "INSERT INTO %s (%s", table, newparam);
|
||||
ast_str_set(&sql, 0, "INSERT INTO %s (`%s`", table, newparam);
|
||||
ast_str_set(&sql2, 0, ") VALUES ('%s'", ast_str_buffer(buf));
|
||||
|
||||
internal_require(database, table, newparam, RQ_CHAR, ast_str_strlen(buf), SENTINEL);
|
||||
|
@ -828,7 +828,7 @@ static int store_mysql(const char *database, const char *table, va_list ap)
|
|||
ast_str_reset(buf);
|
||||
}
|
||||
if (internal_require(database, table, newparam, RQ_CHAR, ast_str_strlen(buf), SENTINEL) == 0) {
|
||||
ast_str_append(&sql, 0, ", %s", newparam);
|
||||
ast_str_append(&sql, 0, ", `%s`", newparam);
|
||||
ast_str_append(&sql2, 0, ", '%s'", ast_str_buffer(buf));
|
||||
}
|
||||
}
|
||||
|
@ -894,11 +894,11 @@ static int destroy_mysql(const char *database, const char *table, const char *ke
|
|||
/* Create the first part of the query using the first parameter/value pairs we just extracted
|
||||
If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
|
||||
ESCAPE_STRING(buf, lookup);
|
||||
ast_str_set(&sql, 0, "DELETE FROM %s WHERE %s = '%s'", table, keyfield, ast_str_buffer(buf));
|
||||
ast_str_set(&sql, 0, "DELETE FROM %s WHERE `%s` = '%s'", table, keyfield, ast_str_buffer(buf));
|
||||
while ((newparam = va_arg(ap, const char *))) {
|
||||
newval = va_arg(ap, const char *);
|
||||
ESCAPE_STRING(buf, newval);
|
||||
ast_str_append(&sql, 0, " AND %s = '%s'", newparam, ast_str_buffer(buf));
|
||||
ast_str_append(&sql, 0, " AND `%s` = '%s'", newparam, ast_str_buffer(buf));
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
|
@ -1074,7 +1074,7 @@ static int modify_mysql(const char *database, const char *tablename, struct colu
|
|||
res = -1;
|
||||
break;
|
||||
}
|
||||
ast_str_set(&sql, 0, "ALTER TABLE %s MODIFY %s %s", tablename, column->name, ast_str_buffer(typestr));
|
||||
ast_str_set(&sql, 0, "ALTER TABLE %s MODIFY `%s` %s", tablename, column->name, ast_str_buffer(typestr));
|
||||
if (!column->null) {
|
||||
ast_str_append(&sql, 0, " NOT NULL");
|
||||
}
|
||||
|
|
|
@ -27,6 +27,12 @@ all: _all
|
|||
|
||||
include $(ASTTOPDIR)/Makefile.moddir_rules
|
||||
|
||||
clean::
|
||||
rm -f confbridge/*.o confbridge/*.i
|
||||
|
||||
$(if $(filter app_confbridge,$(EMBEDDED_MODS)),modules.link,app_confbridge.so): $(subst .c,.o,$(wildcard confbridge/*.c))
|
||||
$(subst .c,.o,$(wildcard confbridge/*.c)): _ASTCFLAGS+=$(call MOD_ASTCFLAGS,app_confbridge)
|
||||
|
||||
ifneq ($(findstring $(OSARCH), mingw32 cygwin ),)
|
||||
LIBS+= -lres_features.so -lres_ael_share.so -lres_monitor.so -lres_speech.so
|
||||
LIBS+= -lres_smdi.so
|
||||
|
|
|
@ -157,7 +157,6 @@ static void isAnsweringMachine(struct ast_channel *chan, const char *data)
|
|||
int iTotalTime = 0;
|
||||
int iWordsCount = 0;
|
||||
int currentState = STATE_IN_WORD;
|
||||
int previousState = STATE_IN_SILENCE;
|
||||
int consecutiveVoiceDuration = 0;
|
||||
char amdCause[256] = "", amdStatus[256] = "";
|
||||
char *parse = ast_strdupa(data);
|
||||
|
@ -303,7 +302,6 @@ static void isAnsweringMachine(struct ast_channel *chan, const char *data)
|
|||
|
||||
if (silenceDuration >= betweenWordsSilence) {
|
||||
if (currentState != STATE_IN_SILENCE ) {
|
||||
previousState = currentState;
|
||||
ast_verb(3, "AMD: Channel [%s]. Changed state to STATE_IN_SILENCE\n", chan->name);
|
||||
}
|
||||
/* Find words less than word duration */
|
||||
|
@ -343,7 +341,6 @@ static void isAnsweringMachine(struct ast_channel *chan, const char *data)
|
|||
if (consecutiveVoiceDuration >= minimumWordLength && currentState == STATE_IN_SILENCE) {
|
||||
iWordsCount++;
|
||||
ast_verb(3, "AMD: Channel [%s]. Word detected. iWordsCount:%d\n", chan->name, iWordsCount);
|
||||
previousState = currentState;
|
||||
currentState = STATE_IN_WORD;
|
||||
}
|
||||
if (consecutiveVoiceDuration >= maximumWordLength){
|
||||
|
|
|
@ -404,6 +404,7 @@ struct chanspy_translation_helper {
|
|||
struct ast_audiohook bridge_whisper_audiohook;
|
||||
int fd;
|
||||
int volfactor;
|
||||
struct ast_flags flags;
|
||||
};
|
||||
|
||||
struct spy_dtmf_options {
|
||||
|
@ -438,7 +439,7 @@ static int spy_generate(struct ast_channel *chan, void *data, int len, int sampl
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (ast_test_flag(&csth->spy_audiohook, OPTION_READONLY)) {
|
||||
if (ast_test_flag(&csth->flags, OPTION_READONLY)) {
|
||||
/* Option 'o' was set, so don't mix channel audio */
|
||||
f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_READ, &format_slin);
|
||||
} else {
|
||||
|
@ -539,7 +540,7 @@ static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_auto
|
|||
spyer_name, name);
|
||||
|
||||
memset(&csth, 0, sizeof(csth));
|
||||
ast_copy_flags(&csth.spy_audiohook, flags, AST_FLAGS_ALL);
|
||||
ast_copy_flags(&csth.flags, flags, AST_FLAGS_ALL);
|
||||
|
||||
ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy", 0);
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -768,12 +768,16 @@ static void senddialevent(struct ast_channel *src, struct ast_channel *dst, cons
|
|||
"Destination: %s\r\n"
|
||||
"CallerIDNum: %s\r\n"
|
||||
"CallerIDName: %s\r\n"
|
||||
"ConnectedLineNum: %s\r\n"
|
||||
"ConnectedLineName: %s\r\n"
|
||||
"UniqueID: %s\r\n"
|
||||
"DestUniqueID: %s\r\n"
|
||||
"Dialstring: %s\r\n",
|
||||
src->name, dst->name,
|
||||
S_COR(src->caller.id.number.valid, src->caller.id.number.str, "<unknown>"),
|
||||
S_COR(src->caller.id.name.valid, src->caller.id.name.str, "<unknown>"),
|
||||
S_COR(src->connected.id.number.valid, src->connected.id.number.str, "<unknown>"),
|
||||
S_COR(src->connected.id.name.valid, src->connected.id.name.str, "<unknown>"),
|
||||
src->uniqueid, dst->uniqueid,
|
||||
dialstring ? dialstring : "");
|
||||
}
|
||||
|
@ -1244,14 +1248,17 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
|
|||
/* Setup early media if appropriate */
|
||||
if (single && CAN_EARLY_BRIDGE(peerflags, in, c))
|
||||
ast_channel_early_bridge(in, c);
|
||||
if (!ast_test_flag64(outgoing, OPT_RINGBACK))
|
||||
if (!ast_test_flag64(outgoing, OPT_RINGBACK)) {
|
||||
if (single || (!single && !pa->sentringing)) {
|
||||
ast_indicate(in, AST_CONTROL_PROGRESS);
|
||||
}
|
||||
if(!ast_strlen_zero(dtmf_progress)) {
|
||||
ast_verb(3, "Sending DTMF '%s' to the called party as result of receiving a PROGRESS message.\n", dtmf_progress);
|
||||
ast_dtmf_stream(c, in, dtmf_progress, 250, 0);
|
||||
}
|
||||
}
|
||||
if (!ast_strlen_zero(dtmf_progress)) {
|
||||
ast_verb(3,
|
||||
"Sending DTMF '%s' to the called party as result of receiving a PROGRESS message.\n",
|
||||
dtmf_progress);
|
||||
ast_dtmf_stream(c, in, dtmf_progress, 250, 0);
|
||||
}
|
||||
break;
|
||||
case AST_CONTROL_VIDUPDATE:
|
||||
ast_verb(3, "%s requested a video update, passing it to %s\n", c->name, in->name);
|
||||
|
@ -1418,12 +1425,17 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
|
|||
}
|
||||
}
|
||||
|
||||
if (single) {
|
||||
/* Send the frame from the in channel to all outgoing channels. */
|
||||
for (o = outgoing; o; o = o->next) {
|
||||
if (!o->chan || !ast_test_flag64(o, DIAL_STILLGOING)) {
|
||||
/* This outgoing channel has died so don't send the frame to it. */
|
||||
continue;
|
||||
}
|
||||
switch (f->frametype) {
|
||||
case AST_FRAME_HTML:
|
||||
/* Forward HTML stuff */
|
||||
if (!ast_test_flag64(outgoing, DIAL_NOFORWARDHTML)
|
||||
&& ast_channel_sendhtml(outgoing->chan, f->subclass.integer, f->data.ptr, f->datalen) == -1) {
|
||||
if (!ast_test_flag64(o, DIAL_NOFORWARDHTML)
|
||||
&& ast_channel_sendhtml(o->chan, f->subclass.integer, f->data.ptr, f->datalen) == -1) {
|
||||
ast_log(LOG_WARNING, "Unable to send URL\n");
|
||||
}
|
||||
break;
|
||||
|
@ -1432,7 +1444,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
|
|||
case AST_FRAME_TEXT:
|
||||
case AST_FRAME_DTMF_BEGIN:
|
||||
case AST_FRAME_DTMF_END:
|
||||
if (ast_write(outgoing->chan, f)) {
|
||||
if (ast_write(o->chan, f)) {
|
||||
ast_log(LOG_WARNING, "Unable to forward frametype: %d\n",
|
||||
f->frametype);
|
||||
}
|
||||
|
@ -1443,17 +1455,18 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
|
|||
case AST_CONTROL_UNHOLD:
|
||||
case AST_CONTROL_VIDUPDATE:
|
||||
case AST_CONTROL_SRCUPDATE:
|
||||
ast_verb(3, "%s requested special control %d, passing it to %s\n", in->name, f->subclass.integer, outgoing->chan->name);
|
||||
ast_indicate_data(outgoing->chan, f->subclass.integer, f->data.ptr, f->datalen);
|
||||
ast_verb(3, "%s requested special control %d, passing it to %s\n",
|
||||
in->name, f->subclass.integer, o->chan->name);
|
||||
ast_indicate_data(o->chan, f->subclass.integer, f->data.ptr, f->datalen);
|
||||
break;
|
||||
case AST_CONTROL_CONNECTED_LINE:
|
||||
if (ast_channel_connected_line_macro(in, outgoing->chan, f, 0, 1)) {
|
||||
ast_indicate_data(outgoing->chan, f->subclass.integer, f->data.ptr, f->datalen);
|
||||
if (ast_channel_connected_line_macro(in, o->chan, f, 0, 1)) {
|
||||
ast_indicate_data(o->chan, f->subclass.integer, f->data.ptr, f->datalen);
|
||||
}
|
||||
break;
|
||||
case AST_CONTROL_REDIRECTING:
|
||||
if (ast_channel_redirecting_macro(in, outgoing->chan, f, 0, 1)) {
|
||||
ast_indicate_data(outgoing->chan, f->subclass.integer, f->data.ptr, f->datalen);
|
||||
if (ast_channel_redirecting_macro(in, o->chan, f, 0, 1)) {
|
||||
ast_indicate_data(o->chan, f->subclass.integer, f->data.ptr, f->datalen);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -1939,7 +1952,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
|
|||
pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status);
|
||||
goto done;
|
||||
}
|
||||
ast_verb(3, "Setting call duration limit to %.3lf milliseconds.\n", calldurationlimit.tv_sec + calldurationlimit.tv_usec / 1000000.0);
|
||||
ast_verb(3, "Setting call duration limit to %.3lf seconds.\n", calldurationlimit.tv_sec + calldurationlimit.tv_usec / 1000000.0);
|
||||
}
|
||||
|
||||
if (ast_test_flag64(&opts, OPT_SENDDTMF) && !ast_strlen_zero(opt_args[OPT_ARG_SENDDTMF])) {
|
||||
|
@ -2234,6 +2247,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
|
|||
* No hint name available. We have a connected name supplied by
|
||||
* the dialplan we can use instead.
|
||||
*/
|
||||
caller.id.name.valid = 1;
|
||||
caller.id.name = chan->connected.id.name;
|
||||
}
|
||||
ast_channel_set_caller_event(tc, &caller, NULL);
|
||||
|
@ -2247,6 +2261,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
|
|||
* We have a connected name supplied by the dialplan we can
|
||||
* use instead.
|
||||
*/
|
||||
caller.id.name.valid = 1;
|
||||
caller.id.name = chan->connected.id.name;
|
||||
ast_channel_set_caller_event(tc, &caller, NULL);
|
||||
}
|
||||
|
@ -2390,8 +2405,11 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
|
|||
* to which the datastore was moved hangs up, it will attempt to free this
|
||||
* datastore again, causing a crash
|
||||
*/
|
||||
if (!ast_channel_datastore_remove(chan, datastore))
|
||||
ast_channel_lock(chan);
|
||||
if (!ast_channel_datastore_remove(chan, datastore)) {
|
||||
ast_datastore_free(datastore);
|
||||
}
|
||||
ast_channel_unlock(chan);
|
||||
if (!peer) {
|
||||
if (result) {
|
||||
res = result;
|
||||
|
|
|
@ -97,60 +97,17 @@ static const char app[] = "Pickup";
|
|||
static const char app2[] = "PickupChan";
|
||||
/*! \todo This application should return a result code, like PICKUPRESULT */
|
||||
|
||||
/* Perform actual pickup between two channels */
|
||||
static int pickup_do(struct ast_channel *chan, struct ast_channel *target)
|
||||
{
|
||||
int res = 0;
|
||||
struct ast_party_connected_line connected_caller;
|
||||
struct ast_channel *chans[2] = { chan, target };
|
||||
|
||||
ast_debug(1, "Call pickup on '%s' by '%s'\n", target->name, chan->name);
|
||||
ast_cel_report_event(target, AST_CEL_PICKUP, NULL, NULL, chan);
|
||||
|
||||
ast_party_connected_line_init(&connected_caller);
|
||||
ast_party_connected_line_copy(&connected_caller, &target->connected);
|
||||
connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
|
||||
if (ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) {
|
||||
ast_channel_update_connected_line(chan, &connected_caller, NULL);
|
||||
}
|
||||
ast_party_connected_line_free(&connected_caller);
|
||||
|
||||
ast_channel_lock(chan);
|
||||
ast_connected_line_copy_from_caller(&connected_caller, &chan->caller);
|
||||
ast_channel_unlock(chan);
|
||||
connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
|
||||
ast_channel_queue_connected_line_update(chan, &connected_caller, NULL);
|
||||
ast_party_connected_line_free(&connected_caller);
|
||||
|
||||
if ((res = ast_answer(chan))) {
|
||||
ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((res = ast_queue_control(chan, AST_CONTROL_ANSWER))) {
|
||||
ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((res = ast_channel_masquerade(target, chan))) {
|
||||
ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, target->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* If you want UniqueIDs, set channelvars in manager.conf to CHANNEL(uniqueid) */
|
||||
ast_manager_event_multichan(EVENT_FLAG_CALL, "Pickup", 2, chans,
|
||||
"Channel: %s\r\nTargetChannel: %s\r\n", chan->name, target->name);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Helper function that determines whether a channel is capable of being picked up */
|
||||
static int can_pickup(struct ast_channel *chan)
|
||||
{
|
||||
if (!chan->pbx && (chan->_state == AST_STATE_RINGING || chan->_state == AST_STATE_RING || chan->_state == AST_STATE_DOWN))
|
||||
if (!chan->pbx && !chan->masq &&
|
||||
!ast_test_flag(chan, AST_FLAG_ZOMBIE) &&
|
||||
(chan->_state == AST_STATE_RINGING ||
|
||||
chan->_state == AST_STATE_RING ||
|
||||
chan->_state == AST_STATE_DOWN)) {
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct pickup_by_name_args {
|
||||
|
@ -160,15 +117,15 @@ struct pickup_by_name_args {
|
|||
|
||||
static int pickup_by_name_cb(void *obj, void *arg, void *data, int flags)
|
||||
{
|
||||
struct ast_channel *chan = obj;
|
||||
struct ast_channel *target = obj;/*!< Potential pickup target */
|
||||
struct pickup_by_name_args *args = data;
|
||||
|
||||
ast_channel_lock(chan);
|
||||
if (!strncasecmp(chan->name, args->name, args->len) && can_pickup(chan)) {
|
||||
ast_channel_lock(target);
|
||||
if (!strncasecmp(target->name, args->name, args->len) && can_pickup(target)) {
|
||||
/* Return with the channel still locked on purpose */
|
||||
return CMP_MATCH | CMP_STOP;
|
||||
}
|
||||
ast_channel_unlock(chan);
|
||||
ast_channel_unlock(target);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -201,31 +158,29 @@ static struct ast_channel *my_ast_get_channel_by_name_locked(const char *channam
|
|||
return ast_channel_callback(pickup_by_name_cb, NULL, &pickup_args, 0);
|
||||
}
|
||||
|
||||
/*! \brief Attempt to pick up specified channel named , does not use context */
|
||||
/*! \brief Attempt to pick up named channel, does not use context */
|
||||
static int pickup_by_channel(struct ast_channel *chan, char *pickup)
|
||||
{
|
||||
int res = 0;
|
||||
struct ast_channel *target;
|
||||
int res = -1;
|
||||
struct ast_channel *target;/*!< Potential pickup target */
|
||||
|
||||
if (!(target = my_ast_get_channel_by_name_locked(pickup))) {
|
||||
return -1;
|
||||
target = my_ast_get_channel_by_name_locked(pickup);
|
||||
if (target) {
|
||||
/* Just check that we are not picking up the SAME as target. (i.e. ourself) */
|
||||
if (chan != target) {
|
||||
res = ast_do_pickup(chan, target);
|
||||
}
|
||||
ast_channel_unlock(target);
|
||||
target = ast_channel_unref(target);
|
||||
}
|
||||
|
||||
/* Just check that we are not picking up the SAME as target */
|
||||
if (chan != target) {
|
||||
res = pickup_do(chan, target);
|
||||
}
|
||||
|
||||
ast_channel_unlock(target);
|
||||
target = ast_channel_unref(target);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Attempt to pick up specified extension with context */
|
||||
static int pickup_by_exten(struct ast_channel *chan, const char *exten, const char *context)
|
||||
{
|
||||
struct ast_channel *target = NULL;
|
||||
struct ast_channel *target = NULL;/*!< Potential pickup target */
|
||||
struct ast_channel_iterator *iter;
|
||||
int res = -1;
|
||||
|
||||
|
@ -236,6 +191,7 @@ static int pickup_by_exten(struct ast_channel *chan, const char *exten, const ch
|
|||
while ((target = ast_channel_iterator_next(iter))) {
|
||||
ast_channel_lock(target);
|
||||
if ((chan != target) && can_pickup(target)) {
|
||||
ast_log(LOG_NOTICE, "%s pickup by %s\n", target->name, chan->name);
|
||||
break;
|
||||
}
|
||||
ast_channel_unlock(target);
|
||||
|
@ -245,7 +201,7 @@ static int pickup_by_exten(struct ast_channel *chan, const char *exten, const ch
|
|||
ast_channel_iterator_destroy(iter);
|
||||
|
||||
if (target) {
|
||||
res = pickup_do(chan, target);
|
||||
res = ast_do_pickup(chan, target);
|
||||
ast_channel_unlock(target);
|
||||
target = ast_channel_unref(target);
|
||||
}
|
||||
|
@ -255,31 +211,63 @@ static int pickup_by_exten(struct ast_channel *chan, const char *exten, const ch
|
|||
|
||||
static int find_by_mark(void *obj, void *arg, void *data, int flags)
|
||||
{
|
||||
struct ast_channel *c = obj;
|
||||
struct ast_channel *target = obj;/*!< Potential pickup target */
|
||||
const char *mark = data;
|
||||
const char *tmp;
|
||||
int res;
|
||||
|
||||
ast_channel_lock(c);
|
||||
ast_channel_lock(target);
|
||||
tmp = pbx_builtin_getvar_helper(target, PICKUPMARK);
|
||||
if (tmp && !strcasecmp(tmp, mark) && can_pickup(target)) {
|
||||
/* Return with the channel still locked on purpose */
|
||||
return CMP_MATCH | CMP_STOP;
|
||||
}
|
||||
ast_channel_unlock(target);
|
||||
|
||||
res = (tmp = pbx_builtin_getvar_helper(c, PICKUPMARK)) &&
|
||||
!strcasecmp(tmp, mark) &&
|
||||
can_pickup(c);
|
||||
|
||||
ast_channel_unlock(c);
|
||||
|
||||
return res ? CMP_MATCH | CMP_STOP : 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Attempt to pick up specified mark */
|
||||
static int pickup_by_mark(struct ast_channel *chan, const char *mark)
|
||||
{
|
||||
struct ast_channel *target;
|
||||
struct ast_channel *target;/*!< Potential pickup target */
|
||||
int res = -1;
|
||||
|
||||
if ((target = ast_channel_callback(find_by_mark, NULL, (char *) mark, 0))) {
|
||||
ast_channel_lock(target);
|
||||
res = pickup_do(chan, target);
|
||||
/* The found channel is already locked. */
|
||||
target = ast_channel_callback(find_by_mark, NULL, (char *) mark, 0);
|
||||
if (target) {
|
||||
res = ast_do_pickup(chan, target);
|
||||
ast_channel_unlock(target);
|
||||
target = ast_channel_unref(target);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int find_channel_by_group(void *obj, void *arg, void *data, int flags)
|
||||
{
|
||||
struct ast_channel *target = obj;/*!< Potential pickup target */
|
||||
struct ast_channel *chan = data;/*!< Channel wanting to pickup call */
|
||||
|
||||
ast_channel_lock(target);
|
||||
if (chan != target && (chan->pickupgroup & target->callgroup) && can_pickup(target)) {
|
||||
/* Return with the channel still locked on purpose */
|
||||
return CMP_MATCH | CMP_STOP;
|
||||
}
|
||||
ast_channel_unlock(target);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pickup_by_group(struct ast_channel *chan)
|
||||
{
|
||||
struct ast_channel *target;/*!< Potential pickup target */
|
||||
int res = -1;
|
||||
|
||||
/* The found channel is already locked. */
|
||||
target = ast_channel_callback(find_channel_by_group, NULL, chan, 0);
|
||||
if (target) {
|
||||
ast_log(LOG_NOTICE, "pickup %s attempt by %s\n", target->name, chan->name);
|
||||
res = ast_do_pickup(chan, target);
|
||||
ast_channel_unlock(target);
|
||||
target = ast_channel_unref(target);
|
||||
}
|
||||
|
@ -290,58 +278,63 @@ static int pickup_by_mark(struct ast_channel *chan, const char *mark)
|
|||
/* application entry point for Pickup() */
|
||||
static int pickup_exec(struct ast_channel *chan, const char *data)
|
||||
{
|
||||
int res = 0;
|
||||
char *tmp = ast_strdupa(data);
|
||||
char *exten = NULL, *context = NULL;
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
res = ast_pickup_call(chan);
|
||||
return res;
|
||||
return pickup_by_group(chan) ? 0 : -1;
|
||||
}
|
||||
|
||||
|
||||
/* Parse extension (and context if there) */
|
||||
while (!ast_strlen_zero(tmp) && (exten = strsep(&tmp, "&"))) {
|
||||
if ((context = strchr(exten, '@')))
|
||||
*context++ = '\0';
|
||||
if (!ast_strlen_zero(context) && !strcasecmp(context, PICKUPMARK)) {
|
||||
if (!pickup_by_mark(chan, exten))
|
||||
break;
|
||||
if (!pickup_by_mark(chan, exten)) {
|
||||
/* Pickup successful. Stop the dialplan this channel is a zombie. */
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (!pickup_by_exten(chan, exten, !ast_strlen_zero(context) ? context : chan->context))
|
||||
break;
|
||||
if (!pickup_by_exten(chan, exten, !ast_strlen_zero(context) ? context : chan->context)) {
|
||||
/* Pickup successful. Stop the dialplan this channel is a zombie. */
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
ast_log(LOG_NOTICE, "No target channel found for %s.\n", exten);
|
||||
}
|
||||
|
||||
return res;
|
||||
/* Pickup failed. Keep going in the dialplan. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Find channel for pick up specified by partial channel name */
|
||||
static int find_by_part(void *obj, void *arg, void *data, int flags)
|
||||
{
|
||||
struct ast_channel *c = obj;
|
||||
struct ast_channel *target = obj;/*!< Potential pickup target */
|
||||
const char *part = data;
|
||||
int res = 0;
|
||||
int len = strlen(part);
|
||||
|
||||
ast_channel_lock(c);
|
||||
if (len <= strlen(c->name)) {
|
||||
res = !(strncmp(c->name, part, len)) && (can_pickup(c));
|
||||
ast_channel_lock(target);
|
||||
if (len <= strlen(target->name) && !strncmp(target->name, part, len)
|
||||
&& can_pickup(target)) {
|
||||
/* Return with the channel still locked on purpose */
|
||||
return CMP_MATCH | CMP_STOP;
|
||||
}
|
||||
ast_channel_unlock(c);
|
||||
ast_channel_unlock(target);
|
||||
|
||||
return res ? CMP_MATCH | CMP_STOP : 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Attempt to pick up specified by partial channel name */
|
||||
static int pickup_by_part(struct ast_channel *chan, const char *part)
|
||||
{
|
||||
struct ast_channel *target;
|
||||
struct ast_channel *target;/*!< Potential pickup target */
|
||||
int res = -1;
|
||||
|
||||
if ((target = ast_channel_callback(find_by_part, NULL, (char *) part, 0))) {
|
||||
ast_channel_lock(target);
|
||||
res = pickup_do(chan, target);
|
||||
/* The found channel is already locked. */
|
||||
target = ast_channel_callback(find_by_part, NULL, (char *) part, 0);
|
||||
if (target) {
|
||||
res = ast_do_pickup(chan, target);
|
||||
ast_channel_unlock(target);
|
||||
target = ast_channel_unref(target);
|
||||
}
|
||||
|
@ -352,7 +345,6 @@ static int pickup_by_part(struct ast_channel *chan, const char *part)
|
|||
/* application entry point for PickupChan() */
|
||||
static int pickupchan_exec(struct ast_channel *chan, const char *data)
|
||||
{
|
||||
int res = 0;
|
||||
int partial_pickup = 0;
|
||||
char *pickup = NULL;
|
||||
char *parse = ast_strdupa(data);
|
||||
|
@ -364,7 +356,8 @@ static int pickupchan_exec(struct ast_channel *chan, const char *data)
|
|||
|
||||
if (ast_strlen_zero(args.channel)) {
|
||||
ast_log(LOG_WARNING, "PickupChan requires an argument (channel)!\n");
|
||||
return -1;
|
||||
/* Pickup failed. Keep going in the dialplan. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!ast_strlen_zero(args.options) && strchr(args.options, 'p')) {
|
||||
|
@ -378,16 +371,19 @@ static int pickupchan_exec(struct ast_channel *chan, const char *data)
|
|||
} else {
|
||||
if (partial_pickup) {
|
||||
if (!pickup_by_part(chan, pickup)) {
|
||||
break;
|
||||
/* Pickup successful. Stop the dialplan this channel is a zombie. */
|
||||
return -1;
|
||||
}
|
||||
} else if (!pickup_by_channel(chan, pickup)) {
|
||||
break;
|
||||
/* Pickup successful. Stop the dialplan this channel is a zombie. */
|
||||
return -1;
|
||||
}
|
||||
ast_log(LOG_NOTICE, "No target channel found for %s.\n", pickup);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
/* Pickup failed. Keep going in the dialplan. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
|
|
|
@ -36,6 +36,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
|||
#include "asterisk/module.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/translate.h"
|
||||
|
||||
/*** DOCUMENTATION
|
||||
<application name="DumpChan" language="en_US">
|
||||
|
@ -67,9 +68,11 @@ static int serialize_showchan(struct ast_channel *c, char *buf, size_t size)
|
|||
struct timeval now;
|
||||
long elapsed_seconds = 0;
|
||||
int hour = 0, min = 0, sec = 0;
|
||||
char cgrp[BUFSIZ/2];
|
||||
char pgrp[BUFSIZ/2];
|
||||
char formatbuf[BUFSIZ/2];
|
||||
char nf[256];
|
||||
char cgrp[256];
|
||||
char pgrp[256];
|
||||
struct ast_str *write_transpath = ast_str_alloca(256);
|
||||
struct ast_str *read_transpath = ast_str_alloca(256);
|
||||
|
||||
now = ast_tvnow();
|
||||
memset(buf, 0, size);
|
||||
|
@ -84,65 +87,83 @@ static int serialize_showchan(struct ast_channel *c, char *buf, size_t size)
|
|||
}
|
||||
|
||||
snprintf(buf,size,
|
||||
"Name= %s\n"
|
||||
"Type= %s\n"
|
||||
"UniqueID= %s\n"
|
||||
"CallerIDNum= %s\n"
|
||||
"CallerIDName= %s\n"
|
||||
"DNIDDigits= %s\n"
|
||||
"RDNIS= %s\n"
|
||||
"Parkinglot= %s\n"
|
||||
"Language= %s\n"
|
||||
"State= %s (%d)\n"
|
||||
"Rings= %d\n"
|
||||
"NativeFormat= %s\n"
|
||||
"WriteFormat= %s\n"
|
||||
"ReadFormat= %s\n"
|
||||
"RawWriteFormat= %s\n"
|
||||
"RawReadFormat= %s\n"
|
||||
"1stFileDescriptor= %d\n"
|
||||
"Framesin= %d %s\n"
|
||||
"Framesout= %d %s\n"
|
||||
"TimetoHangup= %ld\n"
|
||||
"ElapsedTime= %dh%dm%ds\n"
|
||||
"Context= %s\n"
|
||||
"Extension= %s\n"
|
||||
"Priority= %d\n"
|
||||
"CallGroup= %s\n"
|
||||
"PickupGroup= %s\n"
|
||||
"Application= %s\n"
|
||||
"Data= %s\n"
|
||||
"Blocking_in= %s\n",
|
||||
c->name,
|
||||
c->tech->type,
|
||||
c->uniqueid,
|
||||
S_COR(c->caller.id.number.valid, c->caller.id.number.str, "(N/A)"),
|
||||
S_COR(c->caller.id.name.valid, c->caller.id.name.str, "(N/A)"),
|
||||
S_OR(c->dialed.number.str, "(N/A)"),
|
||||
S_COR(c->redirecting.from.number.valid, c->redirecting.from.number.str, "(N/A)"),
|
||||
c->parkinglot,
|
||||
c->language,
|
||||
ast_state2str(c->_state),
|
||||
c->_state,
|
||||
c->rings,
|
||||
ast_getformatname_multiple(formatbuf, sizeof(formatbuf), c->nativeformats),
|
||||
ast_getformatname(&c->writeformat),
|
||||
ast_getformatname(&c->readformat),
|
||||
ast_getformatname(&c->rawwriteformat),
|
||||
ast_getformatname(&c->rawreadformat),
|
||||
c->fds[0], c->fin & ~DEBUGCHAN_FLAG, (c->fin & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "",
|
||||
c->fout & ~DEBUGCHAN_FLAG, (c->fout & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "", (long)c->whentohangup.tv_sec,
|
||||
hour,
|
||||
min,
|
||||
sec,
|
||||
c->context,
|
||||
c->exten,
|
||||
c->priority,
|
||||
ast_print_group(cgrp, sizeof(cgrp), c->callgroup),
|
||||
ast_print_group(pgrp, sizeof(pgrp), c->pickupgroup),
|
||||
( c->appl ? c->appl : "(N/A)" ),
|
||||
( c-> data ? S_OR(c->data, "(Empty)") : "(None)"),
|
||||
(ast_test_flag(c, AST_FLAG_BLOCKING) ? c->blockproc : "(Not Blocking)"));
|
||||
"Name= %s\n"
|
||||
"Type= %s\n"
|
||||
"UniqueID= %s\n"
|
||||
"LinkedID= %s\n"
|
||||
"CallerIDNum= %s\n"
|
||||
"CallerIDName= %s\n"
|
||||
"ConnectedLineIDNum= %s\n"
|
||||
"ConnectedLineIDName=%s\n"
|
||||
"DNIDDigits= %s\n"
|
||||
"RDNIS= %s\n"
|
||||
"Parkinglot= %s\n"
|
||||
"Language= %s\n"
|
||||
"State= %s (%d)\n"
|
||||
"Rings= %d\n"
|
||||
"NativeFormat= %s\n"
|
||||
"WriteFormat= %s\n"
|
||||
"ReadFormat= %s\n"
|
||||
"RawWriteFormat= %s\n"
|
||||
"RawReadFormat= %s\n"
|
||||
"WriteTranscode= %s %s\n"
|
||||
"ReadTranscode= %s %s\n"
|
||||
"1stFileDescriptor= %d\n"
|
||||
"Framesin= %d %s\n"
|
||||
"Framesout= %d %s\n"
|
||||
"TimetoHangup= %ld\n"
|
||||
"ElapsedTime= %dh%dm%ds\n"
|
||||
"DirectBridge= %s\n"
|
||||
"IndirectBridge= %s\n"
|
||||
"Context= %s\n"
|
||||
"Extension= %s\n"
|
||||
"Priority= %d\n"
|
||||
"CallGroup= %s\n"
|
||||
"PickupGroup= %s\n"
|
||||
"Application= %s\n"
|
||||
"Data= %s\n"
|
||||
"Blocking_in= %s\n",
|
||||
c->name,
|
||||
c->tech->type,
|
||||
c->uniqueid,
|
||||
c->linkedid,
|
||||
S_COR(c->caller.id.number.valid, c->caller.id.number.str, "(N/A)"),
|
||||
S_COR(c->caller.id.name.valid, c->caller.id.name.str, "(N/A)"),
|
||||
S_COR(c->connected.id.number.valid, c->connected.id.number.str, "(N/A)"),
|
||||
S_COR(c->connected.id.name.valid, c->connected.id.name.str, "(N/A)"),
|
||||
S_OR(c->dialed.number.str, "(N/A)"),
|
||||
S_COR(c->redirecting.from.number.valid, c->redirecting.from.number.str, "(N/A)"),
|
||||
c->parkinglot,
|
||||
c->language,
|
||||
ast_state2str(c->_state),
|
||||
c->_state,
|
||||
c->rings,
|
||||
ast_getformatname_multiple(nf, sizeof(nf), c->nativeformats),
|
||||
ast_getformatname(&c->writeformat),
|
||||
ast_getformatname(&c->readformat),
|
||||
ast_getformatname(&c->rawwriteformat),
|
||||
ast_getformatname(&c->rawreadformat),
|
||||
c->writetrans ? "Yes" : "No",
|
||||
ast_translate_path_to_str(c->writetrans, &write_transpath),
|
||||
c->readtrans ? "Yes" : "No",
|
||||
ast_translate_path_to_str(c->readtrans, &read_transpath),
|
||||
c->fds[0],
|
||||
c->fin & ~DEBUGCHAN_FLAG, (c->fin & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "",
|
||||
c->fout & ~DEBUGCHAN_FLAG, (c->fout & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "",
|
||||
(long)c->whentohangup.tv_sec,
|
||||
hour,
|
||||
min,
|
||||
sec,
|
||||
c->_bridge ? c->_bridge->name : "<none>",
|
||||
ast_bridged_channel(c) ? ast_bridged_channel(c)->name : "<none>",
|
||||
c->context,
|
||||
c->exten,
|
||||
c->priority,
|
||||
ast_print_group(cgrp, sizeof(cgrp), c->callgroup),
|
||||
ast_print_group(pgrp, sizeof(pgrp), c->pickupgroup),
|
||||
c->appl ? c->appl : "(N/A)",
|
||||
c->data ? S_OR(c->data, "(Empty)") : "(None)",
|
||||
(ast_test_flag(c, AST_FLAG_BLOCKING) ? c->blockproc : "(Not Blocking)"));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -150,7 +171,7 @@ static int serialize_showchan(struct ast_channel *c, char *buf, size_t size)
|
|||
static int dumpchan_exec(struct ast_channel *chan, const char *data)
|
||||
{
|
||||
struct ast_str *vars = ast_str_thread_get(&ast_str_thread_global_buf, 16);
|
||||
char info[1024];
|
||||
char info[2048];
|
||||
int level = 0;
|
||||
static char *line = "================================================================================";
|
||||
|
||||
|
@ -160,7 +181,13 @@ static int dumpchan_exec(struct ast_channel *chan, const char *data)
|
|||
if (option_verbose >= level) {
|
||||
serialize_showchan(chan, info, sizeof(info));
|
||||
pbx_builtin_serialize_variables(chan, &vars);
|
||||
ast_verbose("\nDumping Info For Channel: %s:\n%s\nInfo:\n%s\nVariables:\n%s%s\n", chan->name, line, info, ast_str_buffer(vars), line);
|
||||
ast_verbose("\n"
|
||||
"Dumping Info For Channel: %s:\n"
|
||||
"%s\n"
|
||||
"Info:\n"
|
||||
"%s\n"
|
||||
"Variables:\n"
|
||||
"%s%s\n", chan->name, line, info, ast_str_buffer(vars), line);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -255,6 +255,9 @@ static void phase_e_handler(t30_state_t *f, void *user_data, int result)
|
|||
"Channel: %s\r\n"
|
||||
"Exten: %s\r\n"
|
||||
"CallerID: %s\r\n"
|
||||
"CallerIDName: %s\r\n"
|
||||
"ConnectedLineNum: %s\r\n"
|
||||
"ConnectedLineName: %s\r\n"
|
||||
"RemoteStationID: %s\r\n"
|
||||
"LocalStationID: %s\r\n"
|
||||
"PagesTransferred: %d\r\n"
|
||||
|
@ -264,6 +267,9 @@ static void phase_e_handler(t30_state_t *f, void *user_data, int result)
|
|||
s->chan->name,
|
||||
s->chan->exten,
|
||||
S_COR(s->chan->caller.id.number.valid, s->chan->caller.id.number.str, ""),
|
||||
S_COR(s->chan->caller.id.name.valid, s->chan->caller.id.name.str, ""),
|
||||
S_COR(s->chan->connected.id.number.valid, s->chan->connected.id.number.str, ""),
|
||||
S_COR(s->chan->connected.id.name.valid, s->chan->connected.id.name.str, ""),
|
||||
far_ident,
|
||||
local_ident,
|
||||
pages_transferred,
|
||||
|
|
|
@ -163,7 +163,6 @@ static int send_waveform_to_channel(struct ast_channel *chan, char *waveform, in
|
|||
{
|
||||
int res = 0;
|
||||
int fds[2];
|
||||
int pid = -1;
|
||||
int needed = 0;
|
||||
struct ast_format owriteformat;
|
||||
struct ast_frame *f;
|
||||
|
@ -196,7 +195,6 @@ static int send_waveform_to_channel(struct ast_channel *chan, char *waveform, in
|
|||
|
||||
res = send_waveform_to_fd(waveform, length, fds[1]);
|
||||
if (res >= 0) {
|
||||
pid = res;
|
||||
/* Order is important -- there's almost always going to be mp3... we want to prioritize the
|
||||
user */
|
||||
for (;;) {
|
||||
|
@ -258,10 +256,6 @@ static int send_waveform_to_channel(struct ast_channel *chan, char *waveform, in
|
|||
close(fds[0]);
|
||||
close(fds[1]);
|
||||
|
||||
#if 0
|
||||
if (pid > -1)
|
||||
kill(pid, SIGKILL);
|
||||
#endif
|
||||
if (!res && owriteformat.id)
|
||||
ast_set_write_format(chan, &owriteformat);
|
||||
return res;
|
||||
|
@ -285,7 +279,6 @@ static int festival_exec(struct ast_channel *chan, const char *vdata)
|
|||
char ack[4];
|
||||
char *waveform;
|
||||
int filesize;
|
||||
int wave;
|
||||
char bigstring[MAXFESTLEN];
|
||||
int i;
|
||||
struct MD5Context md5ctx;
|
||||
|
@ -494,7 +487,6 @@ static int festival_exec(struct ast_channel *chan, const char *vdata)
|
|||
|
||||
/* Read back info from server */
|
||||
/* This assumes only one waveform will come back, also LP is unlikely */
|
||||
wave = 0;
|
||||
do {
|
||||
int read_data;
|
||||
for (n = 0; n < 3; ) {
|
||||
|
|
|
@ -804,7 +804,6 @@ static void findmeexec(struct fm_args *tpargs)
|
|||
char *rest, *number;
|
||||
struct findme_user *tmpuser;
|
||||
struct findme_user *fmuser;
|
||||
struct findme_user *headuser;
|
||||
struct findme_user_listptr *findme_user_list;
|
||||
int status;
|
||||
|
||||
|
@ -915,7 +914,6 @@ static void findmeexec(struct fm_args *tpargs)
|
|||
|
||||
fmuser = NULL;
|
||||
tmpuser = NULL;
|
||||
headuser = NULL;
|
||||
if (winner)
|
||||
break;
|
||||
|
||||
|
|
|
@ -112,7 +112,6 @@ static int ices_exec(struct ast_channel *chan, const char *data)
|
|||
int pid = -1;
|
||||
int flags;
|
||||
struct ast_format oreadformat;
|
||||
struct timeval last;
|
||||
struct ast_frame *f;
|
||||
char filename[256]="";
|
||||
char *c;
|
||||
|
@ -123,8 +122,6 @@ static int ices_exec(struct ast_channel *chan, const char *data)
|
|||
return -1;
|
||||
}
|
||||
|
||||
last = ast_tv(0, 0);
|
||||
|
||||
if (pipe(fds)) {
|
||||
ast_log(LOG_WARNING, "Unable to create pipe\n");
|
||||
return -1;
|
||||
|
|
|
@ -626,8 +626,9 @@ enum {
|
|||
CONFFLAG_NO_AUDIO_UNTIL_UP = (1 << 31),
|
||||
};
|
||||
|
||||
/* !If set play an intro announcement at start of conference */
|
||||
#define CONFFLAG_INTROMSG ((uint64_t)1 << 32)
|
||||
/* These flags are defined separately because we ran out of bits that an enum can be used to represent.
|
||||
If you add new flags, be sure to do it in the same way that CONFFLAG_INTROMSG is. */
|
||||
#define CONFFLAG_INTROMSG ((uint64_t)1 << 32) /*!< If set play an intro announcement at start of conference */
|
||||
#define CONFFLAG_INTROUSER_VMREC ((uint64_t)1 << 33)
|
||||
|
||||
enum {
|
||||
|
@ -779,13 +780,13 @@ struct ast_conf_user {
|
|||
char usrvalue[50]; /*!< Custom User Value */
|
||||
char namerecloc[PATH_MAX]; /*!< Name Recorded file Location */
|
||||
time_t jointime; /*!< Time the user joined the conference */
|
||||
time_t kicktime; /*!< Time the user will be kicked from the conference */
|
||||
struct timeval start_time; /*!< Time the user entered into the conference */
|
||||
long timelimit; /*!< Time limit for the user to be in the conference L(x:y:z) */
|
||||
long play_warning; /*!< Play a warning when 'y' ms are left */
|
||||
long warning_freq; /*!< Repeat the warning every 'z' ms */
|
||||
const char *warning_sound; /*!< File to play as warning if 'y' is defined */
|
||||
const char *end_sound; /*!< File to play when time is up. */
|
||||
time_t kicktime; /*!< Time the user will be kicked from the conference */
|
||||
struct timeval start_time; /*!< Time the user entered into the conference */
|
||||
long timelimit; /*!< Time limit for the user to be in the conference L(x:y:z) */
|
||||
long play_warning; /*!< Play a warning when 'y' ms are left */
|
||||
long warning_freq; /*!< Repeat the warning every 'z' ms */
|
||||
const char *warning_sound; /*!< File to play as warning if 'y' is defined */
|
||||
const char *end_sound; /*!< File to play when time is up. */
|
||||
struct volume talk;
|
||||
struct volume listen;
|
||||
AST_LIST_ENTRY(ast_conf_user) list;
|
||||
|
@ -1370,6 +1371,7 @@ static char *complete_meetmecmd(const char *line, const char *word, int pos, int
|
|||
AST_LIST_UNLOCK(&confs);
|
||||
return usr ? ast_strdup(usrno) : NULL;
|
||||
}
|
||||
AST_LIST_UNLOCK(&confs);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2245,7 +2247,6 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struc
|
|||
int talkreq_manager = 0;
|
||||
int using_pseudo = 0;
|
||||
int duration = 20;
|
||||
int hr, min, sec;
|
||||
int sent_event = 0;
|
||||
int checked = 0;
|
||||
int announcement_played = 0;
|
||||
|
@ -2732,7 +2733,7 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struc
|
|||
ao2_ref(item, -1);
|
||||
}
|
||||
|
||||
if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED && !conf->markedusers))
|
||||
if (ast_test_flag64(confflags, CONFFLAG_WAITMARKED) && !conf->markedusers)
|
||||
dahdic.confmode = DAHDI_CONF_CONF;
|
||||
else if (ast_test_flag64(confflags, CONFFLAG_MONITOR))
|
||||
dahdic.confmode = DAHDI_CONF_CONFMON | DAHDI_CONF_LISTENER;
|
||||
|
@ -2755,11 +2756,15 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struc
|
|||
"Meetme: %s\r\n"
|
||||
"Usernum: %d\r\n"
|
||||
"CallerIDnum: %s\r\n"
|
||||
"CallerIDname: %s\r\n",
|
||||
"CallerIDname: %s\r\n"
|
||||
"ConnectedLineNum: %s\r\n"
|
||||
"ConnectedLineName: %s\r\n",
|
||||
chan->name, chan->uniqueid, conf->confno,
|
||||
user->user_no,
|
||||
S_COR(user->chan->caller.id.number.valid, user->chan->caller.id.number.str, "<unknown>"),
|
||||
S_COR(user->chan->caller.id.name.valid, user->chan->caller.id.name.str, "<unknown>")
|
||||
S_COR(user->chan->caller.id.name.valid, user->chan->caller.id.name.str, "<unknown>"),
|
||||
S_COR(user->chan->connected.id.number.valid, user->chan->connected.id.number.str, "<unknown>"),
|
||||
S_COR(user->chan->connected.id.name.valid, user->chan->connected.id.name.str, "<unknown>")
|
||||
);
|
||||
sent_event = 1;
|
||||
}
|
||||
|
@ -2917,6 +2922,11 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, struc
|
|||
res = ast_streamfile(chan, user->end_sound, chan->language);
|
||||
res = ast_waitstream(chan, "");
|
||||
}
|
||||
if (ast_test_flag64(confflags, CONFFLAG_KICK_CONTINUE)) {
|
||||
ret = 0;
|
||||
} else {
|
||||
ret = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -3802,9 +3812,6 @@ bailoutandtrynormal:
|
|||
if (user->user_no) {
|
||||
/* Only cleanup users who really joined! */
|
||||
now = ast_tvnow();
|
||||
hr = (now.tv_sec - user->jointime) / 3600;
|
||||
min = ((now.tv_sec - user->jointime) % 3600) / 60;
|
||||
sec = (now.tv_sec - user->jointime) % 60;
|
||||
|
||||
if (sent_event) {
|
||||
ast_manager_event(chan, EVENT_FLAG_CALL, "MeetmeLeave",
|
||||
|
@ -3814,11 +3821,15 @@ bailoutandtrynormal:
|
|||
"Usernum: %d\r\n"
|
||||
"CallerIDNum: %s\r\n"
|
||||
"CallerIDName: %s\r\n"
|
||||
"ConnectedLineNum: %s\r\n"
|
||||
"ConnectedLineName: %s\r\n"
|
||||
"Duration: %ld\r\n",
|
||||
chan->name, chan->uniqueid, conf->confno,
|
||||
user->user_no,
|
||||
S_COR(user->chan->caller.id.number.valid, user->chan->caller.id.number.str, "<unknown>"),
|
||||
S_COR(user->chan->caller.id.name.valid, user->chan->caller.id.name.str, "<unknown>"),
|
||||
S_COR(user->chan->connected.id.number.valid, user->chan->connected.id.number.str, "<unknown>"),
|
||||
S_COR(user->chan->connected.id.name.valid, user->chan->connected.id.name.str, "<unknown>"),
|
||||
(long)(now.tv_sec - user->jointime));
|
||||
}
|
||||
|
||||
|
@ -3906,7 +3917,7 @@ static struct ast_conference *find_conf_realtime(struct ast_channel *chan, char
|
|||
ast_localtime(&now, &tm, NULL);
|
||||
ast_strftime(currenttime, sizeof(currenttime), DATE_FORMAT, &tm);
|
||||
|
||||
ast_debug(1, "Looking for conference %s that starts after %s\n", confno, eatime);
|
||||
ast_debug(1, "Looking for conference %s that starts after %s\n", confno, currenttime);
|
||||
|
||||
var = ast_load_realtime("meetme", "confno",
|
||||
confno, "starttime <= ", currenttime, "endtime >= ",
|
||||
|
@ -4880,6 +4891,8 @@ static int action_meetmelist(struct mansession *s, const struct message *m)
|
|||
"UserNumber: %d\r\n"
|
||||
"CallerIDNum: %s\r\n"
|
||||
"CallerIDName: %s\r\n"
|
||||
"ConnectedLineNum: %s\r\n"
|
||||
"ConnectedLineName: %s\r\n"
|
||||
"Channel: %s\r\n"
|
||||
"Admin: %s\r\n"
|
||||
"Role: %s\r\n"
|
||||
|
@ -4892,6 +4905,8 @@ static int action_meetmelist(struct mansession *s, const struct message *m)
|
|||
user->user_no,
|
||||
S_COR(user->chan->caller.id.number.valid, user->chan->caller.id.number.str, "<unknown>"),
|
||||
S_COR(user->chan->caller.id.name.valid, user->chan->caller.id.name.str, "<no name>"),
|
||||
S_COR(user->chan->connected.id.number.valid, user->chan->connected.id.number.str, "<unknown>"),
|
||||
S_COR(user->chan->connected.id.name.valid, user->chan->connected.id.name.str, "<no name>"),
|
||||
user->chan->name,
|
||||
ast_test_flag64(&user->userflags, CONFFLAG_ADMIN) ? "Yes" : "No",
|
||||
ast_test_flag64(&user->userflags, CONFFLAG_MONITOR) ? "Listen only" : ast_test_flag64(&user->userflags, CONFFLAG_TALKER) ? "Talk only" : "Talk and listen",
|
||||
|
@ -6453,7 +6468,6 @@ static int sla_trunk_exec(struct ast_channel *chan, const char *data)
|
|||
AST_APP_ARG(options);
|
||||
);
|
||||
char *opts[SLA_TRUNK_OPT_ARG_ARRAY_SIZE] = { NULL, };
|
||||
char *conf_opt_args[OPT_ARG_ARRAY_SIZE] = { NULL, };
|
||||
struct ast_flags opt_flags = { 0 };
|
||||
char *parse;
|
||||
|
||||
|
@ -6516,7 +6530,6 @@ static int sla_trunk_exec(struct ast_channel *chan, const char *data)
|
|||
if (ast_test_flag(&opt_flags, SLA_TRUNK_OPT_MOH)) {
|
||||
ast_indicate(chan, -1);
|
||||
ast_set_flag64(&conf_flags, CONFFLAG_MOH);
|
||||
conf_opt_args[OPT_ARG_MOH_CLASS] = opts[SLA_TRUNK_OPT_ARG_MOH_CLASS];
|
||||
} else
|
||||
ast_indicate(chan, AST_CONTROL_RINGING);
|
||||
|
||||
|
|
|
@ -1229,7 +1229,7 @@ static int sendmail(struct minivm_template *template, struct minivm_account *vmu
|
|||
struct ast_tm tm;
|
||||
struct minivm_zone *the_zone = NULL;
|
||||
struct ast_channel *ast;
|
||||
char *finalfilename;
|
||||
char *finalfilename = "";
|
||||
struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
|
||||
char *fromaddress;
|
||||
char *fromemail;
|
||||
|
@ -1266,13 +1266,22 @@ static int sendmail(struct minivm_template *template, struct minivm_account *vmu
|
|||
char tmpcmd[PATH_MAX];
|
||||
int tmpfd;
|
||||
|
||||
/**
|
||||
* XXX
|
||||
* /bug tmpfd is a leaked fd. The file is also never unlinked.
|
||||
* See app_voicemail.c for how the code works there that
|
||||
* doesn't have this bug.
|
||||
*/
|
||||
|
||||
ast_copy_string(newtmp, "/tmp/XXXXXX", sizeof(newtmp));
|
||||
ast_debug(3, "newtmp: %s\n", newtmp);
|
||||
tmpfd = mkstemp(newtmp);
|
||||
snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, filename, format, newtmp, format);
|
||||
ast_safe_system(tmpcmd);
|
||||
finalfilename = newtmp;
|
||||
ast_debug(3, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", filename, format, vmu->volgain, vmu->username);
|
||||
if (tmpfd > -1) {
|
||||
snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, filename, format, newtmp, format);
|
||||
ast_safe_system(tmpcmd);
|
||||
finalfilename = newtmp;
|
||||
ast_debug(3, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", filename, format, vmu->volgain, vmu->username);
|
||||
}
|
||||
} else {
|
||||
finalfilename = ast_strdupa(filename);
|
||||
}
|
||||
|
@ -1828,7 +1837,6 @@ static int leave_voicemail(struct ast_channel *chan, char *username, struct leav
|
|||
char callerid[256];
|
||||
FILE *txt;
|
||||
int res = 0, txtdes;
|
||||
int msgnum;
|
||||
int duration = 0;
|
||||
char date[256];
|
||||
char tmpdir[PATH_MAX];
|
||||
|
@ -1871,7 +1879,6 @@ static int leave_voicemail(struct ast_channel *chan, char *username, struct leav
|
|||
pbx_builtin_setvar_helper(chan, "MVM_RECORD_STATUS", "FAILED");
|
||||
return res;
|
||||
}
|
||||
msgnum = 0;
|
||||
|
||||
userdir = check_dirpath(tmpdir, sizeof(tmpdir), vmu->domain, username, "tmp");
|
||||
|
||||
|
@ -2452,7 +2459,6 @@ static int minivm_accmess_exec(struct ast_channel *chan, const char *data)
|
|||
char *message = NULL;
|
||||
char *prompt = NULL;
|
||||
int duration;
|
||||
int cmd;
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_ERROR, "MinivmAccmess needs at least two arguments: account and option\n");
|
||||
|
@ -2526,7 +2532,7 @@ static int minivm_accmess_exec(struct ast_channel *chan, const char *data)
|
|||
}
|
||||
snprintf(filename,sizeof(filename), "%s%s/%s/%s", MVM_SPOOL_DIR, vmu->domain, vmu->username, message);
|
||||
/* Maybe we should check the result of play_record_review ? */
|
||||
cmd = play_record_review(chan, prompt, filename, global_maxgreet, default_vmformat, 0, vmu, &duration, NULL, FALSE);
|
||||
play_record_review(chan, prompt, filename, global_maxgreet, default_vmformat, 0, vmu, &duration, NULL, FALSE);
|
||||
|
||||
ast_debug(1, "Recorded new %s message in %s (duration %d)\n", message, filename, duration);
|
||||
|
||||
|
@ -3238,12 +3244,10 @@ static int minivm_account_func_read(struct ast_channel *chan, const char *cmd, c
|
|||
check_dirpath(buf, len, vmu->domain, vmu->username, NULL);
|
||||
} else { /* Look in channel variables */
|
||||
struct ast_variable *var;
|
||||
int found = 0;
|
||||
|
||||
for (var = vmu->chanvars ; var ; var = var->next)
|
||||
if (!strcmp(var->name, colname)) {
|
||||
ast_copy_string(buf, var->value, len);
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -101,7 +101,6 @@ static int originate_exec(struct ast_channel *chan, const char *data)
|
|||
char *parse;
|
||||
char *chantech, *chandata;
|
||||
int res = -1;
|
||||
int outgoing_res = 0;
|
||||
int outgoing_status = 0;
|
||||
static const unsigned int timeout = 30;
|
||||
static const char default_exten[] = "s";
|
||||
|
@ -154,14 +153,14 @@ static int originate_exec(struct ast_channel *chan, const char *data)
|
|||
ast_debug(1, "Originating call to '%s/%s' and connecting them to extension %s,%s,%d\n",
|
||||
chantech, chandata, args.arg1, exten, priority);
|
||||
|
||||
outgoing_res = ast_pbx_outgoing_exten(chantech, cap_slin, chandata,
|
||||
ast_pbx_outgoing_exten(chantech, cap_slin, chandata,
|
||||
timeout * 1000, args.arg1, exten, priority, &outgoing_status, 0, NULL,
|
||||
NULL, NULL, NULL, NULL);
|
||||
} else if (!strcasecmp(args.type, "app")) {
|
||||
ast_debug(1, "Originating call to '%s/%s' and connecting them to %s(%s)\n",
|
||||
chantech, chandata, args.arg1, S_OR(args.arg2, ""));
|
||||
|
||||
outgoing_res = ast_pbx_outgoing_app(chantech, cap_slin, chandata,
|
||||
ast_pbx_outgoing_app(chantech, cap_slin, chandata,
|
||||
timeout * 1000, args.arg1, args.arg2, &outgoing_status, 0, NULL,
|
||||
NULL, NULL, NULL, NULL);
|
||||
} else {
|
||||
|
|
|
@ -53,6 +53,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
|||
<parameter name="minlength">
|
||||
<para>Minimum allowable digits in the input callerid number. Defaults to <literal>10</literal>.</para>
|
||||
</parameter>
|
||||
<parameter name="options">
|
||||
<para>Position reserved for options.</para>
|
||||
</parameter>
|
||||
<parameter name="context">
|
||||
<para>Context to check the given callerid against patterns.</para>
|
||||
</parameter>
|
||||
|
|
|
@ -999,7 +999,7 @@ struct callattempt {
|
|||
struct queue_ent {
|
||||
struct call_queue *parent; /*!< What queue is our parent */
|
||||
char moh[80]; /*!< Name of musiconhold to be used */
|
||||
char announce[80]; /*!< Announcement to play for member when call is answered */
|
||||
char announce[PATH_MAX]; /*!< Announcement to play for member when call is answered */
|
||||
char context[AST_MAX_CONTEXT]; /*!< Context when user exits queue */
|
||||
char digits[AST_MAX_EXTENSION]; /*!< Digits entered while in queue */
|
||||
int valid_digits; /*!< Digits entered correspond to valid extension. Exited */
|
||||
|
@ -2072,9 +2072,9 @@ static void queue_set_param(struct call_queue *q, const char *param, const char
|
|||
* \brief Find rt member record to update otherwise create one.
|
||||
*
|
||||
* Search for member in queue, if found update penalty/paused state,
|
||||
* if no member exists create one flag it as a RT member and add to queue member list.
|
||||
* if no member exists create one flag it as a RT member and add to queue member list.
|
||||
*/
|
||||
static void rt_handle_member_record(struct call_queue *q, char *interface, const char *rt_uniqueid, const char *membername, const char *penalty_str, const char *paused_str, const char* state_interface)
|
||||
static void rt_handle_member_record(struct call_queue *q, char *interface, struct ast_config *member_config)
|
||||
{
|
||||
struct member *m;
|
||||
struct ao2_iterator mem_iter;
|
||||
|
@ -2082,6 +2082,12 @@ static void rt_handle_member_record(struct call_queue *q, char *interface, const
|
|||
int paused = 0;
|
||||
int found = 0;
|
||||
|
||||
const char *rt_uniqueid = ast_variable_retrieve(member_config, interface, "uniqueid");
|
||||
const char *membername = S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface);
|
||||
const char *state_interface = S_OR(ast_variable_retrieve(member_config, interface, "state_interface"), interface);
|
||||
const char *penalty_str = ast_variable_retrieve(member_config, interface, "penalty");
|
||||
const char *paused_str = ast_variable_retrieve(member_config, interface, "paused");
|
||||
|
||||
if (ast_strlen_zero(rt_uniqueid)) {
|
||||
ast_log(LOG_WARNING, "Realtime field uniqueid is empty for member %s\n", S_OR(membername, "NULL"));
|
||||
return;
|
||||
|
@ -2299,12 +2305,7 @@ static struct call_queue *find_queue_by_name_rt(const char *queuename, struct as
|
|||
ao2_iterator_destroy(&mem_iter);
|
||||
|
||||
while ((interface = ast_category_browse(member_config, interface))) {
|
||||
rt_handle_member_record(q, interface,
|
||||
ast_variable_retrieve(member_config, interface, "uniqueid"),
|
||||
S_OR(ast_variable_retrieve(member_config, interface, "membername"),interface),
|
||||
ast_variable_retrieve(member_config, interface, "penalty"),
|
||||
ast_variable_retrieve(member_config, interface, "paused"),
|
||||
S_OR(ast_variable_retrieve(member_config, interface, "state_interface"),interface));
|
||||
rt_handle_member_record(q, interface, member_config);
|
||||
}
|
||||
|
||||
/* Delete all realtime members that have been deleted in DB. */
|
||||
|
@ -2426,12 +2427,7 @@ static void update_realtime_members(struct call_queue *q)
|
|||
ao2_iterator_destroy(&mem_iter);
|
||||
|
||||
while ((interface = ast_category_browse(member_config, interface))) {
|
||||
rt_handle_member_record(q, interface,
|
||||
ast_variable_retrieve(member_config, interface, "uniqueid"),
|
||||
S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface),
|
||||
ast_variable_retrieve(member_config, interface, "penalty"),
|
||||
ast_variable_retrieve(member_config, interface, "paused"),
|
||||
S_OR(ast_variable_retrieve(member_config, interface, "state_interface"), interface));
|
||||
rt_handle_member_record(q, interface, member_config);
|
||||
}
|
||||
|
||||
/* Delete all realtime members that have been deleted in DB. */
|
||||
|
@ -2515,10 +2511,20 @@ static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *
|
|||
q->count++;
|
||||
res = 0;
|
||||
ast_manager_event(qe->chan, EVENT_FLAG_CALL, "Join",
|
||||
"Channel: %s\r\nCallerIDNum: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n",
|
||||
"Channel: %s\r\n"
|
||||
"CallerIDNum: %s\r\n"
|
||||
"CallerIDName: %s\r\n"
|
||||
"ConnectedLineNum: %s\r\n"
|
||||
"ConnectedLineName: %s\r\n"
|
||||
"Queue: %s\r\n"
|
||||
"Position: %d\r\n"
|
||||
"Count: %d\r\n"
|
||||
"Uniqueid: %s\r\n",
|
||||
qe->chan->name,
|
||||
S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, "unknown"),/* XXX somewhere else it is <unknown> */
|
||||
S_COR(qe->chan->caller.id.name.valid, qe->chan->caller.id.name.str, "unknown"),
|
||||
S_COR(qe->chan->connected.id.number.valid, qe->chan->connected.id.number.str, "unknown"),/* XXX somewhere else it is <unknown> */
|
||||
S_COR(qe->chan->connected.id.name.valid, qe->chan->connected.id.name.str, "unknown"),
|
||||
q->name, qe->pos, q->count, qe->chan->uniqueid );
|
||||
ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
|
||||
}
|
||||
|
@ -3152,6 +3158,8 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
|
|||
"DestinationChannel: %s\r\n"
|
||||
"CallerIDNum: %s\r\n"
|
||||
"CallerIDName: %s\r\n"
|
||||
"ConnectedLineNum: %s\r\n"
|
||||
"ConnectedLineName: %s\r\n"
|
||||
"Context: %s\r\n"
|
||||
"Extension: %s\r\n"
|
||||
"Priority: %d\r\n"
|
||||
|
@ -3160,6 +3168,8 @@ static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies
|
|||
qe->parent->name, tmp->interface, tmp->member->membername, qe->chan->name, tmp->chan->name,
|
||||
S_COR(tmp->chan->caller.id.number.valid, tmp->chan->caller.id.number.str, "unknown"),
|
||||
S_COR(tmp->chan->caller.id.name.valid, tmp->chan->caller.id.name.str, "unknown"),
|
||||
S_COR(tmp->chan->connected.id.number.valid, tmp->chan->connected.id.number.str, "unknown"),
|
||||
S_COR(tmp->chan->connected.id.name.valid, tmp->chan->connected.id.name.str, "unknown"),
|
||||
qe->chan->context, qe->chan->exten, qe->chan->priority, qe->chan->uniqueid,
|
||||
qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
|
||||
ast_verb(3, "Called %s\n", tmp->interface);
|
||||
|
@ -4323,7 +4333,6 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
|
|||
char *agiexec = NULL;
|
||||
char *macroexec = NULL;
|
||||
char *gosubexec = NULL;
|
||||
int ret = 0;
|
||||
const char *monitorfilename;
|
||||
const char *monitor_exec;
|
||||
const char *monitor_options;
|
||||
|
@ -4849,7 +4858,7 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
|
|||
/* We purposely lock the CDR so that pbx_exec does not update the application data */
|
||||
if (qe->chan->cdr)
|
||||
ast_set_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED);
|
||||
ret = pbx_exec(qe->chan, mixmonapp, mixmonargs);
|
||||
pbx_exec(qe->chan, mixmonapp, mixmonargs);
|
||||
if (qe->chan->cdr)
|
||||
ast_clear_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED);
|
||||
|
||||
|
@ -4981,7 +4990,7 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
|
|||
application = pbx_findapp("agi");
|
||||
if (application) {
|
||||
agiexec = ast_strdupa(agi);
|
||||
ret = pbx_exec(qe->chan, application, agiexec);
|
||||
pbx_exec(qe->chan, application, agiexec);
|
||||
} else
|
||||
ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n");
|
||||
}
|
||||
|
@ -7248,12 +7257,16 @@ static int manager_queues_status(struct mansession *s, const struct message *m)
|
|||
"Uniqueid: %s\r\n"
|
||||
"CallerIDNum: %s\r\n"
|
||||
"CallerIDName: %s\r\n"
|
||||
"ConnectedLineNum: %s\r\n"
|
||||
"ConnectedLineName: %s\r\n"
|
||||
"Wait: %ld\r\n"
|
||||
"%s"
|
||||
"\r\n",
|
||||
q->name, pos++, qe->chan->name, qe->chan->uniqueid,
|
||||
S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, "unknown"),
|
||||
S_COR(qe->chan->caller.id.name.valid, qe->chan->caller.id.name.str, "unknown"),
|
||||
S_COR(qe->chan->connected.id.number.valid, qe->chan->connected.id.number.str, "unknown"),
|
||||
S_COR(qe->chan->connected.id.name.valid, qe->chan->connected.id.name.str, "unknown"),
|
||||
(long) (now - qe->start), idText);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1975,7 +1975,11 @@ unsigned int seq;
|
|||
return;
|
||||
}
|
||||
n = finddelim(astr,astrs,100);
|
||||
if (n < 1) return;
|
||||
if (n < 1) {
|
||||
ast_free(str);
|
||||
ast_free(astr);
|
||||
return;
|
||||
}
|
||||
ast_mutex_lock(&myrpt->statpost_lock);
|
||||
seq = ++myrpt->statpost_seqno;
|
||||
ast_mutex_unlock(&myrpt->statpost_lock);
|
||||
|
@ -12218,7 +12222,7 @@ struct ast_format_cap *cap = NULL;
|
|||
// ctcss code autopatch initiate
|
||||
if (strstr((char *)f->data.ptr,"/M/")&& !myrpt->macropatch)
|
||||
{
|
||||
char value[16];
|
||||
char value[16] = "";
|
||||
strcat(value,"*6");
|
||||
myrpt->macropatch=1;
|
||||
rpt_mutex_lock(&myrpt->lock);
|
||||
|
|
|
@ -85,7 +85,12 @@ static int userevent_exec(struct ast_channel *chan, const char *data)
|
|||
ast_str_append(&body, 0, "%s\r\n", args.extra[x]);
|
||||
}
|
||||
|
||||
manager_event(EVENT_FLAG_USER, "UserEvent", "UserEvent: %s\r\n%s", args.eventname, ast_str_buffer(body));
|
||||
manager_event(EVENT_FLAG_USER, "UserEvent",
|
||||
"UserEvent: %s\r\n"
|
||||
"Uniqueid: %s\r\n"
|
||||
"%s",
|
||||
args.eventname, chan->uniqueid, ast_str_buffer(body));
|
||||
|
||||
ast_free(body);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -2177,11 +2177,16 @@ static int imap_store_file(const char *dir, const char *mailboxuser, const char
|
|||
int ret; /* for better error checking */
|
||||
char *imap_flags = NIL;
|
||||
int msgcount = (messagecount(vmu->context, vmu->mailbox, "INBOX") + messagecount(vmu->context, vmu->mailbox, "Old"));
|
||||
int box = NEW_FOLDER;
|
||||
|
||||
/* Back out early if this is a greeting and we don't want to store greetings in IMAP */
|
||||
if (msgnum < 0 && !imapgreetings) {
|
||||
return 0;
|
||||
}
|
||||
/* Back out early if this is a greeting and we don't want to store greetings in IMAP */
|
||||
if (msgnum < 0) {
|
||||
if(!imapgreetings) {
|
||||
return 0;
|
||||
} else {
|
||||
box = GREETINGS_FOLDER;
|
||||
}
|
||||
}
|
||||
|
||||
if (imap_check_limits(chan, vms, vmu, msgcount)) {
|
||||
return -1;
|
||||
|
@ -2264,9 +2269,9 @@ static int imap_store_file(const char *dir, const char *mailboxuser, const char
|
|||
}
|
||||
((char *) buf)[len] = '\0';
|
||||
INIT(&str, mail_string, buf, len);
|
||||
ret = init_mailstream(vms, NEW_FOLDER);
|
||||
ret = init_mailstream(vms, box);
|
||||
if (ret == 0) {
|
||||
imap_mailbox_name(mailbox, sizeof(mailbox), vms, NEW_FOLDER, 1);
|
||||
imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
|
||||
ast_mutex_lock(&vms->lock);
|
||||
if(!mail_append_full(vms->mailstream, mailbox, imap_flags, NIL, &str))
|
||||
ast_log(LOG_ERROR, "Error while sending the message to %s\n", mailbox);
|
||||
|
@ -4734,6 +4739,7 @@ static int add_email_attachment(FILE *p, struct ast_vm_user *vmu, char *format,
|
|||
char fname[256];
|
||||
char tmpcmd[256];
|
||||
int tmpfd = -1;
|
||||
int soxstatus = 0;
|
||||
|
||||
/* Eww. We want formats to tell us their own MIME type */
|
||||
char *ctype = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-";
|
||||
|
@ -4745,7 +4751,6 @@ static int add_email_attachment(FILE *p, struct ast_vm_user *vmu, char *format,
|
|||
chmod(newtmp, VOICEMAIL_FILE_MODE & ~my_umask);
|
||||
ast_debug(3, "newtmp: %s\n", newtmp);
|
||||
if (tmpfd > -1) {
|
||||
int soxstatus;
|
||||
snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
|
||||
if ((soxstatus = ast_safe_system(tmpcmd)) == 0) {
|
||||
attach = newtmp;
|
||||
|
@ -4773,7 +4778,9 @@ static int add_email_attachment(FILE *p, struct ast_vm_user *vmu, char *format,
|
|||
if (last)
|
||||
fprintf(p, ENDL ENDL "--%s--" ENDL "." ENDL, bound);
|
||||
if (tmpfd > -1) {
|
||||
unlink(fname);
|
||||
if (soxstatus == 0) {
|
||||
unlink(fname);
|
||||
}
|
||||
close(tmpfd);
|
||||
unlink(newtmp);
|
||||
}
|
||||
|
@ -6696,7 +6703,21 @@ static int get_folder(struct ast_channel *chan, int start)
|
|||
if (d)
|
||||
return d;
|
||||
snprintf(fn, sizeof(fn), "vm-%s", mbox(NULL, x)); /* Folder name */
|
||||
d = vm_play_folder_name(chan, fn);
|
||||
|
||||
/* The inbox folder can have its name changed under certain conditions
|
||||
* so this checks if the sound file exists for the inbox folder name and
|
||||
* if it doesn't, plays the default name instead. */
|
||||
if (x == 0) {
|
||||
if (ast_fileexists(fn, NULL, NULL)) {
|
||||
d = vm_play_folder_name(chan, fn);
|
||||
} else {
|
||||
ast_verb(1, "failed to find %s\n", fn);
|
||||
d = vm_play_folder_name(chan, "vm-INBOX");
|
||||
}
|
||||
} else {
|
||||
d = vm_play_folder_name(chan, fn);
|
||||
}
|
||||
|
||||
if (d)
|
||||
return d;
|
||||
d = ast_waitfordigit(chan, 500);
|
||||
|
@ -7061,7 +7082,6 @@ static int forward_message(struct ast_channel *chan, char *context, struct vm_st
|
|||
char *dir;
|
||||
int curmsg;
|
||||
char urgent_str[7] = "";
|
||||
char tmptxtfile[PATH_MAX];
|
||||
int prompt_played = 0;
|
||||
#ifndef IMAP_STORAGE
|
||||
char msgfile[PATH_MAX], textfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
|
||||
|
@ -7074,7 +7094,6 @@ static int forward_message(struct ast_channel *chan, char *context, struct vm_st
|
|||
dir = vms->curdir;
|
||||
curmsg = vms->curmsg;
|
||||
|
||||
tmptxtfile[0] = '\0';
|
||||
while (!res && !valid_extensions) {
|
||||
int use_directory = 0;
|
||||
if (ast_test_flag((&globalflags), VM_DIRECFORWARD)) {
|
||||
|
@ -12129,6 +12148,9 @@ static int load_config(int reload)
|
|||
|
||||
if (ucfg) {
|
||||
for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
|
||||
if (!strcasecmp(cat, "general")) {
|
||||
continue;
|
||||
}
|
||||
if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
|
||||
continue;
|
||||
if ((current = find_or_create(userscontext, cat))) {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,320 @@
|
|||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2011, Digium, Inc.
|
||||
*
|
||||
* David Vossel <dvossel@digium.com>
|
||||
* Joshua Colp <jcolp@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.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _CONFBRIDGE_H
|
||||
#define _CONFBRIDGE_H
|
||||
|
||||
#include "asterisk.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/linkedlists.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/bridging.h"
|
||||
#include "asterisk/bridging_features.h"
|
||||
|
||||
/* Maximum length of a conference bridge name */
|
||||
#define MAX_CONF_NAME 32
|
||||
/* Maximum length of a conference pin */
|
||||
#define MAX_PIN 80
|
||||
|
||||
#define DEFAULT_USER_PROFILE "default_user"
|
||||
#define DEFAULT_BRIDGE_PROFILE "default_bridge"
|
||||
|
||||
#define DEFAULT_TALKING_THRESHOLD 160
|
||||
#define DEFAULT_SILENCE_THRESHOLD 2500
|
||||
|
||||
enum user_profile_flags {
|
||||
USER_OPT_ADMIN = (1 << 0), /*!< Set if the caller is an administrator */
|
||||
USER_OPT_NOONLYPERSON = (1 << 1), /*!< Set if the "you are currently the only person in this conference" sound file should not be played */
|
||||
USER_OPT_MARKEDUSER = (1 << 2), /*!< Set if the caller is a marked user */
|
||||
USER_OPT_STARTMUTED = (1 << 3), /*!< Set if the caller should be initially set muted */
|
||||
USER_OPT_MUSICONHOLD = (1 << 4), /*!< Set if music on hold should be played if nobody else is in the conference bridge */
|
||||
USER_OPT_QUIET = (1 << 5), /*!< Set if no audio prompts should be played */
|
||||
USER_OPT_ANNOUNCEUSERCOUNT = (1 << 6), /*!< Set if the number of users should be announced to the caller */
|
||||
USER_OPT_WAITMARKED = (1 << 7), /*!< Set if the user must wait for a marked user before starting */
|
||||
USER_OPT_ENDMARKED = (1 << 8), /*!< Set if the user should be kicked after the last Marked user exits */
|
||||
USER_OPT_DENOISE = (1 << 9), /*!< Sets if denoise filter should be used on audio before mixing. */
|
||||
USER_OPT_ANNOUNCE_JOIN_LEAVE = (1 << 10), /*!< Sets if the user's name should be recorded and announced on join and leave. */
|
||||
USER_OPT_TALKER_DETECT = (1 << 11), /*!< Sets if start and stop talking events should generated for this user over AMI. */
|
||||
USER_OPT_DROP_SILENCE = (1 << 12), /*!< Sets if silence should be dropped from the mix or not. */
|
||||
USER_OPT_DTMF_PASS = (1 << 13), /*!< Sets if dtmf should be passed into the conference or not */
|
||||
USER_OPT_ANNOUNCEUSERCOUNTALL = (1 << 14), /*!< Sets if the number of users should be announced to everyone. */
|
||||
USER_OPT_JITTERBUFFER = (1 << 15), /*!< Places a jitterbuffer on the user. */
|
||||
};
|
||||
|
||||
enum bridge_profile_flags {
|
||||
BRIDGE_OPT_RECORD_CONFERENCE = (1 << 0), /*!< Set if the conference should be recorded */
|
||||
};
|
||||
|
||||
enum conf_menu_action_id {
|
||||
MENU_ACTION_TOGGLE_MUTE = 1,
|
||||
MENU_ACTION_PLAYBACK,
|
||||
MENU_ACTION_PLAYBACK_AND_CONTINUE,
|
||||
MENU_ACTION_INCREASE_LISTENING,
|
||||
MENU_ACTION_DECREASE_LISTENING,
|
||||
MENU_ACTION_RESET_LISTENING,
|
||||
MENU_ACTION_RESET_TALKING,
|
||||
MENU_ACTION_INCREASE_TALKING,
|
||||
MENU_ACTION_DECREASE_TALKING,
|
||||
MENU_ACTION_DIALPLAN_EXEC,
|
||||
MENU_ACTION_ADMIN_TOGGLE_LOCK,
|
||||
MENU_ACTION_ADMIN_KICK_LAST,
|
||||
MENU_ACTION_LEAVE,
|
||||
MENU_ACTION_NOOP,
|
||||
};
|
||||
|
||||
/*! The conference menu action contains both
|
||||
* the action id that represents the action that
|
||||
* must take place, along with any data associated
|
||||
* with that action. */
|
||||
struct conf_menu_action {
|
||||
enum conf_menu_action_id id;
|
||||
union {
|
||||
char playback_file[PATH_MAX];
|
||||
struct {
|
||||
char context[AST_MAX_CONTEXT];
|
||||
char exten[AST_MAX_EXTENSION];
|
||||
int priority;
|
||||
} dialplan_args;
|
||||
} data;
|
||||
AST_LIST_ENTRY(conf_menu_action) action;
|
||||
};
|
||||
|
||||
/*! Conference menu entries contain the DTMF sequence
|
||||
* and the list of actions that are associated with that
|
||||
* sequence. */
|
||||
struct conf_menu_entry {
|
||||
/*! the DTMF sequence that triggers the actions */
|
||||
char dtmf[MAXIMUM_DTMF_FEATURE_STRING];
|
||||
/*! The actions associated with this menu entry. */
|
||||
AST_LIST_HEAD_NOLOCK(, conf_menu_action) actions;
|
||||
AST_LIST_ENTRY(conf_menu_entry) entry;
|
||||
};
|
||||
|
||||
/*! Conference menu structure. Contains a list
|
||||
* of DTMF sequences coupled with the actions those
|
||||
* sequences invoke.*/
|
||||
struct conf_menu {
|
||||
char name[128];
|
||||
int delme;
|
||||
AST_LIST_HEAD_NOLOCK(, conf_menu_entry) entries;
|
||||
};
|
||||
|
||||
struct user_profile {
|
||||
char name[128];
|
||||
char pin[MAX_PIN];
|
||||
char moh_class[128];
|
||||
unsigned int flags;
|
||||
unsigned int announce_user_count_all_after;
|
||||
/*! The time in ms of talking before a user is considered to be talking by the dsp. */
|
||||
unsigned int talking_threshold;
|
||||
/*! The time in ms of silence before a user is considered to be silent by the dsp. */
|
||||
unsigned int silence_threshold;
|
||||
int delme;
|
||||
};
|
||||
|
||||
enum conf_sounds {
|
||||
CONF_SOUND_HAS_JOINED,
|
||||
CONF_SOUND_HAS_LEFT,
|
||||
CONF_SOUND_KICKED,
|
||||
CONF_SOUND_MUTED,
|
||||
CONF_SOUND_UNMUTED,
|
||||
CONF_SOUND_ONLY_ONE,
|
||||
CONF_SOUND_THERE_ARE,
|
||||
CONF_SOUND_OTHER_IN_PARTY,
|
||||
CONF_SOUND_PLACE_IN_CONF,
|
||||
CONF_SOUND_WAIT_FOR_LEADER,
|
||||
CONF_SOUND_LEADER_HAS_LEFT,
|
||||
CONF_SOUND_GET_PIN,
|
||||
CONF_SOUND_INVALID_PIN,
|
||||
CONF_SOUND_ONLY_PERSON,
|
||||
CONF_SOUND_LOCKED,
|
||||
CONF_SOUND_LOCKED_NOW,
|
||||
CONF_SOUND_UNLOCKED_NOW,
|
||||
CONF_SOUND_ERROR_MENU,
|
||||
CONF_SOUND_JOIN,
|
||||
CONF_SOUND_LEAVE,
|
||||
};
|
||||
|
||||
struct bridge_profile_sounds {
|
||||
AST_DECLARE_STRING_FIELDS(
|
||||
AST_STRING_FIELD(hasjoin);
|
||||
AST_STRING_FIELD(hasleft);
|
||||
AST_STRING_FIELD(kicked);
|
||||
AST_STRING_FIELD(muted);
|
||||
AST_STRING_FIELD(unmuted);
|
||||
AST_STRING_FIELD(onlyone);
|
||||
AST_STRING_FIELD(thereare);
|
||||
AST_STRING_FIELD(otherinparty);
|
||||
AST_STRING_FIELD(placeintoconf);
|
||||
AST_STRING_FIELD(waitforleader);
|
||||
AST_STRING_FIELD(leaderhasleft);
|
||||
AST_STRING_FIELD(getpin);
|
||||
AST_STRING_FIELD(invalidpin);
|
||||
AST_STRING_FIELD(onlyperson);
|
||||
AST_STRING_FIELD(locked);
|
||||
AST_STRING_FIELD(lockednow);
|
||||
AST_STRING_FIELD(unlockednow);
|
||||
AST_STRING_FIELD(errormenu);
|
||||
AST_STRING_FIELD(leave);
|
||||
AST_STRING_FIELD(join);
|
||||
);
|
||||
};
|
||||
|
||||
struct bridge_profile {
|
||||
char name[64];
|
||||
char rec_file[PATH_MAX];
|
||||
unsigned int flags;
|
||||
unsigned int max_members; /*!< The maximum number of participants allowed in the conference */
|
||||
unsigned int internal_sample_rate; /*!< The internal sample rate of the bridge. 0 when set to auto adjust mode. */
|
||||
unsigned int mix_interval; /*!< The internal mixing interval used by the bridge. When set to 0 the bridgewill use a default interval. */
|
||||
struct bridge_profile_sounds *sounds;
|
||||
int delme;
|
||||
};
|
||||
|
||||
/*! \brief The structure that represents a conference bridge */
|
||||
struct conference_bridge {
|
||||
char name[MAX_CONF_NAME]; /*!< Name of the conference bridge */
|
||||
struct ast_bridge *bridge; /*!< Bridge structure doing the mixing */
|
||||
struct bridge_profile b_profile; /*!< The Bridge Configuration Profile */
|
||||
unsigned int users; /*!< Number of users present */
|
||||
unsigned int markedusers; /*!< Number of marked users present */
|
||||
unsigned int locked:1; /*!< Is this conference bridge locked? */
|
||||
struct ast_channel *playback_chan; /*!< Channel used for playback into the conference bridge */
|
||||
struct ast_channel *record_chan; /*!< Channel used for recording the conference */
|
||||
pthread_t record_thread; /*!< The thread the recording chan lives in */
|
||||
ast_mutex_t playback_lock; /*!< Lock used for playback channel */
|
||||
AST_LIST_HEAD_NOLOCK(, conference_bridge_user) users_list; /*!< List of users participating in the conference bridge */
|
||||
};
|
||||
|
||||
/*! \brief The structure that represents a conference bridge user */
|
||||
struct conference_bridge_user {
|
||||
struct conference_bridge *conference_bridge; /*!< Conference bridge they are participating in */
|
||||
struct bridge_profile b_profile; /*!< The Bridge Configuration Profile */
|
||||
struct user_profile u_profile; /*!< The User Configuration Profile */
|
||||
char menu_name[64]; /*!< The name of the DTMF menu assigned to this user */
|
||||
char name_rec_location[PATH_MAX]; /*!< Location of the User's name recorded file if it exists */
|
||||
struct ast_channel *chan; /*!< Asterisk channel participating */
|
||||
struct ast_bridge_features features; /*!< Bridge features structure */
|
||||
struct ast_bridge_tech_optimizations tech_args; /*!< Bridge technology optimizations for talk detection */
|
||||
unsigned int kicked:1; /*!< User has been kicked from the conference */
|
||||
AST_LIST_ENTRY(conference_bridge_user) list; /*!< Linked list information */
|
||||
};
|
||||
|
||||
/*! \brief load confbridge.conf file */
|
||||
int conf_load_config(int reload);
|
||||
|
||||
/*! \brief destroy the information loaded from the confbridge.conf file*/
|
||||
void conf_destroy_config(void);
|
||||
|
||||
/*!
|
||||
* \brief find a user profile given a user profile's name and store
|
||||
* that profile in result structure.
|
||||
*
|
||||
* \details This function first attempts to find any custom user
|
||||
* profile that might exist on a channel datastore, if that doesn't
|
||||
* exist it looks up the provided user profile name, if that doesn't
|
||||
* exist either the default_user profile is used.
|
||||
|
||||
* \retval user profile on success
|
||||
* \retval NULL on failure
|
||||
*/
|
||||
const struct user_profile *conf_find_user_profile(struct ast_channel *chan, const char *user_profile_name, struct user_profile *result);
|
||||
|
||||
/*!
|
||||
* \brief Find a bridge profile
|
||||
*
|
||||
* \details Any bridge profile found using this function must be
|
||||
* destroyed using conf_bridge_profile_destroy. This function first
|
||||
* attempts to find any custom bridge profile that might exist on
|
||||
* a channel datastore, if that doesn't exist it looks up the
|
||||
* provided bridge profile name, if that doesn't exist either
|
||||
* the default_bridge profile is used.
|
||||
*
|
||||
* \retval Bridge profile on success
|
||||
* \retval NULL on failure
|
||||
*/
|
||||
const struct bridge_profile *conf_find_bridge_profile(struct ast_channel *chan, const char *bridge_profile_name, struct bridge_profile *result);
|
||||
|
||||
/*!
|
||||
* \brief Destroy a bridge profile found by 'conf_find_bridge_profile'
|
||||
*/
|
||||
void conf_bridge_profile_destroy(struct bridge_profile *b_profile);
|
||||
|
||||
/*!
|
||||
* \brief copies a bridge profile
|
||||
* \note conf_bridge_profile_destroy must be called on the dst structure
|
||||
*/
|
||||
void conf_bridge_profile_copy(struct bridge_profile *dst, struct bridge_profile *src);
|
||||
|
||||
/*!
|
||||
* \brief Set a DTMF menu to a conference user by menu name.
|
||||
*
|
||||
* \retval 0 on success, menu was found and set
|
||||
* \retval -1 on error, menu was not found
|
||||
*/
|
||||
int conf_set_menu_to_user(const char *menu_name, struct conference_bridge_user *conference_bridge_user);
|
||||
|
||||
/*!
|
||||
* \brief Finds a menu_entry in a menu structure matched by DTMF sequence.
|
||||
*
|
||||
* \note the menu entry found must be destroyed using conf_menu_entry_destroy()
|
||||
*
|
||||
* \retval 1 success, entry is found and stored in result
|
||||
* \retval 0 failure, no entry found for given DTMF sequence
|
||||
*/
|
||||
int conf_find_menu_entry_by_sequence(const char *dtmf_sequence, struct conf_menu *menu, struct conf_menu_entry *result);
|
||||
|
||||
/*!
|
||||
* \brief Destroys and frees all the actions stored in a menu_entry structure
|
||||
*/
|
||||
void conf_menu_entry_destroy(struct conf_menu_entry *menu_entry);
|
||||
|
||||
/*!
|
||||
* \brief Once a DTMF sequence matches a sequence in the user's DTMF menu, this function will get
|
||||
* called to perform the menu action.
|
||||
*
|
||||
* \param bridge_channel, Bridged channel this is involving
|
||||
* \param conference_bridge_user, the conference user to perform the action on.
|
||||
* \param menu_entry, the menu entry that invoked this callback to occur.
|
||||
* \param menu, an AO2 referenced pointer to the entire menu structure the menu_entry
|
||||
* derived from.
|
||||
*
|
||||
* \note The menu_entry is a deep copy of the entry found in the menu structure. This allows
|
||||
* for the menu_entry to be accessed without requiring the menu lock. If the menu must
|
||||
* be accessed, the menu lock must be held. Reference counting of the menu structure is
|
||||
* handled outside of the scope of this function.
|
||||
*
|
||||
* \retval 0 success
|
||||
* \retval -1 failure
|
||||
*/
|
||||
int conf_handle_dtmf(
|
||||
struct ast_bridge_channel *bridge_channel,
|
||||
struct conference_bridge_user *conference_bridge_user,
|
||||
struct conf_menu_entry *menu_entry,
|
||||
struct conf_menu *menu);
|
||||
|
||||
|
||||
/*! \brief Looks to see if sound file is stored in bridge profile sounds, if not
|
||||
* default sound is provided.*/
|
||||
const char *conf_get_sound(enum conf_sounds sound, struct bridge_profile_sounds *custom_sounds);
|
||||
|
||||
int func_confbridge_helper(struct ast_channel *chan, const char *cmd, char *data, const char *value);
|
||||
#endif
|
|
@ -205,9 +205,9 @@ AC_DEFUN([AST_CHECK_PWLIB_VERSION], [
|
|||
$2_VER=$((${$2_MAJOR_VERSION}*10000+${$2_MINOR_VERSION}*100+${$2_BUILD_NUMBER}))
|
||||
$2_REQ=$(($4*10000+$5*100+$6))
|
||||
if test "x$10" = "x"; then
|
||||
let $2_MAX=9999999
|
||||
$2_MAX=9999999
|
||||
else
|
||||
let $2_MAX=$8*10000+$9*100+$10
|
||||
$2_MAX=$(($8*10000+$9*100+$10))
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING(if $1 version ${$2_VERSION} is compatible with chan_h323)
|
||||
|
|
|
@ -198,12 +198,12 @@ static int feature_attended_transfer(struct ast_bridge *bridge, struct ast_bridg
|
|||
ast_bridge_features_enable(&caller_features, AST_BRIDGE_BUILTIN_HANGUP,
|
||||
(attended_transfer && !ast_strlen_zero(attended_transfer->complete) ? attended_transfer->complete : "*1"), NULL);
|
||||
ast_bridge_features_hook(&caller_features, (attended_transfer && !ast_strlen_zero(attended_transfer->threeway) ? attended_transfer->threeway : "*2"),
|
||||
attended_threeway_transfer, NULL);
|
||||
attended_threeway_transfer, NULL, NULL);
|
||||
ast_bridge_features_hook(&caller_features, (attended_transfer && !ast_strlen_zero(attended_transfer->abort) ? attended_transfer->abort : "*3"),
|
||||
attended_abort_transfer, NULL);
|
||||
attended_abort_transfer, NULL, NULL);
|
||||
|
||||
/* But for the caller we want to join the bridge in a blocking fashion so we don't spin around in this function doing nothing while waiting */
|
||||
attended_bridge_result = ast_bridge_join(attended_bridge, bridge_channel->chan, NULL, &caller_features);
|
||||
attended_bridge_result = ast_bridge_join(attended_bridge, bridge_channel->chan, NULL, &caller_features, NULL);
|
||||
|
||||
/* Since the above returned the caller features structure is of no more use */
|
||||
ast_bridge_features_cleanup(&caller_features);
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2007, Digium, Inc.
|
||||
* Copyright (C) 2011, Digium, Inc.
|
||||
*
|
||||
* Joshua Colp <jcolp@digium.com>
|
||||
* David Vossel <dvossel@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
|
@ -21,12 +22,9 @@
|
|||
* \brief Multi-party software based channel mixing
|
||||
*
|
||||
* \author Joshua Colp <jcolp@digium.com>
|
||||
* \author David Vossel <dvossel@digium.com>
|
||||
*
|
||||
* \ingroup bridges
|
||||
*
|
||||
* \todo This bridge operates in 8 kHz mode unless a define is uncommented.
|
||||
* This needs to be improved so the bridge moves between the dominant codec as needed depending
|
||||
* on channels present in the bridge and transcoding capabilities.
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
@ -51,20 +49,26 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
|||
#include "asterisk/slinfactory.h"
|
||||
#include "asterisk/astobj2.h"
|
||||
#include "asterisk/timing.h"
|
||||
#include "asterisk/translate.h"
|
||||
|
||||
#define MAX_DATALEN 3840
|
||||
#define MAX_DATALEN 8096
|
||||
|
||||
/*! \brief Interval at which mixing will take place. Valid options are 10, 20, and 40. */
|
||||
#define SOFTMIX_INTERVAL 20
|
||||
#define DEFAULT_SOFTMIX_INTERVAL 20
|
||||
|
||||
/*! \brief Size of the buffer used for sample manipulation */
|
||||
#define SOFTMIX_DATALEN(rate) ((rate/50) * (SOFTMIX_INTERVAL / 10))
|
||||
#define SOFTMIX_DATALEN(rate, interval) ((rate/50) * (interval / 10))
|
||||
|
||||
/*! \brief Number of samples we are dealing with */
|
||||
#define SOFTMIX_SAMPLES(rate) (SOFTMIX_DATALEN(rate) / 2)
|
||||
#define SOFTMIX_SAMPLES(rate, interval) (SOFTMIX_DATALEN(rate, interval) / 2)
|
||||
|
||||
/*! \brief Define used to turn on 16 kHz audio support */
|
||||
/* #define SOFTMIX_16_SUPPORT */
|
||||
/*! \brief Number of mixing iterations to perform between gathering statistics. */
|
||||
#define SOFTMIX_STAT_INTERVAL 100
|
||||
|
||||
/* This is the threshold in ms at which a channel's own audio will stop getting
|
||||
* mixed out its own write audio stream because it is not talking. */
|
||||
#define DEFAULT_SOFTMIX_SILENCE_THRESHOLD 2500
|
||||
#define DEFAULT_SOFTMIX_TALKING_THRESHOLD 160
|
||||
|
||||
/*! \brief Structure which contains per-channel mixing information */
|
||||
struct softmix_channel {
|
||||
|
@ -73,7 +77,14 @@ struct softmix_channel {
|
|||
/*! Factory which contains audio read in from the channel */
|
||||
struct ast_slinfactory factory;
|
||||
/*! Frame that contains mixed audio to be written out to the channel */
|
||||
struct ast_frame frame;
|
||||
struct ast_frame write_frame;
|
||||
/*! Frame that contains mixed audio read from the channel */
|
||||
struct ast_frame read_frame;
|
||||
/*! DSP for detecting silence */
|
||||
struct ast_dsp *dsp;
|
||||
/*! Bit used to indicate if a channel is talking or not. This affects how
|
||||
* the channel's audio is mixed back to it. */
|
||||
int talking:1;
|
||||
/*! Bit used to indicate that the channel provided audio for this mixing interval */
|
||||
int have_audio:1;
|
||||
/*! Bit used to indicate that a frame is available to be written out to the channel */
|
||||
|
@ -87,66 +98,268 @@ struct softmix_channel {
|
|||
struct softmix_bridge_data {
|
||||
struct ast_timer *timer;
|
||||
unsigned int internal_rate;
|
||||
unsigned int internal_mixing_interval;
|
||||
};
|
||||
|
||||
struct softmix_stats {
|
||||
/*! Each index represents a sample rate used above the internal rate. */
|
||||
unsigned int sample_rates[16];
|
||||
/*! Each index represents the number of channels using the same index in the sample_rates array. */
|
||||
unsigned int num_channels[16];
|
||||
/*! the number of channels above the internal sample rate */
|
||||
unsigned int num_above_internal_rate;
|
||||
/*! the number of channels at the internal sample rate */
|
||||
unsigned int num_at_internal_rate;
|
||||
/*! the absolute highest sample rate supported by any channel in the bridge */
|
||||
unsigned int highest_supported_rate;
|
||||
/*! Is the sample rate locked by the bridge, if so what is that rate.*/
|
||||
unsigned int locked_rate;
|
||||
};
|
||||
|
||||
struct softmix_mixing_array {
|
||||
int max_num_entries;
|
||||
int used_entries;
|
||||
int16_t **buffers;
|
||||
};
|
||||
|
||||
struct softmix_translate_helper_entry {
|
||||
int num_times_requested; /*!< Once this entry is no longer requested, free the trans_pvt
|
||||
and re-init if it was usable. */
|
||||
struct ast_format dst_format; /*!< The destination format for this helper */
|
||||
struct ast_trans_pvt *trans_pvt; /*!< the translator for this slot. */
|
||||
struct ast_frame *out_frame; /*!< The output frame from the last translation */
|
||||
AST_LIST_ENTRY(softmix_translate_helper_entry) entry;
|
||||
};
|
||||
|
||||
struct softmix_translate_helper {
|
||||
struct ast_format slin_src; /*!< the source format expected for all the translators */
|
||||
AST_LIST_HEAD_NOLOCK(, softmix_translate_helper_entry) entries;
|
||||
};
|
||||
|
||||
static struct softmix_translate_helper_entry *softmix_translate_helper_entry_alloc(struct ast_format *dst)
|
||||
{
|
||||
struct softmix_translate_helper_entry *entry;
|
||||
if (!(entry = ast_calloc(1, sizeof(*entry)))) {
|
||||
return NULL;
|
||||
}
|
||||
ast_format_copy(&entry->dst_format, dst);
|
||||
return entry;
|
||||
}
|
||||
|
||||
static void *softmix_translate_helper_free_entry(struct softmix_translate_helper_entry *entry)
|
||||
{
|
||||
if (entry->trans_pvt) {
|
||||
ast_translator_free_path(entry->trans_pvt);
|
||||
}
|
||||
if (entry->out_frame) {
|
||||
ast_frfree(entry->out_frame);
|
||||
}
|
||||
ast_free(entry);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void softmix_translate_helper_init(struct softmix_translate_helper *trans_helper, unsigned int sample_rate)
|
||||
{
|
||||
memset(trans_helper, 0, sizeof(*trans_helper));
|
||||
ast_format_set(&trans_helper->slin_src, ast_format_slin_by_rate(sample_rate), 0);
|
||||
}
|
||||
|
||||
static void softmix_translate_helper_destroy(struct softmix_translate_helper *trans_helper)
|
||||
{
|
||||
struct softmix_translate_helper_entry *entry;
|
||||
|
||||
while ((entry = AST_LIST_REMOVE_HEAD(&trans_helper->entries, entry))) {
|
||||
softmix_translate_helper_free_entry(entry);
|
||||
}
|
||||
}
|
||||
|
||||
static void softmix_translate_helper_change_rate(struct softmix_translate_helper *trans_helper, unsigned int sample_rate)
|
||||
{
|
||||
struct softmix_translate_helper_entry *entry;
|
||||
|
||||
ast_format_set(&trans_helper->slin_src, ast_format_slin_by_rate(sample_rate), 0);
|
||||
AST_LIST_TRAVERSE_SAFE_BEGIN(&trans_helper->entries, entry, entry) {
|
||||
if (entry->trans_pvt) {
|
||||
ast_translator_free_path(entry->trans_pvt);
|
||||
if (!(entry->trans_pvt = ast_translator_build_path(&entry->dst_format, &trans_helper->slin_src))) {
|
||||
AST_LIST_REMOVE_CURRENT(entry);
|
||||
entry = softmix_translate_helper_free_entry(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
AST_LIST_TRAVERSE_SAFE_END;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Get the next available audio on the softmix channel's read stream
|
||||
* and determine if it should be mixed out or not on the write stream.
|
||||
*
|
||||
* \retval pointer to buffer containing the exact number of samples requested on success.
|
||||
* \retval NULL if no samples are present
|
||||
*/
|
||||
static int16_t *softmix_process_read_audio(struct softmix_channel *sc, unsigned int num_samples)
|
||||
{
|
||||
if ((ast_slinfactory_available(&sc->factory) >= num_samples) &&
|
||||
ast_slinfactory_read(&sc->factory, sc->our_buf, num_samples)) {
|
||||
sc->have_audio = 1;
|
||||
return sc->our_buf;
|
||||
}
|
||||
sc->have_audio = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Process a softmix channel's write audio
|
||||
*
|
||||
* \details This function will remove the channel's talking from its own audio if present and
|
||||
* possibly even do the channel's write translation for it depending on how many other
|
||||
* channels use the same write format.
|
||||
*/
|
||||
static void softmix_process_write_audio(struct softmix_translate_helper *trans_helper,
|
||||
struct ast_format *raw_write_fmt,
|
||||
struct softmix_channel *sc)
|
||||
{
|
||||
struct softmix_translate_helper_entry *entry = NULL;
|
||||
int i;
|
||||
|
||||
/* If we provided audio that was not determined to be silence,
|
||||
* then take it out while in slinear format. */
|
||||
if (sc->have_audio && sc->talking) {
|
||||
for (i = 0; i < sc->write_frame.samples; i++) {
|
||||
ast_slinear_saturated_subtract(&sc->final_buf[i], &sc->our_buf[i]);
|
||||
}
|
||||
/* do not do any special write translate optimization if we had to make
|
||||
* a special mix for them to remove their own audio. */
|
||||
return;
|
||||
}
|
||||
|
||||
AST_LIST_TRAVERSE(&trans_helper->entries, entry, entry) {
|
||||
if (ast_format_cmp(&entry->dst_format, raw_write_fmt) == AST_FORMAT_CMP_EQUAL) {
|
||||
entry->num_times_requested++;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
if (!entry->trans_pvt && (entry->num_times_requested > 1)) {
|
||||
entry->trans_pvt = ast_translator_build_path(&entry->dst_format, &trans_helper->slin_src);
|
||||
}
|
||||
if (entry->trans_pvt && !entry->out_frame) {
|
||||
entry->out_frame = ast_translate(entry->trans_pvt, &sc->write_frame, 0);
|
||||
}
|
||||
if (entry->out_frame && (entry->out_frame->datalen < MAX_DATALEN)) {
|
||||
ast_format_copy(&sc->write_frame.subclass.format, &entry->out_frame->subclass.format);
|
||||
memcpy(sc->final_buf, entry->out_frame->data.ptr, entry->out_frame->datalen);
|
||||
sc->write_frame.datalen = entry->out_frame->datalen;
|
||||
sc->write_frame.samples = entry->out_frame->samples;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* add new entry into list if this format destination was not matched. */
|
||||
if (!entry && (entry = softmix_translate_helper_entry_alloc(raw_write_fmt))) {
|
||||
AST_LIST_INSERT_HEAD(&trans_helper->entries, entry, entry);
|
||||
}
|
||||
}
|
||||
|
||||
static void softmix_translate_helper_cleanup(struct softmix_translate_helper *trans_helper)
|
||||
{
|
||||
struct softmix_translate_helper_entry *entry = NULL;
|
||||
AST_LIST_TRAVERSE(&trans_helper->entries, entry, entry) {
|
||||
if (entry->out_frame) {
|
||||
ast_frfree(entry->out_frame);
|
||||
entry->out_frame = NULL;
|
||||
}
|
||||
entry->num_times_requested = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void softmix_bridge_data_destroy(void *obj)
|
||||
{
|
||||
struct softmix_bridge_data *softmix_data = obj;
|
||||
ast_timer_close(softmix_data->timer);
|
||||
}
|
||||
|
||||
/*! \brief Function called when a bridge is created */
|
||||
static int softmix_bridge_create(struct ast_bridge *bridge)
|
||||
{
|
||||
struct softmix_bridge_data *bridge_data;
|
||||
struct softmix_bridge_data *softmix_data;
|
||||
|
||||
if (!(bridge_data = ast_calloc(1, sizeof(*bridge_data)))) {
|
||||
if (!(softmix_data = ao2_alloc(sizeof(*softmix_data), softmix_bridge_data_destroy))) {
|
||||
return -1;
|
||||
}
|
||||
if (!(bridge_data->timer = ast_timer_open())) {
|
||||
ast_free(bridge_data);
|
||||
if (!(softmix_data->timer = ast_timer_open())) {
|
||||
ao2_ref(softmix_data, -1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* start at 8khz, let it grow from there */
|
||||
bridge_data->internal_rate = 8000;
|
||||
softmix_data->internal_rate = 8000;
|
||||
softmix_data->internal_mixing_interval = DEFAULT_SOFTMIX_INTERVAL;
|
||||
|
||||
bridge->bridge_pvt = bridge_data;
|
||||
bridge->bridge_pvt = softmix_data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! \brief Function called when a bridge is destroyed */
|
||||
static int softmix_bridge_destroy(struct ast_bridge *bridge)
|
||||
{
|
||||
struct softmix_bridge_data *bridge_data = bridge->bridge_pvt;
|
||||
struct softmix_bridge_data *softmix_data = bridge->bridge_pvt;
|
||||
if (!bridge->bridge_pvt) {
|
||||
return -1;
|
||||
}
|
||||
ast_timer_close(bridge_data->timer);
|
||||
ast_free(bridge_data);
|
||||
ao2_ref(softmix_data, -1);
|
||||
bridge->bridge_pvt = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void set_softmix_bridge_data(int rate, struct ast_bridge_channel *bridge_channel, int reset)
|
||||
static void set_softmix_bridge_data(int rate, int interval, struct ast_bridge_channel *bridge_channel, int reset)
|
||||
{
|
||||
struct softmix_channel *sc = bridge_channel->bridge_pvt;
|
||||
unsigned int channel_read_rate = ast_format_rate(&bridge_channel->chan->rawreadformat);
|
||||
|
||||
ast_mutex_lock(&sc->lock);
|
||||
if (reset) {
|
||||
ast_slinfactory_destroy(&sc->factory);
|
||||
ast_dsp_free(sc->dsp);
|
||||
}
|
||||
/* Setup frame parameters */
|
||||
sc->frame.frametype = AST_FRAME_VOICE;
|
||||
/* Setup read/write frame parameters */
|
||||
sc->write_frame.frametype = AST_FRAME_VOICE;
|
||||
ast_format_set(&sc->write_frame.subclass.format, ast_format_slin_by_rate(rate), 0);
|
||||
sc->write_frame.data.ptr = sc->final_buf;
|
||||
sc->write_frame.datalen = SOFTMIX_DATALEN(rate, interval);
|
||||
sc->write_frame.samples = SOFTMIX_SAMPLES(rate, interval);
|
||||
|
||||
ast_format_set(&sc->frame.subclass.format, ast_format_slin_by_rate(rate), 0);
|
||||
sc->frame.data.ptr = sc->final_buf;
|
||||
sc->frame.datalen = SOFTMIX_DATALEN(rate);
|
||||
sc->frame.samples = SOFTMIX_SAMPLES(rate);
|
||||
sc->read_frame.frametype = AST_FRAME_VOICE;
|
||||
ast_format_set(&sc->read_frame.subclass.format, ast_format_slin_by_rate(channel_read_rate), 0);
|
||||
sc->read_frame.data.ptr = sc->our_buf;
|
||||
sc->read_frame.datalen = SOFTMIX_DATALEN(channel_read_rate, interval);
|
||||
sc->read_frame.samples = SOFTMIX_SAMPLES(channel_read_rate, interval);
|
||||
|
||||
/* Setup smoother */
|
||||
ast_slinfactory_init_with_format(&sc->factory, &sc->frame.subclass.format);
|
||||
ast_slinfactory_init_with_format(&sc->factory, &sc->write_frame.subclass.format);
|
||||
|
||||
ast_set_read_format(bridge_channel->chan, &sc->frame.subclass.format);
|
||||
ast_set_write_format(bridge_channel->chan, &sc->frame.subclass.format);
|
||||
/* set new read and write formats on channel. */
|
||||
ast_set_read_format(bridge_channel->chan, &sc->read_frame.subclass.format);
|
||||
ast_set_write_format(bridge_channel->chan, &sc->write_frame.subclass.format);
|
||||
|
||||
/* set up new DSP. This is on the read side only right before the read frame enters the smoother. */
|
||||
sc->dsp = ast_dsp_new_with_rate(channel_read_rate);
|
||||
/* we want to aggressively detect silence to avoid feedback */
|
||||
if (bridge_channel->tech_args.talking_threshold) {
|
||||
ast_dsp_set_threshold(sc->dsp, bridge_channel->tech_args.talking_threshold);
|
||||
} else {
|
||||
ast_dsp_set_threshold(sc->dsp, DEFAULT_SOFTMIX_TALKING_THRESHOLD);
|
||||
}
|
||||
|
||||
ast_mutex_unlock(&sc->lock);
|
||||
}
|
||||
|
||||
/*! \brief Function called when a channel is joined into the bridge */
|
||||
static int softmix_bridge_join(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
|
||||
{
|
||||
struct softmix_channel *sc = NULL;
|
||||
struct softmix_bridge_data *bridge_data = bridge->bridge_pvt;
|
||||
struct softmix_bridge_data *softmix_data = bridge->bridge_pvt;
|
||||
|
||||
/* Create a new softmix_channel structure and allocate various things on it */
|
||||
if (!(sc = ast_calloc(1, sizeof(*sc)))) {
|
||||
|
@ -159,7 +372,9 @@ static int softmix_bridge_join(struct ast_bridge *bridge, struct ast_bridge_chan
|
|||
/* Can't forget to record our pvt structure within the bridged channel structure */
|
||||
bridge_channel->bridge_pvt = sc;
|
||||
|
||||
set_softmix_bridge_data(bridge_data->internal_rate, bridge_channel, 0);
|
||||
set_softmix_bridge_data(softmix_data->internal_rate,
|
||||
softmix_data->internal_mixing_interval ? softmix_data->internal_mixing_interval : DEFAULT_SOFTMIX_INTERVAL,
|
||||
bridge_channel, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -169,45 +384,121 @@ static int softmix_bridge_leave(struct ast_bridge *bridge, struct ast_bridge_cha
|
|||
{
|
||||
struct softmix_channel *sc = bridge_channel->bridge_pvt;
|
||||
|
||||
if (!(bridge_channel->bridge_pvt)) {
|
||||
return 0;
|
||||
}
|
||||
bridge_channel->bridge_pvt = NULL;
|
||||
|
||||
/* Drop mutex lock */
|
||||
ast_mutex_destroy(&sc->lock);
|
||||
|
||||
/* Drop the factory */
|
||||
ast_slinfactory_destroy(&sc->factory);
|
||||
|
||||
/* Drop the DSP */
|
||||
ast_dsp_free(sc->dsp);
|
||||
|
||||
/* Eep! drop ourselves */
|
||||
ast_free(sc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief If the bridging core passes DTMF to us, then they want it to be distributed out to all memebers. Do that here.
|
||||
*/
|
||||
static void softmix_pass_dtmf(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
|
||||
{
|
||||
struct ast_bridge_channel *tmp;
|
||||
AST_LIST_TRAVERSE(&bridge->channels, tmp, entry) {
|
||||
if (tmp == bridge_channel) {
|
||||
continue;
|
||||
}
|
||||
ast_write(tmp->chan, frame);
|
||||
}
|
||||
}
|
||||
|
||||
/*! \brief Function called when a channel writes a frame into the bridge */
|
||||
static enum ast_bridge_write_result softmix_bridge_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)
|
||||
{
|
||||
struct softmix_channel *sc = bridge_channel->bridge_pvt;
|
||||
struct softmix_bridge_data *softmix_data = bridge->bridge_pvt;
|
||||
int totalsilence = 0;
|
||||
int silence_threshold = bridge_channel->tech_args.silence_threshold ?
|
||||
bridge_channel->tech_args.silence_threshold :
|
||||
DEFAULT_SOFTMIX_SILENCE_THRESHOLD;
|
||||
char update_talking = -1; /* if this is set to 0 or 1, tell the bridge that the channel has started or stopped talking. */
|
||||
int res = AST_BRIDGE_WRITE_SUCCESS;
|
||||
|
||||
/* Only accept audio frames, all others are unsupported */
|
||||
if (frame->frametype != AST_FRAME_VOICE) {
|
||||
return AST_BRIDGE_WRITE_UNSUPPORTED;
|
||||
if (frame->frametype == AST_FRAME_DTMF_END || frame->frametype == AST_FRAME_DTMF_BEGIN) {
|
||||
softmix_pass_dtmf(bridge, bridge_channel, frame);
|
||||
goto no_audio;
|
||||
} else if (frame->frametype != AST_FRAME_VOICE) {
|
||||
res = AST_BRIDGE_WRITE_UNSUPPORTED;
|
||||
goto no_audio;
|
||||
} else if (frame->datalen == 0) {
|
||||
goto no_audio;
|
||||
}
|
||||
|
||||
/* If we made it here, we are going to write the frame into the conference */
|
||||
ast_mutex_lock(&sc->lock);
|
||||
|
||||
/* If a frame was provided add it to the smoother */
|
||||
if (frame->frametype == AST_FRAME_VOICE && ast_format_is_slinear(&frame->subclass.format)) {
|
||||
ast_dsp_silence(sc->dsp, frame, &totalsilence);
|
||||
if (totalsilence < silence_threshold) {
|
||||
if (!sc->talking) {
|
||||
update_talking = 1;
|
||||
}
|
||||
sc->talking = 1; /* tell the write process we have audio to be mixed out */
|
||||
} else {
|
||||
if (sc->talking) {
|
||||
update_talking = 0;
|
||||
}
|
||||
sc->talking = 0;
|
||||
}
|
||||
|
||||
/* Before adding audio in, make sure we haven't fallen behind. If audio has fallen
|
||||
* behind 4 times the amount of samples mixed on every iteration of the mixer, Re-sync
|
||||
* the audio by flushing the buffer before adding new audio in. */
|
||||
if (ast_slinfactory_available(&sc->factory) > (4 * SOFTMIX_SAMPLES(softmix_data->internal_rate, softmix_data->internal_mixing_interval))) {
|
||||
ast_slinfactory_flush(&sc->factory);
|
||||
}
|
||||
|
||||
/* If a frame was provided add it to the smoother, unless drop silence is enabled and this frame
|
||||
* is not determined to be talking. */
|
||||
if (!(bridge_channel->tech_args.drop_silence && !sc->talking) &&
|
||||
(frame->frametype == AST_FRAME_VOICE && ast_format_is_slinear(&frame->subclass.format))) {
|
||||
ast_slinfactory_feed(&sc->factory, frame);
|
||||
}
|
||||
|
||||
/* If a frame is ready to be written out, do so */
|
||||
if (sc->have_frame) {
|
||||
ast_write(bridge_channel->chan, &sc->frame);
|
||||
ast_write(bridge_channel->chan, &sc->write_frame);
|
||||
sc->have_frame = 0;
|
||||
}
|
||||
|
||||
/* Alllll done */
|
||||
ast_mutex_unlock(&sc->lock);
|
||||
|
||||
return AST_BRIDGE_WRITE_SUCCESS;
|
||||
if (update_talking != -1) {
|
||||
ast_bridge_notify_talking(bridge, bridge_channel, update_talking);
|
||||
}
|
||||
|
||||
return res;
|
||||
|
||||
no_audio:
|
||||
/* Even though the frame is not being written into the conference because it is not audio,
|
||||
* we should use this opportunity to check to see if a frame is ready to be written out from
|
||||
* the conference to the channel. */
|
||||
ast_mutex_lock(&sc->lock);
|
||||
if (sc->have_frame) {
|
||||
ast_write(bridge_channel->chan, &sc->write_frame);
|
||||
sc->have_frame = 0;
|
||||
}
|
||||
ast_mutex_unlock(&sc->lock);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*! \brief Function called when the channel's thread is poked */
|
||||
|
@ -218,7 +509,7 @@ static int softmix_bridge_poke(struct ast_bridge *bridge, struct ast_bridge_chan
|
|||
ast_mutex_lock(&sc->lock);
|
||||
|
||||
if (sc->have_frame) {
|
||||
ast_write(bridge_channel->chan, &sc->frame);
|
||||
ast_write(bridge_channel->chan, &sc->write_frame);
|
||||
sc->have_frame = 0;
|
||||
}
|
||||
|
||||
|
@ -227,167 +518,306 @@ static int softmix_bridge_poke(struct ast_bridge *bridge, struct ast_bridge_chan
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void gather_softmix_stats(struct softmix_stats *stats,
|
||||
const struct softmix_bridge_data *softmix_data,
|
||||
struct ast_bridge_channel *bridge_channel)
|
||||
{
|
||||
int channel_native_rate;
|
||||
int i;
|
||||
/* Gather stats about channel sample rates. */
|
||||
channel_native_rate = MAX(ast_format_rate(&bridge_channel->chan->rawwriteformat),
|
||||
ast_format_rate(&bridge_channel->chan->rawreadformat));
|
||||
|
||||
if (channel_native_rate > stats->highest_supported_rate) {
|
||||
stats->highest_supported_rate = channel_native_rate;
|
||||
}
|
||||
if (channel_native_rate > softmix_data->internal_rate) {
|
||||
for (i = 0; i < ARRAY_LEN(stats->sample_rates); i++) {
|
||||
if (stats->sample_rates[i] == channel_native_rate) {
|
||||
stats->num_channels[i]++;
|
||||
break;
|
||||
} else if (!stats->sample_rates[i]) {
|
||||
stats->sample_rates[i] = channel_native_rate;
|
||||
stats->num_channels[i]++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
stats->num_above_internal_rate++;
|
||||
} else if (channel_native_rate == softmix_data->internal_rate) {
|
||||
stats->num_at_internal_rate++;
|
||||
}
|
||||
}
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Analyse mixing statistics and change bridges internal rate
|
||||
* if necessary.
|
||||
*
|
||||
* \retval 0, no changes to internal rate
|
||||
* \ratval 1, internal rate was changed, update all the channels on the next mixing iteration.
|
||||
*/
|
||||
static unsigned int analyse_softmix_stats(struct softmix_stats *stats, struct softmix_bridge_data *softmix_data)
|
||||
{
|
||||
int i;
|
||||
/* Re-adjust the internal bridge sample rate if
|
||||
* 1. The bridge's internal sample rate is locked in at a sample
|
||||
* rate other than the current sample rate being used.
|
||||
* 2. two or more channels support a higher sample rate
|
||||
* 3. no channels support the current sample rate or a higher rate
|
||||
*/
|
||||
if (stats->locked_rate) {
|
||||
/* if the rate is locked by the bridge, only update it if it differs
|
||||
* from the current rate we are using. */
|
||||
if (softmix_data->internal_rate != stats->locked_rate) {
|
||||
softmix_data->internal_rate = stats->locked_rate;
|
||||
ast_debug(1, " Bridge is locked in at sample rate %d\n", softmix_data->internal_rate);
|
||||
return 1;
|
||||
}
|
||||
} else if (stats->num_above_internal_rate >= 2) {
|
||||
/* the highest rate is just used as a starting point */
|
||||
unsigned int best_rate = stats->highest_supported_rate;
|
||||
int best_index = -1;
|
||||
|
||||
for (i = 0; i < ARRAY_LEN(stats->num_channels); i++) {
|
||||
if (stats->num_channels[i]) {
|
||||
break;
|
||||
}
|
||||
/* best_rate starts out being the first sample rate
|
||||
* greater than the internal sample rate that 2 or
|
||||
* more channels support. */
|
||||
if (stats->num_channels[i] >= 2 && (best_index == -1)) {
|
||||
best_rate = stats->sample_rates[i];
|
||||
best_index = i;
|
||||
/* If it has been detected that multiple rates above
|
||||
* the internal rate are present, compare those rates
|
||||
* to each other and pick the highest one two or more
|
||||
* channels support. */
|
||||
} else if (((best_index != -1) &&
|
||||
(stats->num_channels[i] >= 2) &&
|
||||
(stats->sample_rates[best_index] < stats->sample_rates[i]))) {
|
||||
best_rate = stats->sample_rates[i];
|
||||
best_index = i;
|
||||
/* It is possible that multiple channels exist with native sample
|
||||
* rates above the internal sample rate, but none of those channels
|
||||
* have the same rate in common. In this case, the lowest sample
|
||||
* rate among those channels is picked. Over time as additional
|
||||
* statistic runs are made the internal sample rate number will
|
||||
* adjust to the most optimal sample rate, but it may take multiple
|
||||
* iterations. */
|
||||
} else if (best_index == -1) {
|
||||
best_rate = MIN(best_rate, stats->sample_rates[i]);
|
||||
}
|
||||
}
|
||||
|
||||
ast_debug(1, " Bridge changed from %d To %d\n", softmix_data->internal_rate, best_rate);
|
||||
softmix_data->internal_rate = best_rate;
|
||||
return 1;
|
||||
} else if (!stats->num_at_internal_rate && !stats->num_above_internal_rate) {
|
||||
/* In this case, the highest supported rate is actually lower than the internal rate */
|
||||
softmix_data->internal_rate = stats->highest_supported_rate;
|
||||
ast_debug(1, " Bridge changed from %d to %d\n", softmix_data->internal_rate, stats->highest_supported_rate);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int softmix_mixing_array_init(struct softmix_mixing_array *mixing_array, unsigned int starting_num_entries)
|
||||
{
|
||||
memset(mixing_array, 0, sizeof(*mixing_array));
|
||||
mixing_array->max_num_entries = starting_num_entries;
|
||||
if (!(mixing_array->buffers = ast_calloc(mixing_array->max_num_entries, sizeof(int16_t *)))) {
|
||||
ast_log(LOG_NOTICE, "Failed to allocate softmix mixing structure. \n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void softmix_mixing_array_destroy(struct softmix_mixing_array *mixing_array)
|
||||
{
|
||||
ast_free(mixing_array->buffers);
|
||||
}
|
||||
|
||||
static int softmix_mixing_array_grow(struct softmix_mixing_array *mixing_array, unsigned int num_entries)
|
||||
{
|
||||
int16_t **tmp;
|
||||
/* give it some room to grow since memory is cheap but allocations can be expensive */
|
||||
mixing_array->max_num_entries = num_entries;
|
||||
if (!(tmp = ast_realloc(mixing_array->buffers, (mixing_array->max_num_entries * sizeof(int16_t *))))) {
|
||||
ast_log(LOG_NOTICE, "Failed to re-allocate softmix mixing structure. \n");
|
||||
return -1;
|
||||
}
|
||||
mixing_array->buffers = tmp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! \brief Function which acts as the mixing thread */
|
||||
static int softmix_bridge_thread(struct ast_bridge *bridge)
|
||||
{
|
||||
struct {
|
||||
/*! Each index represents a sample rate used above the internal rate. */
|
||||
unsigned int sample_rates[8];
|
||||
/*! Each index represents the number of channels using the same index in the sample_rates array. */
|
||||
unsigned int num_channels[8];
|
||||
/*! the number of channels above the internal sample rate */
|
||||
unsigned int num_above_internal_rate;
|
||||
/*! the number of channels at the internal sample rate */
|
||||
unsigned int num_at_internal_rate;
|
||||
/*! the absolute highest sample rate supported by any channel in the bridge */
|
||||
unsigned int highest_supported_rate;
|
||||
} stats;
|
||||
struct softmix_bridge_data *bridge_data = bridge->bridge_pvt;
|
||||
struct ast_timer *timer = bridge_data->timer;
|
||||
int timingfd = ast_timer_fd(timer);
|
||||
struct softmix_stats stats = { { 0 }, };
|
||||
struct softmix_mixing_array mixing_array;
|
||||
struct softmix_bridge_data *softmix_data = bridge->bridge_pvt;
|
||||
struct ast_timer *timer;
|
||||
struct softmix_translate_helper trans_helper;
|
||||
int16_t buf[MAX_DATALEN] = { 0, };
|
||||
unsigned int stat_iteration_counter = 0; /* counts down, gather stats at zero and reset. */
|
||||
int timingfd;
|
||||
int update_all_rates = 0; /* set this when the internal sample rate has changed */
|
||||
int i;
|
||||
int i, x;
|
||||
int res = -1;
|
||||
|
||||
ast_timer_set_rate(timer, (1000 / SOFTMIX_INTERVAL));
|
||||
if (!(softmix_data = bridge->bridge_pvt)) {
|
||||
goto softmix_cleanup;
|
||||
}
|
||||
|
||||
ao2_ref(softmix_data, 1);
|
||||
timer = softmix_data->timer;
|
||||
timingfd = ast_timer_fd(timer);
|
||||
softmix_translate_helper_init(&trans_helper, softmix_data->internal_rate);
|
||||
ast_timer_set_rate(timer, (1000 / softmix_data->internal_mixing_interval));
|
||||
|
||||
/* Give the mixing array room to grow, memory is cheap but allocations are expensive. */
|
||||
if (softmix_mixing_array_init(&mixing_array, bridge->num + 10)) {
|
||||
ast_log(LOG_NOTICE, "Failed to allocate softmix mixing structure. \n");
|
||||
goto softmix_cleanup;
|
||||
}
|
||||
|
||||
while (!bridge->stop && !bridge->refresh && bridge->array_num) {
|
||||
struct ast_bridge_channel *bridge_channel = NULL;
|
||||
short buf[MAX_DATALEN] = {0, };
|
||||
int timeout = -1;
|
||||
enum ast_format_id cur_slin_id = ast_format_slin_by_rate(softmix_data->internal_rate);
|
||||
unsigned int softmix_samples = SOFTMIX_SAMPLES(softmix_data->internal_rate, softmix_data->internal_mixing_interval);
|
||||
unsigned int softmix_datalen = SOFTMIX_DATALEN(softmix_data->internal_rate, softmix_data->internal_mixing_interval);
|
||||
|
||||
/* these variables help determine if a rate change is required */
|
||||
memset(&stats, 0, sizeof(stats));
|
||||
stats.highest_supported_rate = 8000;
|
||||
if (softmix_datalen > MAX_DATALEN) {
|
||||
/* This should NEVER happen, but if it does we need to know about it. Almost
|
||||
* all the memcpys used during this process depend on this assumption. Rather
|
||||
* than checking this over and over again through out the code, this single
|
||||
* verification is done on each iteration. */
|
||||
ast_log(LOG_WARNING, "Conference mixing error, requested mixing length greater than mixing buffer.\n");
|
||||
goto softmix_cleanup;
|
||||
}
|
||||
|
||||
/* Grow the mixing array buffer as participants are added. */
|
||||
if (mixing_array.max_num_entries < bridge->num && softmix_mixing_array_grow(&mixing_array, bridge->num + 5)) {
|
||||
goto softmix_cleanup;
|
||||
}
|
||||
|
||||
/* init the number of buffers stored in the mixing array to 0.
|
||||
* As buffers are added for mixing, this number is incremented. */
|
||||
mixing_array.used_entries = 0;
|
||||
|
||||
/* These variables help determine if a rate change is required */
|
||||
if (!stat_iteration_counter) {
|
||||
memset(&stats, 0, sizeof(stats));
|
||||
stats.locked_rate = bridge->internal_sample_rate;
|
||||
}
|
||||
|
||||
/* If the sample rate has changed, update the translator helper */
|
||||
if (update_all_rates) {
|
||||
softmix_translate_helper_change_rate(&trans_helper, softmix_data->internal_rate);
|
||||
}
|
||||
|
||||
/* Go through pulling audio from each factory that has it available */
|
||||
AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
|
||||
struct softmix_channel *sc = bridge_channel->bridge_pvt;
|
||||
int channel_native_rate;
|
||||
|
||||
ast_mutex_lock(&sc->lock);
|
||||
|
||||
/* Update the sample rate to match the bridge's native sample rate if necessary. */
|
||||
if (update_all_rates) {
|
||||
set_softmix_bridge_data(bridge_data->internal_rate, bridge_channel, 1);
|
||||
set_softmix_bridge_data(softmix_data->internal_rate, softmix_data->internal_mixing_interval, bridge_channel, 1);
|
||||
}
|
||||
|
||||
/* If stat_iteration_counter is 0, then collect statistics during this mixing interation */
|
||||
if (!stat_iteration_counter) {
|
||||
gather_softmix_stats(&stats, softmix_data, bridge_channel);
|
||||
}
|
||||
|
||||
/* if the channel is suspended, don't check for audio, but still gather stats */
|
||||
if (bridge_channel->suspended) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Try to get audio from the factory if available */
|
||||
if (ast_slinfactory_available(&sc->factory) >= SOFTMIX_SAMPLES(bridge_data->internal_rate) &&
|
||||
ast_slinfactory_read(&sc->factory, sc->our_buf, SOFTMIX_SAMPLES(bridge_data->internal_rate))) {
|
||||
short *data1, *data2;
|
||||
int i;
|
||||
|
||||
/* Put into the local final buffer */
|
||||
for (i = 0, data1 = buf, data2 = sc->our_buf; i < SOFTMIX_DATALEN(bridge_data->internal_rate); i++, data1++, data2++)
|
||||
ast_slinear_saturated_add(data1, data2);
|
||||
/* Yay we have our own audio */
|
||||
sc->have_audio = 1;
|
||||
} else {
|
||||
/* Awww we don't have audio ;( */
|
||||
sc->have_audio = 0;
|
||||
ast_mutex_lock(&sc->lock);
|
||||
if ((mixing_array.buffers[mixing_array.used_entries] = softmix_process_read_audio(sc, softmix_samples))) {
|
||||
mixing_array.used_entries++;
|
||||
}
|
||||
|
||||
/* Gather stats about channel sample rates. */
|
||||
channel_native_rate = MAX(ast_format_rate(&bridge_channel->chan->rawwriteformat),
|
||||
ast_format_rate(&bridge_channel->chan->rawreadformat));
|
||||
|
||||
if (channel_native_rate > stats.highest_supported_rate) {
|
||||
stats.highest_supported_rate = channel_native_rate;
|
||||
}
|
||||
if (channel_native_rate > bridge_data->internal_rate) {
|
||||
for (i = 0; i < ARRAY_LEN(stats.sample_rates); i++) {
|
||||
if (stats.sample_rates[i] == channel_native_rate) {
|
||||
stats.num_channels[i]++;
|
||||
break;
|
||||
} else if (!stats.sample_rates[i]) {
|
||||
stats.sample_rates[i] = channel_native_rate;
|
||||
stats.num_channels[i]++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
stats.num_above_internal_rate++;
|
||||
} else if (channel_native_rate == bridge_data->internal_rate) {
|
||||
stats.num_at_internal_rate++;
|
||||
}
|
||||
|
||||
ast_mutex_unlock(&sc->lock);
|
||||
}
|
||||
|
||||
/* mix it like crazy */
|
||||
memset(buf, 0, softmix_datalen);
|
||||
for (i = 0; i < mixing_array.used_entries; i++) {
|
||||
for (x = 0; x < softmix_samples; x++) {
|
||||
ast_slinear_saturated_add(buf + x, mixing_array.buffers[i] + x);
|
||||
}
|
||||
}
|
||||
|
||||
/* Next step go through removing the channel's own audio and creating a good frame... */
|
||||
AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
|
||||
struct softmix_channel *sc = bridge_channel->bridge_pvt;
|
||||
int i = 0;
|
||||
|
||||
/* Copy from local final buffer to our final buffer */
|
||||
memcpy(sc->final_buf, buf, sizeof(sc->final_buf));
|
||||
|
||||
/* If we provided audio then take it out */
|
||||
if (sc->have_audio) {
|
||||
for (i = 0; i < SOFTMIX_DATALEN(bridge_data->internal_rate); i++) {
|
||||
ast_slinear_saturated_subtract(&sc->final_buf[i], &sc->our_buf[i]);
|
||||
}
|
||||
if (bridge_channel->suspended) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ast_mutex_lock(&sc->lock);
|
||||
|
||||
/* Make SLINEAR write frame from local buffer */
|
||||
if (sc->write_frame.subclass.format.id != cur_slin_id) {
|
||||
ast_format_set(&sc->write_frame.subclass.format, cur_slin_id, 0);
|
||||
}
|
||||
sc->write_frame.datalen = softmix_datalen;
|
||||
sc->write_frame.samples = softmix_samples;
|
||||
memcpy(sc->final_buf, buf, softmix_datalen);
|
||||
|
||||
/* process the softmix channel's new write audio */
|
||||
softmix_process_write_audio(&trans_helper, &bridge_channel->chan->rawwriteformat, sc);
|
||||
|
||||
/* The frame is now ready for use... */
|
||||
sc->have_frame = 1;
|
||||
|
||||
ast_mutex_unlock(&sc->lock);
|
||||
|
||||
/* Poke bridged channel thread just in case */
|
||||
pthread_kill(bridge_channel->thread, SIGURG);
|
||||
}
|
||||
|
||||
/* Re-adjust the internal bridge sample rate if
|
||||
* 1. two or more channels support a higher sample rate
|
||||
* 2. no channels support the current sample rate or a higher rate
|
||||
*/
|
||||
if (stats.num_above_internal_rate >= 2) {
|
||||
/* the highest rate is just used as a starting point */
|
||||
unsigned int best_rate = stats.highest_supported_rate;
|
||||
int best_index = -1;
|
||||
|
||||
/* 1. pick the best sample rate two or more channels support
|
||||
* 2. if two or more channels do not support the same rate, pick the
|
||||
* lowest sample rate that is still above the internal rate. */
|
||||
for (i = 0; ((i < ARRAY_LEN(stats.num_channels)) && stats.num_channels[i]); i++) {
|
||||
if ((stats.num_channels[i] >= 2 && (best_index == -1)) ||
|
||||
((best_index != -1) &&
|
||||
(stats.num_channels[i] >= 2) &&
|
||||
(stats.sample_rates[best_index] < stats.sample_rates[i]))) {
|
||||
|
||||
best_rate = stats.sample_rates[i];
|
||||
best_index = i;
|
||||
} else if (best_index == -1) {
|
||||
best_rate = MIN(best_rate, stats.sample_rates[i]);
|
||||
}
|
||||
}
|
||||
|
||||
ast_debug(1, " Bridge changed from %d To %d\n", bridge_data->internal_rate, best_rate);
|
||||
bridge_data->internal_rate = best_rate;
|
||||
update_all_rates = 1;
|
||||
} else if (!stats.num_at_internal_rate && !stats.num_above_internal_rate) {
|
||||
update_all_rates = 1;
|
||||
/* in this case, the highest supported rate is actually lower than the internal rate */
|
||||
bridge_data->internal_rate = stats.highest_supported_rate;
|
||||
ast_debug(1, " Bridge changed from %d to %d\n", bridge_data->internal_rate, stats.highest_supported_rate);
|
||||
update_all_rates = 1;
|
||||
} else {
|
||||
update_all_rates = 0;
|
||||
update_all_rates = 0;
|
||||
if (!stat_iteration_counter) {
|
||||
update_all_rates = analyse_softmix_stats(&stats, softmix_data);
|
||||
stat_iteration_counter = SOFTMIX_STAT_INTERVAL;
|
||||
}
|
||||
stat_iteration_counter--;
|
||||
|
||||
ao2_unlock(bridge);
|
||||
|
||||
/* cleanup any translation frame data from the previous mixing iteration. */
|
||||
softmix_translate_helper_cleanup(&trans_helper);
|
||||
/* Wait for the timing source to tell us to wake up and get things done */
|
||||
ast_waitfor_n_fd(&timingfd, 1, &timeout, NULL);
|
||||
|
||||
ast_timer_ack(timer, 1);
|
||||
|
||||
ao2_lock(bridge);
|
||||
|
||||
/* make sure to detect mixing interval changes if they occur. */
|
||||
if (bridge->internal_mixing_interval && (bridge->internal_mixing_interval != softmix_data->internal_mixing_interval)) {
|
||||
softmix_data->internal_mixing_interval = bridge->internal_mixing_interval;
|
||||
ast_timer_set_rate(timer, (1000 / softmix_data->internal_mixing_interval));
|
||||
update_all_rates = 1; /* if the interval changes, the rates must be adjusted as well just to be notified new interval.*/
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
res = 0;
|
||||
|
||||
softmix_cleanup:
|
||||
softmix_translate_helper_destroy(&trans_helper);
|
||||
softmix_mixing_array_destroy(&mixing_array);
|
||||
if (softmix_data) {
|
||||
ao2_ref(softmix_data, -1);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static struct ast_bridge_technology softmix_bridge = {
|
||||
.name = "softmix",
|
||||
.capabilities = AST_BRIDGE_CAPABILITY_MULTIMIX | AST_BRIDGE_CAPABILITY_THREAD | AST_BRIDGE_CAPABILITY_MULTITHREADED,
|
||||
.capabilities = AST_BRIDGE_CAPABILITY_MULTIMIX | AST_BRIDGE_CAPABILITY_THREAD | AST_BRIDGE_CAPABILITY_MULTITHREADED | AST_BRIDGE_CAPABILITY_OPTIMIZE,
|
||||
.preference = AST_BRIDGE_PREFERENCE_LOW,
|
||||
.create = softmix_bridge_create,
|
||||
.destroy = softmix_bridge_destroy,
|
||||
|
@ -410,11 +840,7 @@ static int load_module(void)
|
|||
if (!(softmix_bridge.format_capabilities = ast_format_cap_alloc())) {
|
||||
return AST_MODULE_LOAD_DECLINE;
|
||||
}
|
||||
#ifdef SOFTMIX_16_SUPPORT
|
||||
ast_format_cap_add(softmix_bridge.format_capabilities, ast_format_set(&tmp, AST_FORMAT_SLINEAR16, 0));
|
||||
#else
|
||||
ast_format_cap_add(softmix_bridge.format_capabilities, ast_format_set(&tmp, AST_FORMAT_SLINEAR, 0));
|
||||
#endif
|
||||
return ast_bridge_technology_register(&softmix_bridge);
|
||||
}
|
||||
|
||||
|
|
|
@ -224,6 +224,10 @@ return_cleanup:
|
|||
static int unload_module(void)
|
||||
{
|
||||
ast_cdr_unregister(name);
|
||||
if (rh) {
|
||||
rc_destroy(rh);
|
||||
rh = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -231,7 +235,6 @@ static int load_module(void)
|
|||
{
|
||||
struct ast_config *cfg;
|
||||
struct ast_flags config_flags = { 0 };
|
||||
int res;
|
||||
const char *tmp;
|
||||
|
||||
if ((cfg = ast_config_load(cdr_config, config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) {
|
||||
|
@ -244,8 +247,17 @@ static int load_module(void)
|
|||
} else
|
||||
return AST_MODULE_LOAD_DECLINE;
|
||||
|
||||
/* start logging */
|
||||
rc_openlog("asterisk");
|
||||
/*
|
||||
* start logging
|
||||
*
|
||||
* NOTE: Yes this causes a slight memory leak if the module is
|
||||
* unloaded. However, it is better than a crash if cdr_radius
|
||||
* and cel_radius are both loaded.
|
||||
*/
|
||||
tmp = ast_strdup("asterisk");
|
||||
if (tmp) {
|
||||
rc_openlog((char *) tmp);
|
||||
}
|
||||
|
||||
/* read radiusclient-ng config file */
|
||||
if (!(rh = rc_read_config(radiuscfg))) {
|
||||
|
@ -256,11 +268,18 @@ static int load_module(void)
|
|||
/* read radiusclient-ng dictionaries */
|
||||
if (rc_read_dictionary(rh, rc_conf_str(rh, "dictionary"))) {
|
||||
ast_log(LOG_NOTICE, "Cannot load radiusclient-ng dictionary file.\n");
|
||||
rc_destroy(rh);
|
||||
rh = NULL;
|
||||
return AST_MODULE_LOAD_DECLINE;
|
||||
}
|
||||
|
||||
res = ast_cdr_register(name, desc, radius_log);
|
||||
return AST_MODULE_LOAD_SUCCESS;
|
||||
if (ast_cdr_register(name, desc, radius_log)) {
|
||||
rc_destroy(rh);
|
||||
rh = NULL;
|
||||
return AST_MODULE_LOAD_DECLINE;
|
||||
} else {
|
||||
return AST_MODULE_LOAD_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "RADIUS CDR Backend",
|
||||
|
|
|
@ -264,8 +264,10 @@ static int reload(void)
|
|||
return AST_MODULE_LOAD_DECLINE;
|
||||
}
|
||||
|
||||
free_config();
|
||||
res = load_config(1);
|
||||
if ((res = load_config(1))) {
|
||||
free_config();
|
||||
}
|
||||
|
||||
AST_RWLIST_UNLOCK(&sinks);
|
||||
|
||||
return res ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS;
|
||||
|
|
|
@ -751,11 +751,15 @@ static int unload_module(void)
|
|||
|
||||
free_config();
|
||||
AST_RWLIST_UNLOCK(&odbc_tables);
|
||||
AST_RWLIST_HEAD_DESTROY(&odbc_tables);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
{
|
||||
AST_RWLIST_HEAD_INIT(&odbc_tables);
|
||||
|
||||
if (AST_RWLIST_WRLOCK(&odbc_tables)) {
|
||||
ast_log(LOG_ERROR, "Unable to lock column list. Load failed.\n");
|
||||
return 0;
|
||||
|
|
|
@ -239,6 +239,8 @@ static void pgsql_log(const struct ast_event *event, void *userdata)
|
|||
value = record.user_field;
|
||||
} else if (strcmp(cur->name, "peer") == 0) {
|
||||
value = record.peer;
|
||||
} else if (strcmp(cur->name, "extra") == 0) {
|
||||
value = record.extra;
|
||||
} else {
|
||||
value = NULL;
|
||||
}
|
||||
|
@ -535,7 +537,6 @@ static int process_my_load_module(struct ast_config *cfg)
|
|||
static int my_load_module(int reload)
|
||||
{
|
||||
struct ast_config *cfg;
|
||||
int res;
|
||||
struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
|
||||
|
||||
if ((cfg = ast_config_load(config, config_flags)) == NULL || cfg == CONFIG_STATUS_FILEINVALID) {
|
||||
|
@ -545,7 +546,7 @@ static int my_load_module(int reload)
|
|||
return AST_MODULE_LOAD_SUCCESS;
|
||||
}
|
||||
|
||||
res = process_my_load_module(cfg);
|
||||
process_my_load_module(cfg);
|
||||
ast_config_destroy(cfg);
|
||||
|
||||
event_sub = ast_event_subscribe(AST_EVENT_CEL, pgsql_log, "CEL PGSQL backend", NULL, AST_EVENT_IE_END);
|
||||
|
|
|
@ -206,6 +206,10 @@ static int unload_module(void)
|
|||
if (event_sub) {
|
||||
event_sub = ast_event_unsubscribe(event_sub);
|
||||
}
|
||||
if (rh) {
|
||||
rc_destroy(rh);
|
||||
rh = NULL;
|
||||
}
|
||||
return AST_MODULE_LOAD_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -225,8 +229,17 @@ static int load_module(void)
|
|||
return AST_MODULE_LOAD_DECLINE;
|
||||
}
|
||||
|
||||
/* start logging */
|
||||
rc_openlog("asterisk");
|
||||
/*
|
||||
* start logging
|
||||
*
|
||||
* NOTE: Yes this causes a slight memory leak if the module is
|
||||
* unloaded. However, it is better than a crash if cdr_radius
|
||||
* and cel_radius are both loaded.
|
||||
*/
|
||||
tmp = ast_strdup("asterisk");
|
||||
if (tmp) {
|
||||
rc_openlog((char *) tmp);
|
||||
}
|
||||
|
||||
/* read radiusclient-ng config file */
|
||||
if (!(rh = rc_read_config(radiuscfg))) {
|
||||
|
@ -237,12 +250,15 @@ static int load_module(void)
|
|||
/* read radiusclient-ng dictionaries */
|
||||
if (rc_read_dictionary(rh, rc_conf_str(rh, "dictionary"))) {
|
||||
ast_log(LOG_NOTICE, "Cannot load radiusclient-ng dictionary file.\n");
|
||||
rc_destroy(rh);
|
||||
rh = NULL;
|
||||
return AST_MODULE_LOAD_DECLINE;
|
||||
}
|
||||
|
||||
event_sub = ast_event_subscribe(AST_EVENT_CEL, radius_log, "CEL Radius Logging", NULL, AST_EVENT_IE_END);
|
||||
|
||||
if (!event_sub) {
|
||||
rc_destroy(rh);
|
||||
rh = NULL;
|
||||
return AST_MODULE_LOAD_DECLINE;
|
||||
} else {
|
||||
return AST_MODULE_LOAD_SUCCESS;
|
||||
|
|
|
@ -269,9 +269,9 @@ struct agent_pvt {
|
|||
char agent[AST_MAX_AGENT]; /*!< Agent ID */
|
||||
char password[AST_MAX_AGENT]; /*!< Password for Agent login */
|
||||
char name[AST_MAX_AGENT];
|
||||
ast_mutex_t app_lock; /**< Synchronization between owning applications */
|
||||
int app_lock_flag;
|
||||
ast_cond_t app_complete_cond;
|
||||
ast_cond_t login_wait_cond;
|
||||
volatile int app_sleep_cond; /**< Sleep condition for the login app */
|
||||
struct ast_channel *owner; /**< Agent */
|
||||
char logincallerid[80]; /**< Caller ID they had when they logged in */
|
||||
|
@ -429,8 +429,8 @@ static struct agent_pvt *add_agent(const char *agent, int pending)
|
|||
return NULL;
|
||||
ast_copy_string(p->agent, agt, sizeof(p->agent));
|
||||
ast_mutex_init(&p->lock);
|
||||
ast_mutex_init(&p->app_lock);
|
||||
ast_cond_init(&p->app_complete_cond, NULL);
|
||||
ast_cond_init(&p->login_wait_cond, NULL);
|
||||
p->app_lock_flag = 0;
|
||||
p->app_sleep_cond = 1;
|
||||
p->group = group;
|
||||
|
@ -483,20 +483,23 @@ static struct agent_pvt *add_agent(const char *agent, int pending)
|
|||
*/
|
||||
static int agent_cleanup(struct agent_pvt *p)
|
||||
{
|
||||
struct ast_channel *chan = p->owner;
|
||||
struct ast_channel *chan = NULL;
|
||||
ast_mutex_lock(&p->lock);
|
||||
chan = p->owner;
|
||||
p->owner = NULL;
|
||||
chan->tech_pvt = NULL;
|
||||
p->app_sleep_cond = 1;
|
||||
/* Release ownership of the agent to other threads (presumably running the login app). */
|
||||
p->app_sleep_cond = 1;
|
||||
p->app_lock_flag = 0;
|
||||
ast_cond_signal(&p->app_complete_cond);
|
||||
if (chan) {
|
||||
chan = ast_channel_release(chan);
|
||||
}
|
||||
if (p->dead) {
|
||||
ast_mutex_unlock(&p->lock);
|
||||
ast_mutex_destroy(&p->lock);
|
||||
ast_mutex_destroy(&p->app_lock);
|
||||
ast_cond_destroy(&p->app_complete_cond);
|
||||
ast_cond_destroy(&p->login_wait_cond);
|
||||
ast_free(p);
|
||||
}
|
||||
return 0;
|
||||
|
@ -773,30 +776,42 @@ static int agent_call(struct ast_channel *ast, char *dest, int timeout)
|
|||
struct agent_pvt *p = ast->tech_pvt;
|
||||
int res = -1;
|
||||
int newstate=0;
|
||||
struct ast_channel *chan;
|
||||
|
||||
ast_mutex_lock(&p->lock);
|
||||
p->acknowledged = 0;
|
||||
if (!p->chan) {
|
||||
if (p->pending) {
|
||||
ast_debug(1, "Pretending to dial on pending agent\n");
|
||||
newstate = AST_STATE_DIALING;
|
||||
res = 0;
|
||||
} else {
|
||||
ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call... what are the odds of that?\n");
|
||||
res = -1;
|
||||
}
|
||||
|
||||
if (p->pending) {
|
||||
ast_log(LOG_DEBUG, "Pretending to dial on pending agent\n");
|
||||
ast_mutex_unlock(&p->lock);
|
||||
ast_setstate(ast, AST_STATE_DIALING);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!p->chan) {
|
||||
ast_log(LOG_DEBUG, "Agent disconnected while we were connecting the call\n");
|
||||
ast_mutex_unlock(&p->lock);
|
||||
if (newstate)
|
||||
ast_setstate(ast, newstate);
|
||||
return res;
|
||||
}
|
||||
ast_verb(3, "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name);
|
||||
ast_debug(3, "Playing beep, lang '%s'\n", p->chan->language);
|
||||
res = ast_streamfile(p->chan, beep, p->chan->language);
|
||||
|
||||
chan = p->chan;
|
||||
ast_mutex_unlock(&p->lock);
|
||||
|
||||
res = ast_streamfile(chan, beep, chan->language);
|
||||
ast_debug(3, "Played beep, result '%d'\n", res);
|
||||
if (!res) {
|
||||
res = ast_waitstream(p->chan, "");
|
||||
res = ast_waitstream(chan, "");
|
||||
ast_debug(3, "Waited for stream, result '%d'\n", res);
|
||||
}
|
||||
|
||||
ast_mutex_lock(&p->lock);
|
||||
if (!p->chan) {
|
||||
/* chan went away while we were streaming, this shouldn't be possible */
|
||||
res = -1;
|
||||
}
|
||||
|
||||
if (!res) {
|
||||
struct ast_format tmpfmt;
|
||||
res = ast_set_read_format_from_cap(p->chan, p->chan->nativeformats);
|
||||
|
@ -872,7 +887,6 @@ int agent_set_base_channel(struct ast_channel *chan, struct ast_channel *base)
|
|||
static int agent_hangup(struct ast_channel *ast)
|
||||
{
|
||||
struct agent_pvt *p = ast->tech_pvt;
|
||||
int howlong = 0;
|
||||
|
||||
ast_mutex_lock(&p->lock);
|
||||
p->owner = NULL;
|
||||
|
@ -880,6 +894,10 @@ static int agent_hangup(struct ast_channel *ast)
|
|||
p->app_sleep_cond = 1;
|
||||
p->acknowledged = 0;
|
||||
|
||||
/* Release ownership of the agent to other threads (presumably running the login app). */
|
||||
p->app_lock_flag = 0;
|
||||
ast_cond_signal(&p->app_complete_cond);
|
||||
|
||||
/* if they really are hung up then set start to 0 so the test
|
||||
* later if we're called on an already downed channel
|
||||
* doesn't cause an agent to be logged out like when
|
||||
|
@ -889,11 +907,8 @@ static int agent_hangup(struct ast_channel *ast)
|
|||
|
||||
ast_debug(1, "Hangup called for state %s\n", ast_state2str(ast->_state));
|
||||
if (p->start && (ast->_state != AST_STATE_UP)) {
|
||||
howlong = time(NULL) - p->start;
|
||||
p->start = 0;
|
||||
} else if (ast->_state == AST_STATE_RESERVED)
|
||||
howlong = 0;
|
||||
else
|
||||
} else
|
||||
p->start = 0;
|
||||
if (p->chan) {
|
||||
p->chan->_bridge = NULL;
|
||||
|
@ -930,8 +945,8 @@ static int agent_hangup(struct ast_channel *ast)
|
|||
p->abouttograb = 0;
|
||||
} else if (p->dead) {
|
||||
ast_mutex_destroy(&p->lock);
|
||||
ast_mutex_destroy(&p->app_lock);
|
||||
ast_cond_destroy(&p->app_complete_cond);
|
||||
ast_cond_destroy(&p->login_wait_cond);
|
||||
ast_free(p);
|
||||
} else {
|
||||
if (p->chan) {
|
||||
|
@ -941,9 +956,6 @@ static int agent_hangup(struct ast_channel *ast)
|
|||
p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
|
||||
ast_mutex_unlock(&p->lock);
|
||||
}
|
||||
/* Release ownership of the agent to other threads (presumably running the login app). */
|
||||
p->app_lock_flag = 0;
|
||||
ast_cond_signal(&p->app_complete_cond);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -1030,7 +1042,6 @@ static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct
|
|||
static struct ast_channel *agent_new(struct agent_pvt *p, int state, const char *linkedid)
|
||||
{
|
||||
struct ast_channel *tmp;
|
||||
int alreadylocked;
|
||||
#if 0
|
||||
if (!p->chan) {
|
||||
ast_log(LOG_WARNING, "No channel? :(\n");
|
||||
|
@ -1068,38 +1079,6 @@ static struct ast_channel *agent_new(struct agent_pvt *p, int state, const char
|
|||
tmp->tech_pvt = p;
|
||||
p->owner = tmp;
|
||||
tmp->priority = 1;
|
||||
/* Wake up and wait for other applications (by definition the login app)
|
||||
* to release this channel). Takes ownership of the agent channel
|
||||
* to this thread only.
|
||||
* For signalling the other thread, ast_queue_frame is used until we
|
||||
* can safely use signals for this purpose. The pselect() needs to be
|
||||
* implemented in the kernel for this.
|
||||
*/
|
||||
p->app_sleep_cond = 0;
|
||||
|
||||
alreadylocked = p->app_lock_flag;
|
||||
p->app_lock_flag = 1;
|
||||
|
||||
if (alreadylocked) {
|
||||
if (p->chan) {
|
||||
ast_queue_frame(p->chan, &ast_null_frame);
|
||||
ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */
|
||||
p->app_lock_flag = 1;
|
||||
ast_mutex_lock(&p->lock);
|
||||
} else {
|
||||
ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
|
||||
p->owner = NULL;
|
||||
tmp->tech_pvt = NULL;
|
||||
p->app_sleep_cond = 1;
|
||||
tmp = ast_channel_release(tmp);
|
||||
ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */
|
||||
p->app_lock_flag = 0;
|
||||
ast_cond_signal(&p->app_complete_cond);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (p->chan)
|
||||
ast_indicate(p->chan, AST_CONTROL_UNHOLD);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
@ -1257,8 +1236,8 @@ static int read_agent_config(int reload)
|
|||
if (!p->owner) {
|
||||
if (!p->chan) {
|
||||
ast_mutex_destroy(&p->lock);
|
||||
ast_mutex_destroy(&p->app_lock);
|
||||
ast_cond_destroy(&p->app_complete_cond);
|
||||
ast_cond_destroy(&p->login_wait_cond);
|
||||
ast_free(p);
|
||||
} else {
|
||||
/* Cause them to hang up */
|
||||
|
@ -1459,6 +1438,45 @@ static struct ast_channel *agent_request(const char *type, struct ast_format_cap
|
|||
}
|
||||
*cause = hasagent ? AST_CAUSE_BUSY : AST_CAUSE_UNREGISTERED;
|
||||
AST_LIST_UNLOCK(&agents);
|
||||
|
||||
if (chan) {
|
||||
ast_mutex_lock(&p->lock);
|
||||
if (p->pending) {
|
||||
ast_mutex_unlock(&p->lock);
|
||||
return chan;
|
||||
}
|
||||
|
||||
if (!p->chan) {
|
||||
ast_log(LOG_DEBUG, "Agent disconnected while we were connecting the call\n");
|
||||
*cause = AST_CAUSE_UNREGISTERED;
|
||||
ast_mutex_unlock(&p->lock);
|
||||
agent_hangup(chan);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* we need to take control of the channel from the login app
|
||||
* thread */
|
||||
p->app_sleep_cond = 0;
|
||||
p->app_lock_flag = 1;
|
||||
|
||||
ast_queue_frame(p->chan, &ast_null_frame);
|
||||
ast_cond_wait(&p->login_wait_cond, &p->lock);
|
||||
|
||||
if (!p->chan) {
|
||||
ast_log(LOG_DEBUG, "Agent disconnected while we were connecting the call\n");
|
||||
p->app_sleep_cond = 1;
|
||||
p->app_lock_flag = 0;
|
||||
ast_cond_signal(&p->app_complete_cond);
|
||||
ast_mutex_unlock(&p->lock);
|
||||
*cause = AST_CAUSE_UNREGISTERED;
|
||||
agent_hangup(chan);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ast_indicate(p->chan, AST_CONTROL_UNHOLD);
|
||||
ast_mutex_unlock(&p->lock);
|
||||
}
|
||||
|
||||
return chan;
|
||||
}
|
||||
|
||||
|
@ -1834,7 +1852,6 @@ static int login_exec(struct ast_channel *chan, const char *data)
|
|||
int max_login_tries = maxlogintries;
|
||||
struct agent_pvt *p;
|
||||
struct ast_module_user *u;
|
||||
int login_state = 0;
|
||||
char user[AST_MAX_AGENT] = "";
|
||||
char pass[AST_MAX_AGENT];
|
||||
char agent[AST_MAX_AGENT] = "";
|
||||
|
@ -1928,7 +1945,6 @@ static int login_exec(struct ast_channel *chan, const char *data)
|
|||
ast_mutex_lock(&p->lock);
|
||||
if (!strcmp(p->agent, user) &&
|
||||
!strcmp(p->password, pass) && !p->pending) {
|
||||
login_state = 1; /* Successful Login */
|
||||
|
||||
/* Ensure we can't be gotten until we're done */
|
||||
p->lastdisc = ast_tvnow();
|
||||
|
@ -2070,13 +2086,13 @@ static int login_exec(struct ast_channel *chan, const char *data)
|
|||
}
|
||||
ast_mutex_unlock(&p->lock);
|
||||
AST_LIST_UNLOCK(&agents);
|
||||
|
||||
/* Synchronize channel ownership between call to agent and itself. */
|
||||
ast_mutex_lock(&p->app_lock);
|
||||
if (p->app_lock_flag == 1) {
|
||||
ast_cond_wait(&p->app_complete_cond, &p->app_lock);
|
||||
}
|
||||
ast_mutex_unlock(&p->app_lock);
|
||||
ast_mutex_lock(&p->lock);
|
||||
if (p->app_lock_flag == 1) {
|
||||
ast_cond_signal(&p->login_wait_cond);
|
||||
ast_cond_wait(&p->app_complete_cond, &p->lock);
|
||||
}
|
||||
ast_mutex_unlock(&p->lock);
|
||||
if (p->ackcall) {
|
||||
res = agent_ack_sleep(p);
|
||||
|
@ -2094,12 +2110,20 @@ static int login_exec(struct ast_channel *chan, const char *data)
|
|||
sched_yield();
|
||||
}
|
||||
ast_mutex_lock(&p->lock);
|
||||
if (res && p->owner)
|
||||
ast_log(LOG_WARNING, "Huh? We broke out when there was still an owner?\n");
|
||||
/* Log us off if appropriate */
|
||||
if (p->chan == chan) {
|
||||
p->chan = NULL;
|
||||
}
|
||||
|
||||
/* Synchronize channel ownership between call to agent and itself. */
|
||||
if (p->app_lock_flag == 1) {
|
||||
ast_cond_signal(&p->login_wait_cond);
|
||||
ast_cond_wait(&p->app_complete_cond, &p->lock);
|
||||
}
|
||||
|
||||
if (res && p->owner)
|
||||
ast_log(LOG_WARNING, "Huh? We broke out when there was still an owner?\n");
|
||||
|
||||
p->acknowledged = 0;
|
||||
logintime = time(NULL) - p->loginstart;
|
||||
p->loginstart = 0;
|
||||
|
@ -2115,8 +2139,8 @@ static int login_exec(struct ast_channel *chan, const char *data)
|
|||
ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
|
||||
if (p->dead && !p->owner) {
|
||||
ast_mutex_destroy(&p->lock);
|
||||
ast_mutex_destroy(&p->app_lock);
|
||||
ast_cond_destroy(&p->app_complete_cond);
|
||||
ast_cond_destroy(&p->login_wait_cond);
|
||||
ast_free(p);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,13 +57,14 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
|||
#include "asterisk/musiconhold.h"
|
||||
#include "asterisk/poll-compat.h"
|
||||
|
||||
/*! Global jitterbuffer configuration - by default, jb is disabled */
|
||||
/*! Global jitterbuffer configuration - by default, jb is disabled
|
||||
* \note Values shown here match the defaults shown in alsa.conf.sample */
|
||||
static struct ast_jb_conf default_jbconf = {
|
||||
.flags = 0,
|
||||
.max_size = -1,
|
||||
.resync_threshold = -1,
|
||||
.impl = "",
|
||||
.target_extra = -1,
|
||||
.max_size = 200,
|
||||
.resync_threshold = 1000,
|
||||
.impl = "fixed",
|
||||
.target_extra = 40,
|
||||
};
|
||||
static struct ast_jb_conf global_jbconf;
|
||||
|
||||
|
@ -382,7 +383,6 @@ static int alsa_write(struct ast_channel *chan, struct ast_frame *f)
|
|||
static char sizbuf[8000];
|
||||
static int sizpos = 0;
|
||||
int len = sizpos;
|
||||
int pos;
|
||||
int res = 0;
|
||||
/* size_t frames = 0; */
|
||||
snd_pcm_state_t state;
|
||||
|
@ -396,7 +396,6 @@ static int alsa_write(struct ast_channel *chan, struct ast_frame *f)
|
|||
} else {
|
||||
memcpy(sizbuf + sizpos, f->data.ptr, f->datalen);
|
||||
len += f->datalen;
|
||||
pos = 0;
|
||||
state = snd_pcm_state(alsa.ocard);
|
||||
if (state == SND_PCM_STATE_XRUN)
|
||||
snd_pcm_prepare(alsa.ocard);
|
||||
|
|
|
@ -172,13 +172,14 @@ AST_RWLOCK_DEFINE_STATIC(active_lock);
|
|||
* \brief Global jitterbuffer configuration
|
||||
*
|
||||
* \note Disabled by default.
|
||||
* \note Values shown here match the defaults shown in console.conf.sample
|
||||
*/
|
||||
static struct ast_jb_conf default_jbconf = {
|
||||
.flags = 0,
|
||||
.max_size = -1,
|
||||
.resync_threshold = -1,
|
||||
.impl = "",
|
||||
.target_extra = -1,
|
||||
.max_size = 200,
|
||||
.resync_threshold = 1000,
|
||||
.impl = "fixed",
|
||||
.target_extra = 40,
|
||||
};
|
||||
static struct ast_jb_conf global_jbconf;
|
||||
|
||||
|
@ -725,7 +726,7 @@ static char *cli_console_autoanswer(struct ast_cli_entry *e, int cmd,
|
|||
|
||||
unref_pvt(pvt);
|
||||
|
||||
return CLI_SUCCESS;
|
||||
return res;
|
||||
}
|
||||
|
||||
static char *cli_console_flash(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
|
||||
|
|
|
@ -235,7 +235,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
|||
</synopsis>
|
||||
<syntax>
|
||||
<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
|
||||
<parameter name="DAHDIChannel" required="true" />
|
||||
<parameter name="DAHDIChannel">
|
||||
<para>Specify the specific channel to show. Show all channels if zero or not present.</para>
|
||||
</parameter>
|
||||
</syntax>
|
||||
<description>
|
||||
</description>
|
||||
|
@ -250,6 +252,19 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
|||
<description>
|
||||
</description>
|
||||
</manager>
|
||||
<manager name="PRIShowSpans" language="en_US">
|
||||
<synopsis>
|
||||
Show status of PRI spans.
|
||||
</synopsis>
|
||||
<syntax>
|
||||
<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
|
||||
<parameter name="Span">
|
||||
<para>Specify the specific span to show. Show all spans if zero or not present.</para>
|
||||
</parameter>
|
||||
</syntax>
|
||||
<description>
|
||||
</description>
|
||||
</manager>
|
||||
***/
|
||||
|
||||
#define SMDI_MD_WAIT_TIMEOUT 1500 /* 1.5 seconds */
|
||||
|
@ -265,14 +280,15 @@ static const char * const lbostr[] = {
|
|||
"-22.5db (CSU)"
|
||||
};
|
||||
|
||||
/*! Global jitterbuffer configuration - by default, jb is disabled */
|
||||
/*! Global jitterbuffer configuration - by default, jb is disabled
|
||||
* \note Values shown here match the defaults shown in chan_dahdi.conf.sample */
|
||||
static struct ast_jb_conf default_jbconf =
|
||||
{
|
||||
.flags = 0,
|
||||
.max_size = -1,
|
||||
.resync_threshold = -1,
|
||||
.impl = "",
|
||||
.target_extra = -1,
|
||||
.max_size = 200,
|
||||
.resync_threshold = 1000,
|
||||
.impl = "fixed",
|
||||
.target_extra = 40,
|
||||
};
|
||||
static struct ast_jb_conf global_jbconf;
|
||||
|
||||
|
@ -979,6 +995,11 @@ struct dahdi_pvt {
|
|||
* \note The "context" string read in from chan_dahdi.conf
|
||||
*/
|
||||
char context[AST_MAX_CONTEXT];
|
||||
/*!
|
||||
* \brief A description for the channel configuration
|
||||
* \note The "description" string read in from chan_dahdi.conf
|
||||
*/
|
||||
char description[32];
|
||||
/*!
|
||||
* \brief Saved context string.
|
||||
*/
|
||||
|
@ -1276,6 +1297,7 @@ struct dahdi_pvt {
|
|||
MEMBER(dahdi_pvt, use_smdi, AST_DATA_BOOLEAN) \
|
||||
MEMBER(dahdi_pvt, context, AST_DATA_STRING) \
|
||||
MEMBER(dahdi_pvt, defcontext, AST_DATA_STRING) \
|
||||
MEMBER(dahdi_pvt, description, AST_DATA_STRING) \
|
||||
MEMBER(dahdi_pvt, exten, AST_DATA_STRING) \
|
||||
MEMBER(dahdi_pvt, language, AST_DATA_STRING) \
|
||||
MEMBER(dahdi_pvt, mohinterpret, AST_DATA_STRING) \
|
||||
|
@ -2937,18 +2959,21 @@ static int my_dial_digits(void *pvt, enum analog_sub sub, struct analog_dialoper
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (sub != ANALOG_SUB_REAL)
|
||||
printf("Trying to dial digits on sub %d\n", sub);
|
||||
if (sub != ANALOG_SUB_REAL) {
|
||||
ast_log(LOG_ERROR, "Trying to dial_digits '%s' on channel %d subchannel %d\n",
|
||||
dop->dialstr, p->channel, sub);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ddop.op = DAHDI_DIAL_OP_REPLACE;
|
||||
strncpy(ddop.dialstr, dop->dialstr, sizeof(ddop.dialstr));
|
||||
ast_copy_string(ddop.dialstr, dop->dialstr, sizeof(ddop.dialstr));
|
||||
|
||||
printf("Dialing %s on %d\n", ddop.dialstr, p->channel);
|
||||
ast_debug(1, "Channel %d: Sending '%s' to DAHDI_DIAL.\n", p->channel, ddop.dialstr);
|
||||
|
||||
res = ioctl(p->subs[index].dfd, DAHDI_DIAL, &ddop);
|
||||
|
||||
if (res == -1)
|
||||
if (res == -1) {
|
||||
ast_debug(1, "DAHDI_DIAL ioctl failed on %s: %s\n", p->owner->name, strerror(errno));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
@ -6111,46 +6136,73 @@ static int dahdi_hangup(struct ast_channel *ast)
|
|||
p->cid_subaddr[0] = '\0';
|
||||
}
|
||||
|
||||
#ifdef HAVE_PRI
|
||||
#if defined(HAVE_PRI)
|
||||
if (dahdi_sig_pri_lib_handles(p->sig)) {
|
||||
x = 1;
|
||||
ast_channel_setoption(ast,AST_OPTION_AUDIO_MODE,&x,sizeof(char),0);
|
||||
dahdi_confmute(p, 0);
|
||||
p->muting = 0;
|
||||
restore_gains(p);
|
||||
if (p->dsp) {
|
||||
ast_dsp_free(p->dsp);
|
||||
p->dsp = NULL;
|
||||
}
|
||||
p->ignoredtmf = 0;
|
||||
revert_fax_buffers(p, ast);
|
||||
dahdi_setlinear(p->subs[SUB_REAL].dfd, 0);
|
||||
p->law = p->law_default;
|
||||
law = p->law_default;
|
||||
res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETLAW, &law);
|
||||
dahdi_disable_ec(p);
|
||||
update_conf(p);
|
||||
reset_conf(p);
|
||||
sig_pri_hangup(p->sig_pvt, ast);
|
||||
p->subs[SUB_REAL].owner = NULL;
|
||||
p->subs[SUB_REAL].needbusy = 0;
|
||||
p->owner = NULL;
|
||||
p->cid_tag[0] = '\0';
|
||||
p->ringt = 0;/* Probably not used in this mode. Reset anyway. */
|
||||
p->distinctivering = 0;/* Probably not used in this mode. Reset anyway. */
|
||||
p->confirmanswer = 0;/* Probably not used in this mode. Reset anyway. */
|
||||
p->outgoing = 0;
|
||||
p->digital = 0;
|
||||
p->faxhandled = 0;
|
||||
p->pulsedial = 0;/* Probably not used in this mode. Reset anyway. */
|
||||
goto hangup_out;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_SS7)
|
||||
if (p->sig == SIG_SS7) {
|
||||
x = 1;
|
||||
ast_channel_setoption(ast,AST_OPTION_AUDIO_MODE,&x,sizeof(char),0);
|
||||
ast_channel_setoption(ast, AST_OPTION_AUDIO_MODE, &x, sizeof(char), 0);
|
||||
|
||||
dahdi_confmute(p, 0);
|
||||
p->muting = 0;
|
||||
restore_gains(p);
|
||||
if (p->dsp) {
|
||||
ast_dsp_free(p->dsp);
|
||||
p->dsp = NULL;
|
||||
}
|
||||
p->ignoredtmf = 0;
|
||||
|
||||
/* Real channel, do some fixup */
|
||||
p->subs[SUB_REAL].owner = NULL;
|
||||
p->subs[SUB_REAL].needbusy = 0;
|
||||
dahdi_setlinear(p->subs[SUB_REAL].dfd, 0);
|
||||
|
||||
p->owner = NULL;
|
||||
p->cid_tag[0] = '\0';
|
||||
p->ringt = 0;/* Probably not used in this mode. Reset anyway. */
|
||||
p->distinctivering = 0;/* Probably not used in this mode. Reset anyway. */
|
||||
p->confirmanswer = 0;/* Probably not used in this mode. Reset anyway. */
|
||||
p->outgoing = 0;
|
||||
p->digital = 0;
|
||||
p->faxhandled = 0;
|
||||
p->pulsedial = 0;/* Probably not used in this mode. Reset anyway. */
|
||||
|
||||
revert_fax_buffers(p, ast);
|
||||
|
||||
p->law = p->law_default;
|
||||
law = p->law_default;
|
||||
res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETLAW, &law);
|
||||
if (res < 0) {
|
||||
ast_log(LOG_WARNING, "Unable to set law on channel %d to default: %s\n",
|
||||
p->channel, strerror(errno));
|
||||
}
|
||||
|
||||
sig_pri_hangup(p->sig_pvt, ast);
|
||||
|
||||
tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
|
||||
dahdi_disable_ec(p);
|
||||
|
||||
x = 0;
|
||||
ast_channel_setoption(ast, AST_OPTION_TDD, &x, sizeof(char), 0);
|
||||
p->didtdd = 0;/* Probably not used in this mode. Reset anyway. */
|
||||
|
||||
p->rdnis[0] = '\0';
|
||||
update_conf(p);
|
||||
reset_conf(p);
|
||||
|
||||
/* Restore data mode */
|
||||
x = 0;
|
||||
ast_channel_setoption(ast, AST_OPTION_AUDIO_MODE, &x, sizeof(char), 0);
|
||||
|
||||
if (num_restart_pending == 0) {
|
||||
restart_monitor();
|
||||
}
|
||||
goto hangup_out;
|
||||
}
|
||||
#endif /* defined(HAVE_PRI) */
|
||||
|
||||
#if defined(HAVE_SS7)
|
||||
if (p->sig == SIG_SS7) {
|
||||
x = 1;
|
||||
ast_channel_setoption(ast, AST_OPTION_AUDIO_MODE, &x, sizeof(char), 0);
|
||||
|
||||
dahdi_confmute(p, 0);
|
||||
p->muting = 0;
|
||||
|
@ -6164,7 +6216,6 @@ static int dahdi_hangup(struct ast_channel *ast)
|
|||
/* Real channel, do some fixup */
|
||||
p->subs[SUB_REAL].owner = NULL;
|
||||
p->subs[SUB_REAL].needbusy = 0;
|
||||
p->polarity = POLARITY_IDLE;
|
||||
dahdi_setlinear(p->subs[SUB_REAL].dfd, 0);
|
||||
|
||||
p->owner = NULL;
|
||||
|
@ -6181,28 +6232,30 @@ static int dahdi_hangup(struct ast_channel *ast)
|
|||
p->law = p->law_default;
|
||||
law = p->law_default;
|
||||
res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETLAW, &law);
|
||||
if (res < 0)
|
||||
ast_log(LOG_WARNING, "Unable to set law on channel %d to default: %s\n", p->channel, strerror(errno));
|
||||
if (res < 0) {
|
||||
ast_log(LOG_WARNING, "Unable to set law on channel %d to default: %s\n",
|
||||
p->channel, strerror(errno));
|
||||
}
|
||||
|
||||
sig_ss7_hangup(p->sig_pvt, ast);
|
||||
|
||||
tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
|
||||
dahdi_disable_ec(p);
|
||||
|
||||
x = 0;
|
||||
ast_channel_setoption(ast,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0);
|
||||
ast_channel_setoption(ast,AST_OPTION_TDD,&x,sizeof(char),0);
|
||||
ast_channel_setoption(ast, AST_OPTION_TDD, &x, sizeof(char), 0);
|
||||
p->didtdd = 0;/* Probably not used in this mode. Reset anyway. */
|
||||
|
||||
update_conf(p);
|
||||
reset_conf(p);
|
||||
|
||||
/* Restore data mode */
|
||||
x = 0;
|
||||
ast_channel_setoption(ast,AST_OPTION_AUDIO_MODE,&x,sizeof(char),0);
|
||||
ast_channel_setoption(ast, AST_OPTION_AUDIO_MODE, &x, sizeof(char), 0);
|
||||
|
||||
if (num_restart_pending == 0)
|
||||
if (num_restart_pending == 0) {
|
||||
restart_monitor();
|
||||
|
||||
ast->tech_pvt = NULL;
|
||||
}
|
||||
goto hangup_out;
|
||||
}
|
||||
#endif /* defined(HAVE_SS7) */
|
||||
|
@ -6416,6 +6469,7 @@ static int dahdi_hangup(struct ast_channel *ast)
|
|||
break;
|
||||
default:
|
||||
tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
|
||||
break;
|
||||
}
|
||||
if (p->sig)
|
||||
dahdi_disable_ec(p);
|
||||
|
@ -6449,8 +6503,8 @@ static int dahdi_hangup(struct ast_channel *ast)
|
|||
p->cidcwexpire = 0;
|
||||
p->cid_suppress_expire = 0;
|
||||
p->oprmode = 0;
|
||||
ast->tech_pvt = NULL;
|
||||
hangup_out:
|
||||
ast->tech_pvt = NULL;
|
||||
ast_free(p->cidspill);
|
||||
p->cidspill = NULL;
|
||||
|
||||
|
@ -9986,7 +10040,10 @@ static void *analog_ss_thread(void *data)
|
|||
/* some switches require a minimum guard time between
|
||||
the last FGD wink and something that answers
|
||||
immediately. This ensures it */
|
||||
if (ast_safe_sleep(chan,100)) goto quit;
|
||||
if (ast_safe_sleep(chan, 100)) {
|
||||
ast_hangup(chan);
|
||||
goto quit;
|
||||
}
|
||||
}
|
||||
dahdi_enable_ec(p);
|
||||
if (NEED_MFDETECT(p)) {
|
||||
|
@ -12135,6 +12192,12 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
|
|||
if (tmp) {
|
||||
int chan_sig = conf->chan.sig;
|
||||
|
||||
/* If there are variables in tmp before it is updated to match the new config, clear them */
|
||||
if (reloading && tmp->vars) {
|
||||
ast_variables_destroy(tmp->vars);
|
||||
tmp->vars = NULL;
|
||||
}
|
||||
|
||||
if (!here) {
|
||||
/* Can only get here if this is a new channel interface being created. */
|
||||
if ((channel != CHAN_PSEUDO)) {
|
||||
|
@ -12439,6 +12502,9 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
|
|||
ast_copy_string(pris[span].pri.mwi_mailboxes,
|
||||
conf->pri.pri.mwi_mailboxes,
|
||||
sizeof(pris[span].pri.mwi_mailboxes));
|
||||
ast_copy_string(pris[span].pri.mwi_vm_numbers,
|
||||
conf->pri.pri.mwi_vm_numbers,
|
||||
sizeof(pris[span].pri.mwi_vm_numbers));
|
||||
#endif /* defined(HAVE_PRI_MWI) */
|
||||
ast_copy_string(pris[span].pri.idledial, conf->pri.pri.idledial, sizeof(pris[span].pri.idledial));
|
||||
ast_copy_string(pris[span].pri.idleext, conf->pri.pri.idleext, sizeof(pris[span].pri.idleext));
|
||||
|
@ -12456,6 +12522,9 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
|
|||
#if defined(HAVE_PRI_MCID)
|
||||
pris[span].pri.mcid_send = conf->pri.pri.mcid_send;
|
||||
#endif /* defined(HAVE_PRI_MCID) */
|
||||
#if defined(HAVE_PRI_DATETIME_SEND)
|
||||
pris[span].pri.datetime_send = conf->pri.pri.datetime_send;
|
||||
#endif /* defined(HAVE_PRI_DATETIME_SEND) */
|
||||
|
||||
for (x = 0; x < PRI_MAX_TIMERS; x++) {
|
||||
pris[span].pri.pritimers[x] = conf->pri.pri.pritimers[x];
|
||||
|
@ -12673,6 +12742,7 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
|
|||
ast_copy_string(tmp->mohinterpret, conf->chan.mohinterpret, sizeof(tmp->mohinterpret));
|
||||
ast_copy_string(tmp->mohsuggest, conf->chan.mohsuggest, sizeof(tmp->mohsuggest));
|
||||
ast_copy_string(tmp->context, conf->chan.context, sizeof(tmp->context));
|
||||
ast_copy_string(tmp->description, conf->chan.description, sizeof(tmp->description));
|
||||
ast_copy_string(tmp->parkinglot, conf->chan.parkinglot, sizeof(tmp->parkinglot));
|
||||
tmp->cid_ton = 0;
|
||||
if (analog_lib_handles(tmp->sig, tmp->radio, tmp->oprmode)) {
|
||||
|
@ -13476,6 +13546,7 @@ static struct ast_channel *dahdi_request(const char *type, struct ast_format_cap
|
|||
}
|
||||
}
|
||||
|
||||
p->distinctivering = 0;
|
||||
/* Make special notes */
|
||||
switch (start.opt) {
|
||||
case '\0':
|
||||
|
@ -14986,8 +15057,8 @@ static int action_dahdirestart(struct mansession *s, const struct message *m)
|
|||
|
||||
static char *dahdi_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
|
||||
{
|
||||
#define FORMAT "%7s %-10.10s %-15.15s %-10.10s %-20.20s %-10.10s %-10.10s\n"
|
||||
#define FORMAT2 "%7s %-10.10s %-15.15s %-10.10s %-20.20s %-10.10s %-10.10s\n"
|
||||
#define FORMAT "%7s %-10.10s %-15.15s %-10.10s %-20.20s %-10.10s %-10.10s %-32.32s\n"
|
||||
#define FORMAT2 "%7s %-10.10s %-15.15s %-10.10s %-20.20s %-10.10s %-10.10s %-32.32s\n"
|
||||
unsigned int targetnum = 0;
|
||||
int filtertype = 0;
|
||||
struct dahdi_pvt *tmp = NULL;
|
||||
|
@ -15024,7 +15095,7 @@ static char *dahdi_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cl
|
|||
}
|
||||
}
|
||||
|
||||
ast_cli(a->fd, FORMAT2, "Chan", "Extension", "Context", "Language", "MOH Interpret", "Blocked", "State");
|
||||
ast_cli(a->fd, FORMAT2, "Chan", "Extension", "Context", "Language", "MOH Interpret", "Blocked", "State", "Description");
|
||||
ast_mutex_lock(&iflock);
|
||||
for (tmp = iflist; tmp; tmp = tmp->next) {
|
||||
if (filtertype) {
|
||||
|
@ -15062,7 +15133,7 @@ static char *dahdi_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cl
|
|||
|
||||
snprintf(statestr, sizeof(statestr), "%s", "In Service");
|
||||
|
||||
ast_cli(a->fd, FORMAT, tmps, tmp->exten, tmp->context, tmp->language, tmp->mohinterpret, blockstr, statestr);
|
||||
ast_cli(a->fd, FORMAT, tmps, tmp->exten, tmp->context, tmp->language, tmp->mohinterpret, blockstr, statestr, tmp->description);
|
||||
}
|
||||
ast_mutex_unlock(&iflock);
|
||||
return CLI_SUCCESS;
|
||||
|
@ -15098,6 +15169,7 @@ static char *dahdi_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli
|
|||
for (tmp = iflist; tmp; tmp = tmp->next) {
|
||||
if (tmp->channel == channel) {
|
||||
ast_cli(a->fd, "Channel: %d\n", tmp->channel);
|
||||
ast_cli(a->fd, "Description: %s\n", tmp->description);
|
||||
ast_cli(a->fd, "File Descriptor: %d\n", tmp->subs[SUB_REAL].dfd);
|
||||
ast_cli(a->fd, "Span: %d\n", tmp->span);
|
||||
ast_cli(a->fd, "Extension: %s\n", tmp->exten);
|
||||
|
@ -15803,6 +15875,7 @@ static int action_dahdishowchannels(struct mansession *s, const struct message *
|
|||
"Context: %s\r\n"
|
||||
"DND: %s\r\n"
|
||||
"Alarm: %s\r\n"
|
||||
"Description: %s\r\n"
|
||||
"%s"
|
||||
"\r\n",
|
||||
tmp->channel,
|
||||
|
@ -15813,7 +15886,8 @@ static int action_dahdishowchannels(struct mansession *s, const struct message *
|
|||
tmp->sig,
|
||||
tmp->context,
|
||||
dahdi_dnd(tmp, -1) ? "Enabled" : "Disabled",
|
||||
alarm2str(alm), idText);
|
||||
alarm2str(alm),
|
||||
tmp->description, idText);
|
||||
} else {
|
||||
astman_append(s,
|
||||
"Event: DAHDIShowChannels\r\n"
|
||||
|
@ -15823,12 +15897,14 @@ static int action_dahdishowchannels(struct mansession *s, const struct message *
|
|||
"Context: %s\r\n"
|
||||
"DND: %s\r\n"
|
||||
"Alarm: %s\r\n"
|
||||
"Description: %s\r\n"
|
||||
"%s"
|
||||
"\r\n",
|
||||
tmp->channel, sig2str(tmp->sig), tmp->sig,
|
||||
tmp->context,
|
||||
dahdi_dnd(tmp, -1) ? "Enabled" : "Disabled",
|
||||
alarm2str(alm), idText);
|
||||
alarm2str(alm),
|
||||
tmp->description, idText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15845,6 +15921,60 @@ static int action_dahdishowchannels(struct mansession *s, const struct message *
|
|||
return 0;
|
||||
}
|
||||
|
||||
#if defined(HAVE_PRI)
|
||||
static int action_prishowspans(struct mansession *s, const struct message *m)
|
||||
{
|
||||
int count;
|
||||
int idx;
|
||||
int span_query;
|
||||
struct dahdi_pri *dspan;
|
||||
const char *id = astman_get_header(m, "ActionID");
|
||||
const char *span_str = astman_get_header(m, "Span");
|
||||
char action_id[256];
|
||||
const char *show_cmd = "PRIShowSpans";
|
||||
|
||||
/* NOTE: Asking for span 0 gets all spans. */
|
||||
if (!ast_strlen_zero(span_str)) {
|
||||
span_query = atoi(span_str);
|
||||
} else {
|
||||
span_query = 0;
|
||||
}
|
||||
|
||||
if (!ast_strlen_zero(id)) {
|
||||
snprintf(action_id, sizeof(action_id), "ActionID: %s\r\n", id);
|
||||
} else {
|
||||
action_id[0] = '\0';
|
||||
}
|
||||
|
||||
astman_send_ack(s, m, "Span status will follow");
|
||||
|
||||
count = 0;
|
||||
for (idx = 0; idx < ARRAY_LEN(pris); ++idx) {
|
||||
dspan = &pris[idx];
|
||||
|
||||
/* If a specific span is asked for, only deliver status for that span. */
|
||||
if (0 < span_query && dspan->pri.span != span_query) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dspan->pri.pri) {
|
||||
count += sig_pri_ami_show_spans(s, show_cmd, &dspan->pri, dspan->dchannels,
|
||||
action_id);
|
||||
}
|
||||
}
|
||||
|
||||
astman_append(s,
|
||||
"Event: %sComplete\r\n"
|
||||
"Items: %d\r\n"
|
||||
"%s"
|
||||
"\r\n",
|
||||
show_cmd,
|
||||
count,
|
||||
action_id);
|
||||
return 0;
|
||||
}
|
||||
#endif /* defined(HAVE_PRI) */
|
||||
|
||||
#if defined(HAVE_SS7)
|
||||
static int linkset_addsigchan(int sigchan)
|
||||
{
|
||||
|
@ -16420,6 +16550,9 @@ static int __unload_module(void)
|
|||
ast_manager_unregister("DAHDIDNDon");
|
||||
ast_manager_unregister("DAHDIShowChannels");
|
||||
ast_manager_unregister("DAHDIRestart");
|
||||
#if defined(HAVE_PRI)
|
||||
ast_manager_unregister("PRIShowSpans");
|
||||
#endif /* defined(HAVE_PRI) */
|
||||
ast_data_unregister(NULL);
|
||||
ast_channel_unregister(&dahdi_tech);
|
||||
|
||||
|
@ -16683,6 +16816,40 @@ static unsigned long dahdi_display_text_option(const char *value)
|
|||
#endif /* defined(HAVE_PRI_DISPLAY_TEXT) */
|
||||
#endif /* defined(HAVE_PRI) */
|
||||
|
||||
#if defined(HAVE_PRI)
|
||||
#if defined(HAVE_PRI_DATETIME_SEND)
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Determine the configured date/time send policy option.
|
||||
* \since 1.10
|
||||
*
|
||||
* \param value Configuration value string.
|
||||
*
|
||||
* \return Configured date/time send policy option.
|
||||
*/
|
||||
static int dahdi_datetime_send_option(const char *value)
|
||||
{
|
||||
int option;
|
||||
|
||||
option = PRI_DATE_TIME_SEND_DEFAULT;
|
||||
|
||||
if (ast_false(value)) {
|
||||
option = PRI_DATE_TIME_SEND_NO;
|
||||
} else if (!strcasecmp(value, "date")) {
|
||||
option = PRI_DATE_TIME_SEND_DATE;
|
||||
} else if (!strcasecmp(value, "date_hh")) {
|
||||
option = PRI_DATE_TIME_SEND_DATE_HH;
|
||||
} else if (!strcasecmp(value, "date_hhmm")) {
|
||||
option = PRI_DATE_TIME_SEND_DATE_HHMM;
|
||||
} else if (!strcasecmp(value, "date_hhmmss")) {
|
||||
option = PRI_DATE_TIME_SEND_DATE_HHMMSS;
|
||||
}
|
||||
|
||||
return option;
|
||||
}
|
||||
#endif /* defined(HAVE_PRI_DATETIME_SEND) */
|
||||
#endif /* defined(HAVE_PRI) */
|
||||
|
||||
/*! process_dahdi() - ignore keyword 'channel' and similar */
|
||||
#define PROC_DAHDI_OPT_NOCHAN (1 << 0)
|
||||
/*! process_dahdi() - No warnings on non-existing cofiguration keywords */
|
||||
|
@ -16827,6 +16994,8 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
|
|||
confp->chan.dtmfrelax = 0;
|
||||
} else if (!strcasecmp(v->name, "mailbox")) {
|
||||
ast_copy_string(confp->chan.mailbox, v->value, sizeof(confp->chan.mailbox));
|
||||
} else if (!strcasecmp(v->name, "description")) {
|
||||
ast_copy_string(confp->chan.description, v->value, sizeof(confp->chan.description));
|
||||
} else if (!strcasecmp(v->name, "hasvoicemail")) {
|
||||
if (ast_true(v->value) && ast_strlen_zero(confp->chan.mailbox)) {
|
||||
ast_copy_string(confp->chan.mailbox, cat, sizeof(confp->chan.mailbox));
|
||||
|
@ -17485,6 +17654,9 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
|
|||
} else if (!strcasecmp(v->name, "mwi_mailboxes")) {
|
||||
ast_copy_string(confp->pri.pri.mwi_mailboxes, v->value,
|
||||
sizeof(confp->pri.pri.mwi_mailboxes));
|
||||
} else if (!strcasecmp(v->name, "mwi_vm_numbers")) {
|
||||
ast_copy_string(confp->pri.pri.mwi_vm_numbers, v->value,
|
||||
sizeof(confp->pri.pri.mwi_vm_numbers));
|
||||
#endif /* defined(HAVE_PRI_MWI) */
|
||||
} else if (!strcasecmp(v->name, "append_msn_to_cid_tag")) {
|
||||
confp->pri.pri.append_msn_to_user_tag = ast_true(v->value);
|
||||
|
@ -17498,6 +17670,10 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
|
|||
} else if (!strcasecmp(v->name, "mcid_send")) {
|
||||
confp->pri.pri.mcid_send = ast_true(v->value);
|
||||
#endif /* defined(HAVE_PRI_MCID) */
|
||||
#if defined(HAVE_PRI_DATETIME_SEND)
|
||||
} else if (!strcasecmp(v->name, "datetime_send")) {
|
||||
confp->pri.pri.datetime_send = dahdi_datetime_send_option(v->value);
|
||||
#endif /* defined(HAVE_PRI_DATETIME_SEND) */
|
||||
#endif /* HAVE_PRI */
|
||||
#if defined(HAVE_SS7)
|
||||
} else if (!strcasecmp(v->name, "ss7type")) {
|
||||
|
@ -17814,6 +17990,13 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
|
|||
} else if (!(options & PROC_DAHDI_OPT_NOWARN) )
|
||||
ast_log(LOG_WARNING, "Ignoring any changes to '%s' (on reload) at line %d.\n", v->name, v->lineno);
|
||||
}
|
||||
|
||||
/* Since confp has already filled invidual dahdi_pvt objects with channels at this point, clear the variables in confp's pvt. */
|
||||
if (confp->chan.vars) {
|
||||
ast_variables_destroy(confp->chan.vars);
|
||||
confp->chan.vars = NULL;
|
||||
}
|
||||
|
||||
if (dahdichan[0]) {
|
||||
/* The user has set 'dahdichan' */
|
||||
/*< \todo pass proper line number instead of 0 */
|
||||
|
@ -18390,6 +18573,9 @@ static int load_module(void)
|
|||
ast_manager_register_xml("DAHDIDNDoff", 0, action_dahdidndoff);
|
||||
ast_manager_register_xml("DAHDIShowChannels", 0, action_dahdishowchannels);
|
||||
ast_manager_register_xml("DAHDIRestart", 0, action_dahdirestart);
|
||||
#if defined(HAVE_PRI)
|
||||
ast_manager_register_xml("PRIShowSpans", 0, action_prishowspans);
|
||||
#endif /* defined(HAVE_PRI) */
|
||||
|
||||
ast_cond_init(&ss_thread_complete, NULL);
|
||||
|
||||
|
|
|
@ -114,14 +114,15 @@ onhold_cb on_hold;
|
|||
|
||||
int h323debug; /*!< global debug flag */
|
||||
|
||||
/*! \brief Global jitterbuffer configuration - by default, jb is disabled */
|
||||
/*! \brief Global jitterbuffer configuration - by default, jb is disabled
|
||||
* \note Values shown here match the defaults shown in h323.conf.sample */
|
||||
static struct ast_jb_conf default_jbconf =
|
||||
{
|
||||
.flags = 0,
|
||||
.max_size = -1,
|
||||
.resync_threshold = -1,
|
||||
.impl = "",
|
||||
.target_extra = -1,
|
||||
.max_size = 200,
|
||||
.resync_threshold = 1000,
|
||||
.impl = "fixed",
|
||||
.target_extra = 40,
|
||||
};
|
||||
static struct ast_jb_conf global_jbconf;
|
||||
|
||||
|
|
|
@ -484,6 +484,7 @@ struct iax2_peer {
|
|||
AST_DECLARE_STRING_FIELDS(
|
||||
AST_STRING_FIELD(name);
|
||||
AST_STRING_FIELD(username);
|
||||
AST_STRING_FIELD(description); /*!< Description of the peer */
|
||||
AST_STRING_FIELD(secret);
|
||||
AST_STRING_FIELD(dbsecret);
|
||||
AST_STRING_FIELD(outkey); /*!< What key we use to talk to this peer */
|
||||
|
@ -1281,10 +1282,7 @@ static void network_change_event_subscribe(void)
|
|||
{
|
||||
if (!network_change_event_subscription) {
|
||||
network_change_event_subscription = ast_event_subscribe(AST_EVENT_NETWORK_CHANGE,
|
||||
network_change_event_cb,
|
||||
"SIP Network Change ",
|
||||
NULL,
|
||||
AST_EVENT_IE_END);
|
||||
network_change_event_cb, "IAX2 Network Change", NULL, AST_EVENT_IE_END);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3837,6 +3835,7 @@ static char *handle_cli_iax2_show_peer(struct ast_cli_entry *e, int cmd, struct
|
|||
encmethods_to_str(peer->encmethods, encmethods);
|
||||
ast_cli(a->fd, "\n\n");
|
||||
ast_cli(a->fd, " * Name : %s\n", peer->name);
|
||||
ast_cli(a->fd, " Description : %s\n", peer->description);
|
||||
ast_cli(a->fd, " Secret : %s\n", ast_strlen_zero(peer->secret) ? "<Not set>" : "<Set>");
|
||||
ast_cli(a->fd, " Context : %s\n", peer->context);
|
||||
ast_cli(a->fd, " Parking lot : %s\n", peer->parkinglot);
|
||||
|
@ -4636,7 +4635,9 @@ static int create_addr(const char *peername, struct ast_channel *c, struct socka
|
|||
return -1;
|
||||
}
|
||||
ast_sockaddr_to_sin(&sin_tmp, sin);
|
||||
sin->sin_port = htons(IAX_DEFAULT_PORTNO);
|
||||
if (sin->sin_port == 0) {
|
||||
sin->sin_port = htons(IAX_DEFAULT_PORTNO);
|
||||
}
|
||||
/* use global iax prefs for unknown peer/user */
|
||||
/* But move the calling channel's native codec to the top of the preference list */
|
||||
memcpy(&ourprefs, &prefs, sizeof(ourprefs));
|
||||
|
@ -5432,7 +5433,7 @@ static int iax2_queryoption(struct ast_channel *c, int option, void *data, int *
|
|||
|
||||
static struct ast_frame *iax2_read(struct ast_channel *c)
|
||||
{
|
||||
ast_log(LOG_NOTICE, "I should never be called!\n");
|
||||
ast_debug(1, "I should never be called!\n");
|
||||
return &ast_null_frame;
|
||||
}
|
||||
|
||||
|
@ -6159,7 +6160,6 @@ static int iax2_trunk_queue(struct chan_iax2_pvt *pvt, struct iax_frame *fr)
|
|||
struct iax2_trunk_peer *tpeer;
|
||||
void *tmp, *ptr;
|
||||
struct timeval now;
|
||||
int res;
|
||||
struct ast_iax2_meta_trunk_entry *met;
|
||||
struct ast_iax2_meta_trunk_mini *mtm;
|
||||
|
||||
|
@ -6215,7 +6215,7 @@ static int iax2_trunk_queue(struct chan_iax2_pvt *pvt, struct iax_frame *fr)
|
|||
/* if we have enough for a full MTU, ship it now without waiting */
|
||||
if (global_max_trunk_mtu > 0 && tpeer->trunkdatalen + f->datalen + 4 >= global_max_trunk_mtu) {
|
||||
now = ast_tvnow();
|
||||
res = send_trunk(tpeer, &now);
|
||||
send_trunk(tpeer, &now);
|
||||
trunk_untimed ++;
|
||||
}
|
||||
|
||||
|
@ -6712,8 +6712,8 @@ static int __iax2_show_peers(int fd, int *total, struct mansession *s, const int
|
|||
int unmonitored_peers = 0;
|
||||
struct ao2_iterator i;
|
||||
|
||||
#define FORMAT2 "%-15.15s %-15.15s %s %-15.15s %-8s %s %-10s\n"
|
||||
#define FORMAT "%-15.15s %-15.15s %s %-15.15s %-5d%s %s %-10s\n"
|
||||
#define FORMAT2 "%-15.15s %-15.15s %s %-15.15s %-8s %s %-11s %-32.32s\n"
|
||||
#define FORMAT "%-15.15s %-15.15s %s %-15.15s %-5d%s %s %-11s %-32.32s\n"
|
||||
|
||||
struct iax2_peer *peer = NULL;
|
||||
char name[256];
|
||||
|
@ -6755,7 +6755,7 @@ static int __iax2_show_peers(int fd, int *total, struct mansession *s, const int
|
|||
|
||||
|
||||
if (!s)
|
||||
ast_cli(fd, FORMAT2, "Name/Username", "Host", " ", "Mask", "Port", " ", "Status");
|
||||
ast_cli(fd, FORMAT2, "Name/Username", "Host", " ", "Mask", "Port", " ", "Status", "Description");
|
||||
|
||||
i = ao2_iterator_init(peers, 0);
|
||||
for (peer = ao2_iterator_next(&i); peer;
|
||||
|
@ -6801,7 +6801,8 @@ static int __iax2_show_peers(int fd, int *total, struct mansession *s, const int
|
|||
"Dynamic: %s\r\n"
|
||||
"Trunk: %s\r\n"
|
||||
"Encryption: %s\r\n"
|
||||
"Status: %s\r\n\r\n",
|
||||
"Status: %s\r\n"
|
||||
"Description: %s\r\n\r\n",
|
||||
idtext,
|
||||
name,
|
||||
ast_sockaddr_stringify_addr(&peer->addr),
|
||||
|
@ -6809,7 +6810,8 @@ static int __iax2_show_peers(int fd, int *total, struct mansession *s, const int
|
|||
ast_test_flag64(peer, IAX_DYNAMIC) ? "yes" : "no",
|
||||
ast_test_flag64(peer, IAX_TRUNK) ? "yes" : "no",
|
||||
peer->encmethods ? ast_str_buffer(encmethods) : "no",
|
||||
status);
|
||||
status,
|
||||
peer->description);
|
||||
} else {
|
||||
ast_cli(fd, FORMAT, name,
|
||||
ast_sockaddr_stringify_addr(&peer->addr),
|
||||
|
@ -6818,7 +6820,8 @@ static int __iax2_show_peers(int fd, int *total, struct mansession *s, const int
|
|||
ast_sockaddr_port(&peer->addr),
|
||||
ast_test_flag64(peer, IAX_TRUNK) ? "(T)" : " ",
|
||||
peer->encmethods ? "(E)" : " ",
|
||||
status);
|
||||
status,
|
||||
peer->description);
|
||||
}
|
||||
total_peers++;
|
||||
}
|
||||
|
@ -9345,7 +9348,6 @@ static void *iax_park_thread(void *stuff)
|
|||
struct iax_dual *d;
|
||||
struct ast_frame *f;
|
||||
int ext;
|
||||
int res;
|
||||
d = stuff;
|
||||
chan1 = d->chan1;
|
||||
chan2 = d->chan2;
|
||||
|
@ -9353,7 +9355,7 @@ static void *iax_park_thread(void *stuff)
|
|||
f = ast_read(chan1);
|
||||
if (f)
|
||||
ast_frfree(f);
|
||||
res = ast_park_call(chan1, chan2, 0, d->parkexten, &ext);
|
||||
ast_park_call(chan1, chan2, 0, d->parkexten, &ext);
|
||||
ast_hangup(chan2);
|
||||
ast_log(LOG_NOTICE, "Parked on extension '%d'\n", ext);
|
||||
return NULL;
|
||||
|
@ -12459,6 +12461,8 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, st
|
|||
ast_string_field_set(peer, mohsuggest, v->value);
|
||||
} else if (!strcasecmp(v->name, "dbsecret")) {
|
||||
ast_string_field_set(peer, dbsecret, v->value);
|
||||
} else if (!strcasecmp(v->name, "description")) {
|
||||
ast_string_field_set(peer, description, v->value);
|
||||
} else if (!strcasecmp(v->name, "trunk")) {
|
||||
ast_set2_flag64(peer, ast_true(v->value), IAX_TRUNK);
|
||||
if (ast_test_flag64(peer, IAX_TRUNK) && !timer) {
|
||||
|
|
|
@ -587,7 +587,6 @@ static int jingle_create_candidates(struct jingle *client, struct jingle_pvt *p,
|
|||
struct ast_sockaddr sin_tmp;
|
||||
struct ast_sockaddr us_tmp;
|
||||
struct ast_sockaddr bindaddr_tmp;
|
||||
struct sockaddr_in dest;
|
||||
struct in_addr us;
|
||||
struct in_addr externaddr;
|
||||
iks *iq, *jingle, *content, *transport, *candidate;
|
||||
|
@ -668,9 +667,6 @@ static int jingle_create_candidates(struct jingle *client, struct jingle_pvt *p,
|
|||
ours2 = NULL;
|
||||
}
|
||||
ours1 = NULL;
|
||||
dest.sin_addr = __ourip;
|
||||
dest.sin_port = sin.sin_port;
|
||||
|
||||
|
||||
for (tmp = p->ourcandidates; tmp; tmp = tmp->next) {
|
||||
snprintf(component, sizeof(component), "%u", tmp->component);
|
||||
|
|
|
@ -154,68 +154,124 @@ struct local_pvt {
|
|||
#define LOCAL_BRIDGE (1 << 3) /*!< Report back the "true" channel as being bridged to */
|
||||
#define LOCAL_MOH_PASSTHRU (1 << 4) /*!< Pass through music on hold start/stop frames */
|
||||
|
||||
static int local_setoption(struct ast_channel *chan, int option, void * data, int datalen)
|
||||
/*
|
||||
* \brief Send a pvt in with no locks held and get all locks
|
||||
*
|
||||
* \note NO locks should be held prior to calling this function
|
||||
* \note The pvt must have a ref held before calling this function
|
||||
* \note if outchan or outowner is set != NULL after calling this function
|
||||
* those channels are locked and reffed.
|
||||
* \note Batman.
|
||||
*/
|
||||
static void awesome_locking(struct local_pvt *p, struct ast_channel **outchan, struct ast_channel **outowner)
|
||||
{
|
||||
int res;
|
||||
struct local_pvt *p;
|
||||
struct ast_channel *otherchan;
|
||||
struct ast_channel *chan = NULL;
|
||||
struct ast_channel *owner = NULL;
|
||||
|
||||
for (;;) {
|
||||
ao2_lock(p);
|
||||
if (p->chan) {
|
||||
chan = p->chan;
|
||||
ast_channel_ref(chan);
|
||||
}
|
||||
if (p->owner) {
|
||||
owner = p->owner;
|
||||
ast_channel_ref(owner);
|
||||
}
|
||||
ao2_unlock(p);
|
||||
|
||||
/* if we don't have both channels, then this is very easy */
|
||||
if (!owner || !chan) {
|
||||
if (owner) {
|
||||
ast_channel_lock(owner);
|
||||
} else if(chan) {
|
||||
ast_channel_lock(chan);
|
||||
}
|
||||
ao2_lock(p);
|
||||
} else {
|
||||
/* lock both channels first, then get the pvt lock */
|
||||
ast_channel_lock(chan);
|
||||
while (ast_channel_trylock(owner)) {
|
||||
CHANNEL_DEADLOCK_AVOIDANCE(chan);
|
||||
}
|
||||
ao2_lock(p);
|
||||
}
|
||||
|
||||
/* Now that we have all the locks, validate that nothing changed */
|
||||
if (p->owner != owner || p->chan != chan) {
|
||||
if (owner) {
|
||||
ast_channel_unlock(owner);
|
||||
owner = ast_channel_unref(owner);
|
||||
}
|
||||
if (chan) {
|
||||
ast_channel_unlock(chan);
|
||||
chan = ast_channel_unref(chan);
|
||||
}
|
||||
ao2_unlock(p);
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
*outowner = p->owner;
|
||||
*outchan = p->chan;
|
||||
}
|
||||
|
||||
static int local_setoption(struct ast_channel *ast, int option, void * data, int datalen)
|
||||
{
|
||||
int res = 0;
|
||||
struct local_pvt *p = NULL;
|
||||
struct ast_channel *otherchan = NULL;
|
||||
ast_chan_write_info_t *write_info;
|
||||
|
||||
if (option != AST_OPTION_CHANNEL_WRITE) {
|
||||
return -1;
|
||||
res = -1;
|
||||
goto setoption_cleanup;
|
||||
}
|
||||
|
||||
write_info = data;
|
||||
|
||||
if (write_info->version != AST_CHAN_WRITE_INFO_T_VERSION) {
|
||||
ast_log(LOG_ERROR, "The chan_write_info_t type has changed, and this channel hasn't been updated!\n");
|
||||
return -1;
|
||||
res = -1;
|
||||
goto setoption_cleanup;
|
||||
}
|
||||
|
||||
|
||||
startover:
|
||||
ast_channel_lock(chan);
|
||||
|
||||
p = chan->tech_pvt;
|
||||
if (!p) {
|
||||
ast_channel_unlock(chan);
|
||||
ast_log(LOG_WARNING, "Could not update other side of %s, local_pvt went away.\n", chan->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (ao2_trylock(p)) {
|
||||
ast_channel_unlock(chan);
|
||||
sched_yield();
|
||||
ast_channel_lock(chan);
|
||||
p = chan->tech_pvt;
|
||||
if (!p) {
|
||||
ast_channel_unlock(chan);
|
||||
ast_log(LOG_WARNING, "Could not update other side of %s, local_pvt went away.\n", chan->name);
|
||||
return -1;
|
||||
}
|
||||
/* get the tech pvt */
|
||||
ast_channel_lock(ast);
|
||||
if (!(p = ast->tech_pvt)) {
|
||||
ast_channel_unlock(ast);
|
||||
res = -1;
|
||||
goto setoption_cleanup;
|
||||
}
|
||||
ao2_ref(p, 1);
|
||||
ast_channel_unlock(ast);
|
||||
|
||||
/* get the channel we are supposed to write to */
|
||||
ao2_lock(p);
|
||||
otherchan = (write_info->chan == p->owner) ? p->chan : p->owner;
|
||||
|
||||
if (!otherchan || otherchan == write_info->chan) {
|
||||
res = -1;
|
||||
otherchan = NULL;
|
||||
ao2_unlock(p);
|
||||
ast_channel_unlock(chan);
|
||||
ast_log(LOG_WARNING, "Could not update other side of %s, other side went away.\n", chan->name);
|
||||
return 0;
|
||||
goto setoption_cleanup;
|
||||
}
|
||||
ast_channel_ref(otherchan);
|
||||
|
||||
if (ast_channel_trylock(otherchan)) {
|
||||
ao2_unlock(p);
|
||||
ast_channel_unlock(chan);
|
||||
goto startover;
|
||||
}
|
||||
|
||||
res = write_info->write_fn(otherchan, write_info->function, write_info->data, write_info->value);
|
||||
|
||||
ast_channel_unlock(otherchan);
|
||||
/* clear the pvt lock before grabbing the channel */
|
||||
ao2_unlock(p);
|
||||
ast_channel_unlock(chan);
|
||||
|
||||
ast_channel_lock(otherchan);
|
||||
res = write_info->write_fn(otherchan, write_info->function, write_info->data, write_info->value);
|
||||
ast_channel_unlock(otherchan);
|
||||
|
||||
setoption_cleanup:
|
||||
if (p) {
|
||||
ao2_ref(p, -1);
|
||||
}
|
||||
if (otherchan) {
|
||||
ast_channel_unref(otherchan);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -294,57 +350,51 @@ static struct ast_channel *local_bridgedchannel(struct ast_channel *chan, struct
|
|||
|
||||
static int local_queryoption(struct ast_channel *ast, int option, void *data, int *datalen)
|
||||
{
|
||||
struct local_pvt *p = ast->tech_pvt;
|
||||
struct ast_channel *chan, *bridged;
|
||||
int res;
|
||||
|
||||
if (!p) {
|
||||
return -1;
|
||||
}
|
||||
struct local_pvt *p;
|
||||
struct ast_channel *bridged = NULL;
|
||||
struct ast_channel *tmp = NULL;
|
||||
int res = 0;
|
||||
|
||||
if (option != AST_OPTION_T38_STATE) {
|
||||
/* AST_OPTION_T38_STATE is the only supported option at this time */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* for some reason the channel is not locked in channel.c when this function is called */
|
||||
ast_channel_lock(ast);
|
||||
if (!(p = ast->tech_pvt)) {
|
||||
ast_channel_unlock(ast);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ao2_lock(p);
|
||||
chan = IS_OUTBOUND(ast, p) ? p->owner : p->chan;
|
||||
|
||||
try_again:
|
||||
if (!chan) {
|
||||
if (!(tmp = IS_OUTBOUND(ast, p) ? p->owner : p->chan)) {
|
||||
ao2_unlock(p);
|
||||
ast_channel_unlock(ast);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ast_channel_trylock(chan)) {
|
||||
ao2_unlock(p);
|
||||
sched_yield();
|
||||
ao2_lock(p);
|
||||
chan = IS_OUTBOUND(ast, p) ? p->owner : p->chan;
|
||||
goto try_again;
|
||||
}
|
||||
|
||||
bridged = ast_bridged_channel(chan);
|
||||
if (!bridged) {
|
||||
/* can't query channel unless we are bridged */
|
||||
ao2_unlock(p);
|
||||
ast_channel_unlock(chan);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ast_channel_trylock(bridged)) {
|
||||
ast_channel_unlock(chan);
|
||||
ao2_unlock(p);
|
||||
sched_yield();
|
||||
ao2_lock(p);
|
||||
chan = IS_OUTBOUND(ast, p) ? p->owner : p->chan;
|
||||
goto try_again;
|
||||
}
|
||||
|
||||
res = ast_channel_queryoption(bridged, option, data, datalen, 0);
|
||||
ast_channel_ref(tmp);
|
||||
ao2_unlock(p);
|
||||
ast_channel_unlock(chan);
|
||||
ast_channel_unlock(bridged);
|
||||
ast_channel_unlock(ast);
|
||||
|
||||
ast_channel_lock(tmp);
|
||||
if (!(bridged = ast_bridged_channel(tmp))) {
|
||||
res = -1;
|
||||
ast_channel_unlock(tmp);
|
||||
goto query_cleanup;
|
||||
}
|
||||
ast_channel_ref(bridged);
|
||||
ast_channel_unlock(tmp);
|
||||
|
||||
query_cleanup:
|
||||
if (bridged) {
|
||||
res = ast_channel_queryoption(bridged, option, data, datalen, 0);
|
||||
bridged = ast_channel_unref(bridged);
|
||||
}
|
||||
if (tmp) {
|
||||
tmp = ast_channel_unref(tmp);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -373,31 +423,24 @@ static int local_queue_frame(struct local_pvt *p, int isoutbound, struct ast_fra
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Ensure that we have both channels locked */
|
||||
while (other && ast_channel_trylock(other)) {
|
||||
int res;
|
||||
if ((res = ao2_unlock(p))) {
|
||||
ast_log(LOG_ERROR, "chan_local bug! '&p->lock' was not locked when entering local_queue_frame! (%s)\n", strerror(res));
|
||||
return -1;
|
||||
}
|
||||
if (us && us_locked) {
|
||||
do {
|
||||
CHANNEL_DEADLOCK_AVOIDANCE(us);
|
||||
} while (ao2_trylock(p));
|
||||
} else {
|
||||
usleep(1);
|
||||
ao2_lock(p);
|
||||
}
|
||||
other = isoutbound ? p->owner : p->chan;
|
||||
/* grab a ref on the channel before unlocking the pvt,
|
||||
* other can not go away from us now regardless of locking */
|
||||
ast_channel_ref(other);
|
||||
if (us && us_locked) {
|
||||
ast_channel_unlock(us);
|
||||
}
|
||||
ao2_unlock(p);
|
||||
|
||||
if (other) {
|
||||
if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_RINGING) {
|
||||
ast_setstate(other, AST_STATE_RINGING);
|
||||
}
|
||||
ast_queue_frame(other, f);
|
||||
ast_channel_unlock(other);
|
||||
if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_RINGING) {
|
||||
ast_setstate(other, AST_STATE_RINGING);
|
||||
}
|
||||
ast_queue_frame(other, f);
|
||||
|
||||
other = ast_channel_unref(other);
|
||||
if (us && us_locked) {
|
||||
ast_channel_lock(us);
|
||||
}
|
||||
ao2_lock(p);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -429,12 +472,38 @@ static int local_answer(struct ast_channel *ast)
|
|||
/*!
|
||||
* \internal
|
||||
* \note This function assumes that we're only called from the "outbound" local channel side
|
||||
*
|
||||
* \note it is assummed p is locked and reffed before entering this function
|
||||
*/
|
||||
static void check_bridge(struct local_pvt *p)
|
||||
{
|
||||
struct ast_channel_monitor *tmp;
|
||||
if (ast_test_flag(p, LOCAL_ALREADY_MASQED) || ast_test_flag(p, LOCAL_NO_OPTIMIZATION) || !p->chan || !p->owner || (p->chan->_bridge != ast_bridged_channel(p->chan)))
|
||||
struct ast_channel *chan = NULL;
|
||||
struct ast_channel *bridged_chan = NULL;
|
||||
|
||||
/* Do a few conditional checks early on just to see if this optimization is possible */
|
||||
if (ast_test_flag(p, LOCAL_NO_OPTIMIZATION)) {
|
||||
return;
|
||||
}
|
||||
if (ast_test_flag(p, LOCAL_ALREADY_MASQED) || !p->chan || !p->owner) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Safely get the channel bridged to p->chan */
|
||||
chan = ast_channel_ref(p->chan);
|
||||
|
||||
ao2_unlock(p); /* don't call bridged channel with the pvt locked */
|
||||
bridged_chan = ast_bridged_channel(chan);
|
||||
ao2_lock(p);
|
||||
|
||||
chan = ast_channel_unref(chan);
|
||||
|
||||
/* since we had to unlock p to get the bridged chan, validate our
|
||||
* data once again and verify the bridged channel is what we expect
|
||||
* it to be in order to perform this optimization */
|
||||
if (ast_test_flag(p, LOCAL_ALREADY_MASQED) || !p->owner || !p->chan || (p->chan->_bridge != bridged_chan)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* only do the masquerade if we are being called on the outbound channel,
|
||||
if it has been bridged to another channel and if there are no pending
|
||||
|
@ -504,8 +573,8 @@ static void check_bridge(struct local_pvt *p)
|
|||
}
|
||||
ast_channel_unlock(p->owner);
|
||||
}
|
||||
ast_channel_unlock(p->chan->_bridge);
|
||||
}
|
||||
ast_channel_unlock(p->chan->_bridge);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -521,18 +590,22 @@ static int local_write(struct ast_channel *ast, struct ast_frame *f)
|
|||
int res = -1;
|
||||
int isoutbound;
|
||||
|
||||
if (!p)
|
||||
if (!p) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Just queue for delivery to the other side */
|
||||
ao2_lock(p);
|
||||
ao2_ref(p, 1); /* ref for local_queue_frame */
|
||||
ao2_lock(p);
|
||||
isoutbound = IS_OUTBOUND(ast, p);
|
||||
if (isoutbound && f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO))
|
||||
|
||||
if (isoutbound && f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) {
|
||||
check_bridge(p);
|
||||
if (!ast_test_flag(p, LOCAL_ALREADY_MASQED))
|
||||
}
|
||||
|
||||
if (!ast_test_flag(p, LOCAL_ALREADY_MASQED)) {
|
||||
res = local_queue_frame(p, isoutbound, f, ast, 1);
|
||||
else {
|
||||
} else {
|
||||
ast_debug(1, "Not posting to queue since already masked on '%s'\n", ast->name);
|
||||
res = 0;
|
||||
}
|
||||
|
@ -562,7 +635,7 @@ static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
|
|||
p->chan = newchan;
|
||||
|
||||
/* Do not let a masquerade cause a Local channel to be bridged to itself! */
|
||||
if (!ast_check_hangup(newchan) && (p->owner->_bridge == p->chan || p->chan->_bridge == p->owner)) {
|
||||
if (!ast_check_hangup(newchan) && ((p->owner && p->owner->_bridge == p->chan) || (p->chan && p->chan->_bridge == p->owner))) {
|
||||
ast_log(LOG_WARNING, "You can not bridge a Local channel to itself!\n");
|
||||
ao2_unlock(p);
|
||||
ast_queue_hangup(newchan);
|
||||
|
@ -731,46 +804,38 @@ static int local_sendhtml(struct ast_channel *ast, int subclass, const char *dat
|
|||
static int local_call(struct ast_channel *ast, char *dest, int timeout)
|
||||
{
|
||||
struct local_pvt *p = ast->tech_pvt;
|
||||
int pvt_locked = 0;
|
||||
|
||||
struct ast_channel *owner = NULL;
|
||||
struct ast_channel *chan = NULL;
|
||||
int res;
|
||||
struct ast_var_t *varptr = NULL, *new;
|
||||
size_t len, namelen;
|
||||
char *reduced_dest = ast_strdupa(dest);
|
||||
char *slash;
|
||||
const char *exten;
|
||||
const char *context;
|
||||
|
||||
if (!p || p->owner != ast) {
|
||||
if (!p) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* since we are letting go of channel locks that were locked coming into
|
||||
* this function, then we need to give the tech pvt a ref */
|
||||
ao2_ref(p, 1);
|
||||
ast_channel_unlock(ast);
|
||||
|
||||
while (ao2_trylock(p)) {
|
||||
ast_channel_unlock(ast);
|
||||
sched_yield();
|
||||
ast_channel_lock(ast);
|
||||
}
|
||||
while ((p->chan && p->owner) && ast_channel_trylock(p->chan)) {
|
||||
ao2_unlock(p);
|
||||
if (p->owner) {
|
||||
ast_channel_unlock(p->owner);
|
||||
}
|
||||
sched_yield();
|
||||
if (p->owner) {
|
||||
ast_channel_lock(p->owner);
|
||||
}
|
||||
ao2_lock(p);
|
||||
awesome_locking(p, &chan, &owner);
|
||||
pvt_locked = 1;
|
||||
|
||||
if (owner != ast) {
|
||||
res = -1;
|
||||
goto return_cleanup;
|
||||
}
|
||||
|
||||
if (!p->owner || !p->chan) {
|
||||
/* someone went away during the locking madness.
|
||||
* time to bail. */
|
||||
if (p->chan) {
|
||||
ast_channel_unlock(p->chan);
|
||||
}
|
||||
ao2_unlock(p);
|
||||
ao2_ref(p,-1);
|
||||
return -1;
|
||||
if (!owner || !chan) {
|
||||
res = -1;
|
||||
goto return_cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -780,37 +845,37 @@ static int local_call(struct ast_channel *ast, char *dest, int timeout)
|
|||
* All these failure points just return -1. The individual strings will
|
||||
* be cleared when we destroy the channel.
|
||||
*/
|
||||
ast_party_redirecting_copy(&p->chan->redirecting, &p->owner->redirecting);
|
||||
ast_party_redirecting_copy(&chan->redirecting, &owner->redirecting);
|
||||
|
||||
ast_party_dialed_copy(&p->chan->dialed, &p->owner->dialed);
|
||||
ast_party_dialed_copy(&chan->dialed, &owner->dialed);
|
||||
|
||||
ast_connected_line_copy_to_caller(&p->chan->caller, &p->owner->connected);
|
||||
ast_connected_line_copy_from_caller(&p->chan->connected, &p->owner->caller);
|
||||
ast_connected_line_copy_to_caller(&chan->caller, &owner->connected);
|
||||
ast_connected_line_copy_from_caller(&chan->connected, &owner->caller);
|
||||
|
||||
ast_string_field_set(p->chan, language, p->owner->language);
|
||||
ast_string_field_set(p->chan, accountcode, p->owner->accountcode);
|
||||
ast_string_field_set(p->chan, musicclass, p->owner->musicclass);
|
||||
ast_cdr_update(p->chan);
|
||||
ast_string_field_set(chan, language, owner->language);
|
||||
ast_string_field_set(chan, accountcode, owner->accountcode);
|
||||
ast_string_field_set(chan, musicclass, owner->musicclass);
|
||||
ast_cdr_update(chan);
|
||||
|
||||
ast_channel_cc_params_init(p->chan, ast_channel_get_cc_config_params(p->owner));
|
||||
ast_channel_cc_params_init(chan, ast_channel_get_cc_config_params(owner));
|
||||
|
||||
/* Make sure we inherit the ANSWERED_ELSEWHERE flag if it's set on the queue/dial call request in the dialplan */
|
||||
if (ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) {
|
||||
ast_set_flag(p->chan, AST_FLAG_ANSWERED_ELSEWHERE);
|
||||
ast_set_flag(chan, AST_FLAG_ANSWERED_ELSEWHERE);
|
||||
}
|
||||
|
||||
/* copy the channel variables from the incoming channel to the outgoing channel */
|
||||
/* Note that due to certain assumptions, they MUST be in the same order */
|
||||
AST_LIST_TRAVERSE(&p->owner->varshead, varptr, entries) {
|
||||
AST_LIST_TRAVERSE(&owner->varshead, varptr, entries) {
|
||||
namelen = strlen(varptr->name);
|
||||
len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2;
|
||||
if ((new = ast_calloc(1, len))) {
|
||||
memcpy(new, varptr, len);
|
||||
new->value = &(new->name[0]) + namelen + 1;
|
||||
AST_LIST_INSERT_TAIL(&p->chan->varshead, new, entries);
|
||||
AST_LIST_INSERT_TAIL(&chan->varshead, new, entries);
|
||||
}
|
||||
}
|
||||
ast_channel_datastore_inherit(p->owner, p->chan);
|
||||
ast_channel_datastore_inherit(owner, chan);
|
||||
/* If the local channel has /n or /b on the end of it,
|
||||
* we need to lop that off for our argument to setting
|
||||
* up the CC_INTERFACES variable
|
||||
|
@ -818,24 +883,57 @@ static int local_call(struct ast_channel *ast, char *dest, int timeout)
|
|||
if ((slash = strrchr(reduced_dest, '/'))) {
|
||||
*slash = '\0';
|
||||
}
|
||||
ast_set_cc_interfaces_chanvar(p->chan, reduced_dest);
|
||||
ast_set_cc_interfaces_chanvar(chan, reduced_dest);
|
||||
|
||||
if (!ast_exists_extension(p->chan, p->chan->context, p->chan->exten, 1,
|
||||
S_COR(p->owner->caller.id.number.valid, p->owner->caller.id.number.str, NULL))) {
|
||||
ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", p->chan->exten, p->chan->context);
|
||||
ao2_unlock(p);
|
||||
ast_channel_unlock(p->chan);
|
||||
ao2_ref(p, -1);
|
||||
return -1;
|
||||
exten = ast_strdupa(chan->exten);
|
||||
context = ast_strdupa(chan->context);
|
||||
|
||||
ao2_unlock(p);
|
||||
pvt_locked = 0;
|
||||
|
||||
ast_channel_unlock(chan);
|
||||
|
||||
if (!ast_exists_extension(chan, context, exten, 1,
|
||||
S_COR(owner->caller.id.number.valid, owner->caller.id.number.str, NULL))) {
|
||||
ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", exten, context);
|
||||
res = -1;
|
||||
chan = ast_channel_unref(chan); /* we already unlocked it, so clear it hear so the cleanup label won't touch it. */
|
||||
goto return_cleanup;
|
||||
}
|
||||
|
||||
/* Start switch on sub channel */
|
||||
if (!(res = ast_pbx_start(p->chan)))
|
||||
if (!(res = ast_pbx_start(chan))) {
|
||||
ao2_lock(p);
|
||||
ast_set_flag(p, LOCAL_LAUNCHED_PBX);
|
||||
ao2_unlock(p);
|
||||
}
|
||||
chan = ast_channel_unref(chan); /* chan is already unlocked, clear it here so the cleanup lable won't touch it. */
|
||||
|
||||
return_cleanup:
|
||||
if (p) {
|
||||
if (pvt_locked) {
|
||||
ao2_unlock(p);
|
||||
}
|
||||
ao2_ref(p, -1);
|
||||
}
|
||||
if (chan) {
|
||||
ast_channel_unlock(chan);
|
||||
chan = ast_channel_unref(chan);
|
||||
}
|
||||
|
||||
/* owner is supposed to be == to ast, if it
|
||||
* is, don't unlock it because ast must exit locked */
|
||||
if (owner) {
|
||||
if (owner != ast) {
|
||||
ast_channel_unlock(owner);
|
||||
ast_channel_lock(ast);
|
||||
}
|
||||
owner = ast_channel_unref(owner);
|
||||
} else {
|
||||
/* we have to exit with ast locked */
|
||||
ast_channel_lock(ast);
|
||||
}
|
||||
|
||||
ao2_unlock(p);
|
||||
ast_channel_unlock(p->chan);
|
||||
ao2_ref(p, -1);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -844,19 +942,31 @@ static int local_hangup(struct ast_channel *ast)
|
|||
{
|
||||
struct local_pvt *p = ast->tech_pvt;
|
||||
int isoutbound;
|
||||
int hangup_chan = 0;
|
||||
int res = 0;
|
||||
struct ast_frame f = { AST_FRAME_CONTROL, { AST_CONTROL_HANGUP }, .data.uint32 = ast->hangupcause };
|
||||
struct ast_channel *ochan = NULL;
|
||||
struct ast_channel *owner = NULL;
|
||||
struct ast_channel *chan = NULL;
|
||||
|
||||
if (!p)
|
||||
if (!p) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* we MUST give the tech_pvt a ref here since we are unlocking the
|
||||
* channel during deadlock avoidance. */
|
||||
/* give the pvt a ref since we are unlocking the channel. */
|
||||
ao2_ref(p, 1);
|
||||
|
||||
ao2_lock(p);
|
||||
/* the pvt isn't going anywhere, we gave it a ref */
|
||||
ast_channel_unlock(ast);
|
||||
|
||||
isoutbound = IS_OUTBOUND(ast, p);
|
||||
/* lock everything */
|
||||
awesome_locking(p, &chan, &owner);
|
||||
|
||||
if (ast != chan && ast != owner) {
|
||||
res = -1;
|
||||
goto local_hangup_cleanup;
|
||||
}
|
||||
|
||||
isoutbound = IS_OUTBOUND(ast, p); /* just comparing pointer of ast */
|
||||
|
||||
if (p->chan && ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) {
|
||||
ast_set_flag(p->chan, AST_FLAG_ANSWERED_ELSEWHERE);
|
||||
|
@ -866,92 +976,59 @@ static int local_hangup(struct ast_channel *ast)
|
|||
if (isoutbound) {
|
||||
const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS");
|
||||
if ((status) && (p->owner)) {
|
||||
/* Deadlock avoidance */
|
||||
while (p->owner && ast_channel_trylock(p->owner)) {
|
||||
ao2_unlock(p);
|
||||
if (p->chan) {
|
||||
ast_channel_unlock(p->chan);
|
||||
}
|
||||
sched_yield();
|
||||
if (p->chan) {
|
||||
ast_channel_lock(p->chan);
|
||||
}
|
||||
ao2_lock(p);
|
||||
}
|
||||
if (p->owner) {
|
||||
p->owner->hangupcause = p->chan->hangupcause;
|
||||
pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status);
|
||||
ast_channel_unlock(p->owner);
|
||||
}
|
||||
}
|
||||
if (!p->chan) {
|
||||
/* chan was == to ast and was !NULL before deadlock avoidance started, if chan
|
||||
* is NULL now, then we should bail because that channel
|
||||
* hungup already. This is possible because we let go of the
|
||||
* lock given to the ast channel passed to this function during
|
||||
* deadlock avoidance. */
|
||||
ao2_unlock(p);
|
||||
ao2_ref(p, -1);
|
||||
return 0;
|
||||
}
|
||||
p->chan = NULL;
|
||||
ast_clear_flag(p, LOCAL_LAUNCHED_PBX);
|
||||
ast_module_user_remove(p->u_chan);
|
||||
} else {
|
||||
ast_module_user_remove(p->u_owner);
|
||||
while (p->chan && ast_channel_trylock(p->chan)) {
|
||||
ao2_unlock(p);
|
||||
if (p->owner) {
|
||||
ast_channel_unlock(p->owner);
|
||||
}
|
||||
sched_yield();
|
||||
if (p->owner) {
|
||||
ast_channel_lock(p->owner);
|
||||
}
|
||||
ao2_lock(p);
|
||||
}
|
||||
if (p->chan) {
|
||||
ast_queue_hangup(p->chan);
|
||||
ast_channel_unlock(p->chan);
|
||||
p->owner->hangupcause = p->chan->hangupcause;
|
||||
pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status);
|
||||
}
|
||||
|
||||
if (!p->owner) {
|
||||
/* owner was == to ast and was !NULL before deadlock avoidance started, if
|
||||
* owner is NULL now, then we should bail because that channel
|
||||
* hungup already. This is possible because we let go of the
|
||||
* lock given to the ast channel passed to this function during
|
||||
* deadlock avoidance. */
|
||||
ao2_unlock(p);
|
||||
ao2_ref(p, -1);
|
||||
return 0;
|
||||
ast_clear_flag(p, LOCAL_LAUNCHED_PBX);
|
||||
ast_module_user_remove(p->u_chan);
|
||||
p->chan = NULL;
|
||||
} else {
|
||||
ast_module_user_remove(p->u_owner);
|
||||
if (p->chan) {
|
||||
ast_queue_hangup(p->chan);
|
||||
}
|
||||
p->owner = NULL;
|
||||
}
|
||||
|
||||
ast->tech_pvt = NULL;
|
||||
ast->tech_pvt = NULL; /* this is one of our locked channels, doesn't matter which */
|
||||
|
||||
if (!p->owner && !p->chan) {
|
||||
ao2_unlock(p);
|
||||
|
||||
/* Remove from list */
|
||||
ao2_unlink(locals, p);
|
||||
ao2_ref(p, -1);
|
||||
return 0;
|
||||
p = NULL;
|
||||
res = 0;
|
||||
goto local_hangup_cleanup;
|
||||
}
|
||||
if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX)) {
|
||||
/* Need to actually hangup since there is no PBX */
|
||||
ochan = p->chan;
|
||||
hangup_chan = 1;
|
||||
} else {
|
||||
local_queue_frame(p, isoutbound, &f, NULL, 1);
|
||||
local_queue_frame(p, isoutbound, &f, NULL, 0);
|
||||
}
|
||||
|
||||
ao2_unlock(p);
|
||||
if (ochan) {
|
||||
ast_hangup(ochan);
|
||||
local_hangup_cleanup:
|
||||
if (p) {
|
||||
ao2_unlock(p);
|
||||
ao2_ref(p, -1);
|
||||
}
|
||||
if (chan) {
|
||||
ast_channel_unlock(chan);
|
||||
if (hangup_chan) {
|
||||
ast_hangup(chan);
|
||||
}
|
||||
chan = ast_channel_unref(chan);
|
||||
}
|
||||
if (owner) {
|
||||
ast_channel_unlock(owner);
|
||||
owner = ast_channel_unref(owner);
|
||||
}
|
||||
|
||||
ao2_ref(p, -1);
|
||||
return 0;
|
||||
/* leave with the same stupid channel locked that came in */
|
||||
ast_channel_lock(ast);
|
||||
return res;
|
||||
}
|
||||
|
||||
static void local_destroy(void *obj)
|
||||
|
|
|
@ -93,14 +93,15 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
|||
#define INADDR_NONE (in_addr_t)(-1)
|
||||
#endif
|
||||
|
||||
/*! Global jitterbuffer configuration - by default, jb is disabled */
|
||||
/*! Global jitterbuffer configuration - by default, jb is disabled
|
||||
* \note Values shown here match the defaults shown in mgcp.conf.sample */
|
||||
static struct ast_jb_conf default_jbconf =
|
||||
{
|
||||
.flags = 0,
|
||||
.max_size = -1,
|
||||
.resync_threshold = -1,
|
||||
.impl = "",
|
||||
.target_extra = -1,
|
||||
.max_size = 200,
|
||||
.resync_threshold = 1000,
|
||||
.impl = "fixed",
|
||||
.target_extra = 40,
|
||||
};
|
||||
static struct ast_jb_conf global_jbconf;
|
||||
|
||||
|
@ -3770,7 +3771,7 @@ static void *do_monitor(void *data)
|
|||
{
|
||||
int res;
|
||||
int reloading;
|
||||
struct mgcp_gateway *g, *gprev, *gnext;
|
||||
struct mgcp_gateway *g, *gprev;
|
||||
/*struct mgcp_gateway *g;*/
|
||||
/*struct mgcp_endpoint *e;*/
|
||||
/*time_t thispass = 0, lastpass = 0;*/
|
||||
|
@ -3840,12 +3841,10 @@ static void *do_monitor(void *data)
|
|||
g = gateways;
|
||||
gprev = NULL;
|
||||
while(g) {
|
||||
gnext = g->next;
|
||||
if(g->realtime) {
|
||||
if(mgcp_prune_realtime_gateway(g)) {
|
||||
if(gprev) {
|
||||
gprev->next = gnext;
|
||||
gprev = g;
|
||||
gprev->next = g->next;
|
||||
} else {
|
||||
gateways = g->next;
|
||||
}
|
||||
|
@ -3859,7 +3858,7 @@ static void *do_monitor(void *data)
|
|||
} else {
|
||||
gprev = g;
|
||||
}
|
||||
g = gnext;
|
||||
g = g->next;
|
||||
}
|
||||
ast_mutex_unlock(&gatelock);
|
||||
lastrun = time(NULL);
|
||||
|
@ -4748,7 +4747,7 @@ static int reload_config(int reload)
|
|||
memcpy(&__ourip, hp->h_addr, sizeof(__ourip));
|
||||
}
|
||||
if (!ntohs(bindaddr.sin_port))
|
||||
bindaddr.sin_port = ntohs(DEFAULT_MGCP_CA_PORT);
|
||||
bindaddr.sin_port = htons(DEFAULT_MGCP_CA_PORT);
|
||||
bindaddr.sin_family = AF_INET;
|
||||
ast_mutex_lock(&netlock);
|
||||
if (mgcpsock > -1)
|
||||
|
|
|
@ -65,14 +65,15 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
|||
|
||||
#include "console_video.h"
|
||||
|
||||
/*! Global jitterbuffer configuration - by default, jb is disabled */
|
||||
/*! Global jitterbuffer configuration - by default, jb is disabled
|
||||
* \note Values shown here match the defaults shown in oss.conf.sample */
|
||||
static struct ast_jb_conf default_jbconf =
|
||||
{
|
||||
.flags = 0,
|
||||
.max_size = -1,
|
||||
.resync_threshold = -1,
|
||||
.impl = "",
|
||||
.target_extra = -1,
|
||||
.max_size = 200,
|
||||
.resync_threshold = 1000,
|
||||
.impl = "fixed",
|
||||
.target_extra = 40,
|
||||
};
|
||||
static struct ast_jb_conf global_jbconf;
|
||||
|
||||
|
|
|
@ -295,12 +295,10 @@ static int phone_call(struct ast_channel *ast, char *dest, int timeout)
|
|||
ast_localtime(&UtcTime, &tm, NULL);
|
||||
|
||||
memset(&cid, 0, sizeof(PHONE_CID));
|
||||
if(&tm != NULL) {
|
||||
snprintf(cid.month, sizeof(cid.month), "%02d",(tm.tm_mon + 1));
|
||||
snprintf(cid.day, sizeof(cid.day), "%02d", tm.tm_mday);
|
||||
snprintf(cid.hour, sizeof(cid.hour), "%02d", tm.tm_hour);
|
||||
snprintf(cid.min, sizeof(cid.min), "%02d", tm.tm_min);
|
||||
}
|
||||
snprintf(cid.month, sizeof(cid.month), "%02d",(tm.tm_mon + 1));
|
||||
snprintf(cid.day, sizeof(cid.day), "%02d", tm.tm_mday);
|
||||
snprintf(cid.hour, sizeof(cid.hour), "%02d", tm.tm_hour);
|
||||
snprintf(cid.min, sizeof(cid.min), "%02d", tm.tm_min);
|
||||
/* the standard format of ast->callerid is: "name" <number>, but not always complete */
|
||||
if (!ast->connected.id.name.valid
|
||||
|| ast_strlen_zero(ast->connected.id.name.str)) {
|
||||
|
|
1571
channels/chan_sip.c
1571
channels/chan_sip.c
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -187,14 +187,15 @@ static void dummy(char *unused, ...)
|
|||
return;
|
||||
}
|
||||
|
||||
/*! \brief Global jitterbuffer configuration - by default, jb is disabled */
|
||||
/*! \brief Global jitterbuffer configuration - by default, jb is disabled
|
||||
* \note Values shown here match the defaults shown in unistim.conf.sample */
|
||||
static struct ast_jb_conf default_jbconf =
|
||||
{
|
||||
.flags = 0,
|
||||
.max_size = -1,
|
||||
.resync_threshold = -1,
|
||||
.impl = "",
|
||||
.target_extra = -1,
|
||||
.max_size = 200,
|
||||
.resync_threshold = 1000,
|
||||
.impl = "fixed",
|
||||
.target_extra = 40,
|
||||
};
|
||||
static struct ast_jb_conf global_jbconf;
|
||||
|
||||
|
@ -1324,7 +1325,7 @@ send_select_output(struct unistimsession *pte, unsigned char output, unsigned ch
|
|||
change_favorite_icon(pte, FAV_ICON_SPEAKER_OFFHOOK_BLACK);
|
||||
}
|
||||
} else
|
||||
ast_log(LOG_WARNING, "Invalid ouput (%d)\n", output);
|
||||
ast_log(LOG_WARNING, "Invalid output (%d)\n", output);
|
||||
if (output != pte->device->output)
|
||||
pte->device->previous_output = pte->device->output;
|
||||
pte->device->output = output;
|
||||
|
@ -1924,7 +1925,7 @@ static int attempt_transfer(struct unistim_subchannel *p1, struct unistim_subcha
|
|||
int res = 0;
|
||||
struct ast_channel
|
||||
*chana = NULL, *chanb = NULL, *bridgea = NULL, *bridgeb = NULL, *peera =
|
||||
NULL, *peerb = NULL, *peerc = NULL, *peerd = NULL;
|
||||
NULL, *peerb = NULL, *peerc = NULL;
|
||||
|
||||
if (!p1->owner || !p2->owner) {
|
||||
ast_log(LOG_WARNING, "Transfer attempted without dual ownership?\n");
|
||||
|
@ -1939,12 +1940,10 @@ static int attempt_transfer(struct unistim_subchannel *p1, struct unistim_subcha
|
|||
peera = chana;
|
||||
peerb = chanb;
|
||||
peerc = bridgea;
|
||||
peerd = bridgeb;
|
||||
} else if (bridgeb) {
|
||||
peera = chanb;
|
||||
peerb = chana;
|
||||
peerc = bridgeb;
|
||||
peerd = bridgea;
|
||||
}
|
||||
|
||||
if (peera && peerb && peerc && (peerb != peerc)) {
|
||||
|
|
|
@ -187,14 +187,15 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
|||
#define EEPROM_TXCTCSSADJ 15
|
||||
#define EEPROM_RXSQUELCHADJ 16
|
||||
|
||||
/*! Global jitterbuffer configuration - by default, jb is disabled */
|
||||
/*! Global jitterbuffer configuration - by default, jb is disabled
|
||||
* \note Values shown here match the defaults shown in usbradio.conf.sample */
|
||||
static struct ast_jb_conf default_jbconf =
|
||||
{
|
||||
.flags = 0,
|
||||
.max_size = -1,
|
||||
.resync_threshold = -1,
|
||||
.impl = "",
|
||||
.target_extra = -1,
|
||||
.max_size = 200,
|
||||
.resync_threshold = 1000,
|
||||
.impl = "fixed",
|
||||
.target_extra = 40,
|
||||
};
|
||||
static struct ast_jb_conf global_jbconf;
|
||||
|
||||
|
|
|
@ -110,7 +110,6 @@ static unsigned int iax_str2flags(const char *buf)
|
|||
{
|
||||
int x;
|
||||
int len;
|
||||
int found;
|
||||
unsigned int flags = 0;
|
||||
char *e;
|
||||
while(buf && *buf) {
|
||||
|
@ -119,7 +118,6 @@ static unsigned int iax_str2flags(const char *buf)
|
|||
len = e - buf;
|
||||
else
|
||||
len = 0;
|
||||
found = 0;
|
||||
for (x = 0; x < ARRAY_LEN(iax_flags); x++) {
|
||||
if ((len && !strncasecmp(iax_flags[x].name, buf, len)) ||
|
||||
(!len && !strcasecmp(iax_flags[x].name, buf))) {
|
||||
|
|
|
@ -1173,7 +1173,7 @@ int setup_bc(struct misdn_bchannel *bc)
|
|||
|
||||
cb_log(4, stack->port," --> Channel is %d\n", bc->channel);
|
||||
|
||||
if (bc->nodsp) {
|
||||
if (bc->nodsp && !bc->hdlc) {
|
||||
cb_log(2, stack->port," --> TRANSPARENT Mode (no DSP, no HDLC)\n");
|
||||
pid.protocol[1] = ISDN_PID_L1_B_64TRANS;
|
||||
pid.protocol[2] = ISDN_PID_L2_B_TRANS;
|
||||
|
|
|
@ -47,14 +47,15 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
|||
#define NUM_GEN_ELEMENTS (sizeof(gen_spec) / sizeof(struct misdn_cfg_spec))
|
||||
#define NUM_PORT_ELEMENTS (sizeof(port_spec) / sizeof(struct misdn_cfg_spec))
|
||||
|
||||
/*! Global jitterbuffer configuration - by default, jb is disabled */
|
||||
/*! Global jitterbuffer configuration - by default, jb is disabled
|
||||
* \note Values shown here match the defaults shown in misdn.conf.sample */
|
||||
static struct ast_jb_conf default_jbconf =
|
||||
{
|
||||
.flags = 0,
|
||||
.max_size = -1,
|
||||
.resync_threshold = -1,
|
||||
.impl = "",
|
||||
.target_extra = -1,
|
||||
.max_size = 200,
|
||||
.resync_threshold = 1000,
|
||||
.impl = "fixed",
|
||||
.target_extra = 40,
|
||||
};
|
||||
|
||||
static struct ast_jb_conf global_jbconf;
|
||||
|
|
|
@ -1470,7 +1470,6 @@ int analog_hangup(struct analog_pvt *p, struct ast_channel *ast)
|
|||
}
|
||||
|
||||
analog_stop_callwait(p);
|
||||
ast->tech_pvt = NULL;
|
||||
|
||||
ast_verb(3, "Hanging up on '%s'\n", ast->name);
|
||||
|
||||
|
@ -2010,10 +2009,13 @@ static void *__analog_ss_thread(void *data)
|
|||
}
|
||||
if ((p->sig == ANALOG_SIG_FEATDMF) || (p->sig == ANALOG_SIG_FEATDMF_TA)) {
|
||||
analog_wink(p, idx);
|
||||
/* some switches require a minimum guard time between
|
||||
the last FGD wink and something that answers
|
||||
immediately. This ensures it */
|
||||
if (ast_safe_sleep(chan,100)) {
|
||||
/*
|
||||
* Some switches require a minimum guard time between the last
|
||||
* FGD wink and something that answers immediately. This
|
||||
* ensures it.
|
||||
*/
|
||||
if (ast_safe_sleep(chan, 100)) {
|
||||
ast_hangup(chan);
|
||||
goto quit;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6242,18 +6242,29 @@ static void *pri_dchannel(void *vpri)
|
|||
e->ringing.call);
|
||||
sig_pri_cc_generic_check(pri, chanpos, AST_CC_CCNR);
|
||||
sig_pri_set_echocanceller(pri->pvts[chanpos], 1);
|
||||
sig_pri_lock_owner(pri, chanpos);
|
||||
if (pri->pvts[chanpos]->owner) {
|
||||
ast_setstate(pri->pvts[chanpos]->owner, AST_STATE_RINGING);
|
||||
ast_channel_unlock(pri->pvts[chanpos]->owner);
|
||||
}
|
||||
pri_queue_control(pri, chanpos, AST_CONTROL_RINGING);
|
||||
if (pri->pvts[chanpos]->call_level < SIG_PRI_CALL_LEVEL_ALERTING) {
|
||||
pri->pvts[chanpos]->call_level = SIG_PRI_CALL_LEVEL_ALERTING;
|
||||
}
|
||||
|
||||
if (
|
||||
if (!pri->pvts[chanpos]->progress
|
||||
&& !pri->pvts[chanpos]->no_b_channel
|
||||
#ifdef PRI_PROGRESS_MASK
|
||||
e->ringing.progressmask & PRI_PROG_INBAND_AVAILABLE
|
||||
&& (e->ringing.progressmask
|
||||
& (PRI_PROG_CALL_NOT_E2E_ISDN | PRI_PROG_INBAND_AVAILABLE))
|
||||
#else
|
||||
e->ringing.progress == 8
|
||||
&& e->ringing.progress == 8
|
||||
#endif
|
||||
) {
|
||||
/* Bring voice path up */
|
||||
pri_queue_control(pri, chanpos, AST_CONTROL_PROGRESS);
|
||||
pri->pvts[chanpos]->progress = 1;
|
||||
sig_pri_set_dialing(pri->pvts[chanpos], 0);
|
||||
sig_pri_open_media(pri->pvts[chanpos]);
|
||||
}
|
||||
|
||||
|
@ -6305,7 +6316,8 @@ static void *pri_dchannel(void *vpri)
|
|||
if (!pri->pvts[chanpos]->progress
|
||||
&& !pri->pvts[chanpos]->no_b_channel
|
||||
#ifdef PRI_PROGRESS_MASK
|
||||
&& (e->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE)
|
||||
&& (e->proceeding.progressmask
|
||||
& (PRI_PROG_CALL_NOT_E2E_ISDN | PRI_PROG_INBAND_AVAILABLE))
|
||||
#else
|
||||
&& e->proceeding.progress == 8
|
||||
#endif
|
||||
|
@ -6347,7 +6359,8 @@ static void *pri_dchannel(void *vpri)
|
|||
if (!pri->pvts[chanpos]->progress
|
||||
&& !pri->pvts[chanpos]->no_b_channel
|
||||
#ifdef PRI_PROGRESS_MASK
|
||||
&& (e->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE)
|
||||
&& (e->proceeding.progressmask
|
||||
& (PRI_PROG_CALL_NOT_E2E_ISDN | PRI_PROG_INBAND_AVAILABLE))
|
||||
#else
|
||||
&& e->proceeding.progress == 8
|
||||
#endif
|
||||
|
@ -6355,9 +6368,9 @@ static void *pri_dchannel(void *vpri)
|
|||
/* Bring voice path up */
|
||||
pri_queue_control(pri, chanpos, AST_CONTROL_PROGRESS);
|
||||
pri->pvts[chanpos]->progress = 1;
|
||||
sig_pri_set_dialing(pri->pvts[chanpos], 0);
|
||||
sig_pri_open_media(pri->pvts[chanpos]);
|
||||
}
|
||||
sig_pri_set_dialing(pri->pvts[chanpos], 0);
|
||||
sig_pri_unlock_private(pri->pvts[chanpos]);
|
||||
break;
|
||||
case PRI_EVENT_FACILITY:
|
||||
|
@ -7040,6 +7053,52 @@ static void *pri_dchannel(void *vpri)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Output AMI show spans response events for the given PRI span.
|
||||
* \since 1.10
|
||||
*
|
||||
* \param show_cmd AMI command name
|
||||
* \param s AMI session to output span information.
|
||||
* \param pri PRI span control structure.
|
||||
* \param dchannels Array of D channel channel numbers.
|
||||
* \param action_id Action ID line to use.
|
||||
*
|
||||
* \return Number of D channels on this span.
|
||||
*/
|
||||
int sig_pri_ami_show_spans(struct mansession *s, const char *show_cmd, struct sig_pri_span *pri, const int *dchannels, const char *action_id)
|
||||
{
|
||||
int count;
|
||||
int x;
|
||||
|
||||
count = 0;
|
||||
for (x = 0; x < ARRAY_LEN(pri->dchans); ++x) {
|
||||
if (pri->dchans[x]) {
|
||||
++count;
|
||||
|
||||
astman_append(s,
|
||||
"Event: %s\r\n"
|
||||
"Span: %d\r\n"
|
||||
"DChannel: %d\r\n"
|
||||
"Order: %s\r\n"
|
||||
"Active: %s\r\n"
|
||||
"Alarm: %s\r\n"
|
||||
"Up: %s\r\n"
|
||||
"%s"
|
||||
"\r\n",
|
||||
show_cmd,
|
||||
pri->span,
|
||||
dchannels[x],
|
||||
pri_order(x),
|
||||
(pri->dchans[x] == pri->pri) ? "Yes" : "No",
|
||||
(pri->dchanavail[x] & DCHAN_NOTINALARM) ? "No" : "Yes",
|
||||
(pri->dchanavail[x] & DCHAN_UP) ? "Yes" : "No",
|
||||
action_id
|
||||
);
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
void sig_pri_init_pri(struct sig_pri_span *pri)
|
||||
{
|
||||
int i;
|
||||
|
@ -7133,8 +7192,6 @@ int sig_pri_hangup(struct sig_pri_chan *p, struct ast_channel *ast)
|
|||
|
||||
sig_pri_span_devstate_changed(p->pri);
|
||||
pri_rel(p->pri);
|
||||
|
||||
ast->tech_pvt = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -8145,18 +8202,20 @@ int sig_pri_digit_begin(struct sig_pri_chan *pvt, struct ast_channel *ast, char
|
|||
* \since 1.8
|
||||
*
|
||||
* \param pri PRI span control structure.
|
||||
* \param vm_number Voicemail controlling number (NULL if not present).
|
||||
* \param mbox_number Mailbox number
|
||||
* \param mbox_context Mailbox context
|
||||
* \param num_messages Number of messages waiting.
|
||||
*
|
||||
* \return Nothing
|
||||
*/
|
||||
static void sig_pri_send_mwi_indication(struct sig_pri_span *pri, const char *mbox_number, const char *mbox_context, int num_messages)
|
||||
static void sig_pri_send_mwi_indication(struct sig_pri_span *pri, const char *vm_number, const char *mbox_number, const char *mbox_context, int num_messages)
|
||||
{
|
||||
struct pri_party_id voicemail;
|
||||
struct pri_party_id mailbox;
|
||||
|
||||
ast_debug(1, "Send MWI indication for %s@%s num_messages:%d\n", mbox_number,
|
||||
mbox_context, num_messages);
|
||||
ast_debug(1, "Send MWI indication for %s@%s vm_number:%s num_messages:%d\n",
|
||||
mbox_number, mbox_context, S_OR(vm_number, "<not-present>"), num_messages);
|
||||
|
||||
memset(&mailbox, 0, sizeof(mailbox));
|
||||
mailbox.number.valid = 1;
|
||||
|
@ -8164,8 +8223,21 @@ static void sig_pri_send_mwi_indication(struct sig_pri_span *pri, const char *mb
|
|||
mailbox.number.plan = (PRI_TON_UNKNOWN << 4) | PRI_NPI_UNKNOWN;
|
||||
ast_copy_string(mailbox.number.str, mbox_number, sizeof(mailbox.number.str));
|
||||
|
||||
memset(&voicemail, 0, sizeof(voicemail));
|
||||
voicemail.number.valid = 1;
|
||||
voicemail.number.presentation = PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
|
||||
voicemail.number.plan = (PRI_TON_UNKNOWN << 4) | PRI_NPI_UNKNOWN;
|
||||
if (vm_number) {
|
||||
ast_copy_string(voicemail.number.str, vm_number, sizeof(voicemail.number.str));
|
||||
}
|
||||
|
||||
ast_mutex_lock(&pri->lock);
|
||||
#if defined(HAVE_PRI_MWI_V2)
|
||||
pri_mwi_indicate_v2(pri->pri, &mailbox, &voicemail, 1 /* speech */, num_messages,
|
||||
NULL, NULL, -1, 0);
|
||||
#else /* !defined(HAVE_PRI_MWI_V2) */
|
||||
pri_mwi_indicate(pri->pri, &mailbox, 1 /* speech */, num_messages, NULL, NULL, -1, 0);
|
||||
#endif /* !defined(HAVE_PRI_MWI_V2) */
|
||||
ast_mutex_unlock(&pri->lock);
|
||||
}
|
||||
#endif /* defined(HAVE_PRI_MWI) */
|
||||
|
@ -8187,6 +8259,7 @@ static void sig_pri_mwi_event_cb(const struct ast_event *event, void *userdata)
|
|||
const char *mbox_context;
|
||||
const char *mbox_number;
|
||||
int num_messages;
|
||||
int idx;
|
||||
|
||||
mbox_number = ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX);
|
||||
if (ast_strlen_zero(mbox_number)) {
|
||||
|
@ -8197,7 +8270,20 @@ static void sig_pri_mwi_event_cb(const struct ast_event *event, void *userdata)
|
|||
return;
|
||||
}
|
||||
num_messages = ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS);
|
||||
sig_pri_send_mwi_indication(pri, mbox_number, mbox_context, num_messages);
|
||||
|
||||
for (idx = 0; idx < ARRAY_LEN(pri->mbox); ++idx) {
|
||||
if (!pri->mbox[idx].sub) {
|
||||
/* Mailbox slot is empty */
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(pri->mbox[idx].number, mbox_number)
|
||||
&& !strcmp(pri->mbox[idx].context, mbox_context)) {
|
||||
/* Found the mailbox. */
|
||||
sig_pri_send_mwi_indication(pri, pri->mbox[idx].vm_number, mbox_number,
|
||||
mbox_context, num_messages);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* defined(HAVE_PRI_MWI) */
|
||||
|
||||
|
@ -8219,8 +8305,8 @@ static void sig_pri_mwi_cache_update(struct sig_pri_span *pri)
|
|||
|
||||
for (idx = 0; idx < ARRAY_LEN(pri->mbox); ++idx) {
|
||||
if (!pri->mbox[idx].sub) {
|
||||
/* There are no more mailboxes on this span. */
|
||||
break;
|
||||
/* Mailbox slot is empty */
|
||||
continue;
|
||||
}
|
||||
|
||||
event = ast_event_get_cached(AST_EVENT_MWI,
|
||||
|
@ -8232,8 +8318,8 @@ static void sig_pri_mwi_cache_update(struct sig_pri_span *pri)
|
|||
continue;
|
||||
}
|
||||
num_messages = ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS);
|
||||
sig_pri_send_mwi_indication(pri, pri->mbox[idx].number, pri->mbox[idx].context,
|
||||
num_messages);
|
||||
sig_pri_send_mwi_indication(pri, pri->mbox[idx].vm_number, pri->mbox[idx].number,
|
||||
pri->mbox[idx].context, num_messages);
|
||||
ast_event_destroy(event);
|
||||
}
|
||||
}
|
||||
|
@ -8318,8 +8404,7 @@ int sig_pri_start_pri(struct sig_pri_span *pri)
|
|||
int i;
|
||||
#if defined(HAVE_PRI_MWI)
|
||||
char *saveptr;
|
||||
char *mbox_number;
|
||||
char *mbox_context;
|
||||
char *prev_vm_number;
|
||||
struct ast_str *mwi_description = ast_str_alloca(64);
|
||||
#endif /* defined(HAVE_PRI_MWI) */
|
||||
|
||||
|
@ -8336,15 +8421,41 @@ int sig_pri_start_pri(struct sig_pri_span *pri)
|
|||
sig_pri_sort_pri_chans(pri);
|
||||
|
||||
#if defined(HAVE_PRI_MWI)
|
||||
/*
|
||||
* Split the mwi_vm_numbers configuration string into the mbox[].vm_number:
|
||||
* vm_number{,vm_number}
|
||||
*/
|
||||
prev_vm_number = NULL;
|
||||
saveptr = pri->mwi_vm_numbers;
|
||||
for (i = 0; i < ARRAY_LEN(pri->mbox); ++i) {
|
||||
char *vm_number;
|
||||
|
||||
vm_number = strsep(&saveptr, ",");
|
||||
if (vm_number) {
|
||||
vm_number = ast_strip(vm_number);
|
||||
}
|
||||
if (ast_strlen_zero(vm_number)) {
|
||||
/* There was no number so reuse the previous number. */
|
||||
vm_number = prev_vm_number;
|
||||
} else {
|
||||
/* We have a new number. */
|
||||
prev_vm_number = vm_number;
|
||||
}
|
||||
pri->mbox[i].vm_number = vm_number;
|
||||
}
|
||||
|
||||
/*
|
||||
* Split the mwi_mailboxes configuration string into the mbox[]:
|
||||
* mailbox_number[@context]{,mailbox_number[@context]}
|
||||
*/
|
||||
i = 0;
|
||||
saveptr = pri->mwi_mailboxes;
|
||||
while (i < ARRAY_LEN(pri->mbox)) {
|
||||
for (i = 0; i < ARRAY_LEN(pri->mbox); ++i) {
|
||||
char *mbox_number;
|
||||
char *mbox_context;
|
||||
|
||||
mbox_number = strsep(&saveptr, ",");
|
||||
if (!mbox_number) {
|
||||
/* No more defined mailboxes. */
|
||||
break;
|
||||
}
|
||||
/* Split the mailbox_number and context */
|
||||
|
@ -8364,6 +8475,8 @@ int sig_pri_start_pri(struct sig_pri_span *pri)
|
|||
}
|
||||
|
||||
/* Fill the mbox[] element. */
|
||||
pri->mbox[i].number = mbox_number;
|
||||
pri->mbox[i].context = mbox_context;
|
||||
ast_str_set(&mwi_description, -1, "%s span %d[%d] MWI mailbox %s@%s",
|
||||
sig_pri_cc_type_name, pri->span, i, mbox_number, mbox_context);
|
||||
pri->mbox[i].sub = ast_event_subscribe(AST_EVENT_MWI, sig_pri_mwi_event_cb,
|
||||
|
@ -8374,11 +8487,13 @@ int sig_pri_start_pri(struct sig_pri_span *pri)
|
|||
if (!pri->mbox[i].sub) {
|
||||
ast_log(LOG_ERROR, "%s span %d could not subscribe to MWI events for %s@%s.",
|
||||
sig_pri_cc_type_name, pri->span, mbox_number, mbox_context);
|
||||
continue;
|
||||
}
|
||||
pri->mbox[i].number = mbox_number;
|
||||
pri->mbox[i].context = mbox_context;
|
||||
++i;
|
||||
#if defined(HAVE_PRI_MWI_V2)
|
||||
if (ast_strlen_zero(pri->mbox[i].vm_number)) {
|
||||
ast_log(LOG_WARNING, "%s span %d MWI voicemail number for %s@%s is empty.\n",
|
||||
sig_pri_cc_type_name, pri->span, mbox_number, mbox_context);
|
||||
}
|
||||
#endif /* defined(HAVE_PRI_MWI_V2) */
|
||||
}
|
||||
#endif /* defined(HAVE_PRI_MWI) */
|
||||
|
||||
|
@ -8465,6 +8580,9 @@ int sig_pri_start_pri(struct sig_pri_span *pri)
|
|||
pri_display_options_send(pri->pri, pri->display_flags_send);
|
||||
pri_display_options_receive(pri->pri, pri->display_flags_receive);
|
||||
#endif /* defined(HAVE_PRI_DISPLAY_TEXT) */
|
||||
#if defined(HAVE_PRI_DATETIME_SEND)
|
||||
pri_date_time_send_option(pri->pri, pri->datetime_send);
|
||||
#endif /* defined(HAVE_PRI_DATETIME_SEND) */
|
||||
|
||||
pri->resetpos = -1;
|
||||
if (ast_pthread_create_background(&pri->master, NULL, pri_dchannel, pri)) {
|
||||
|
@ -8610,18 +8728,10 @@ static void build_status(char *s, size_t len, int status, int active)
|
|||
if (!s || len < 1) {
|
||||
return;
|
||||
}
|
||||
s[0] = '\0';
|
||||
if (!(status & DCHAN_NOTINALARM))
|
||||
strncat(s, "In Alarm, ", len - strlen(s) - 1);
|
||||
if (status & DCHAN_UP)
|
||||
strncat(s, "Up", len - strlen(s) - 1);
|
||||
else
|
||||
strncat(s, "Down", len - strlen(s) - 1);
|
||||
if (active)
|
||||
strncat(s, ", Active", len - strlen(s) - 1);
|
||||
else
|
||||
strncat(s, ", Standby", len - strlen(s) - 1);
|
||||
s[len - 1] = '\0';
|
||||
snprintf(s, len, "%s%s, %s",
|
||||
(status & DCHAN_NOTINALARM) ? "" : "In Alarm, ",
|
||||
(status & DCHAN_UP) ? "Up" : "Down",
|
||||
(active) ? "Active" : "Standby");
|
||||
}
|
||||
|
||||
void sig_pri_cli_show_spans(int fd, int span, struct sig_pri_span *pri)
|
||||
|
|
|
@ -359,12 +359,22 @@ struct sig_pri_chan {
|
|||
#if defined(HAVE_PRI_MWI)
|
||||
/*! Maximum number of mailboxes per span. */
|
||||
#define SIG_PRI_MAX_MWI_MAILBOXES 8
|
||||
/*! Typical maximum length of mwi voicemail controlling number */
|
||||
#define SIG_PRI_MAX_MWI_VM_NUMBER_LEN 10 /* digits in number */
|
||||
/*! Typical maximum length of mwi mailbox number */
|
||||
#define SIG_PRI_MAX_MWI_MBOX_NUMBER_LEN 10 /* digits in number */
|
||||
/*! Typical maximum length of mwi mailbox context */
|
||||
#define SIG_PRI_MAX_MWI_CONTEXT_LEN 10
|
||||
/*!
|
||||
* \brief Maximum mwi_mailbox string length.
|
||||
* \brief Maximum mwi_vm_numbers string length.
|
||||
* \details
|
||||
* max_length = #mailboxes * (vm_number + ',')
|
||||
* The last ',' is a null terminator instead.
|
||||
*/
|
||||
#define SIG_PRI_MAX_MWI_VM_NUMBER_STR (SIG_PRI_MAX_MWI_MAILBOXES \
|
||||
* (SIG_PRI_MAX_MWI_VM_NUMBER_LEN + 1))
|
||||
/*!
|
||||
* \brief Maximum mwi_mailboxs string length.
|
||||
* \details
|
||||
* max_length = #mailboxes * (mbox_number + '@' + context + ',')
|
||||
* The last ',' is a null terminator instead.
|
||||
|
@ -382,6 +392,8 @@ struct sig_pri_mbox {
|
|||
const char *number;
|
||||
/*! \brief Mailbox context. */
|
||||
const char *context;
|
||||
/*! \brief Voicemail controlling number. */
|
||||
const char *vm_number;
|
||||
};
|
||||
#endif /* defined(HAVE_PRI_MWI) */
|
||||
|
||||
|
@ -429,6 +441,10 @@ struct sig_pri_span {
|
|||
/*! \brief TRUE if allow sending MCID request on this span. */
|
||||
unsigned int mcid_send:1;
|
||||
#endif /* defined(HAVE_PRI_MCID) */
|
||||
#if defined(HAVE_PRI_DATETIME_SEND)
|
||||
/*! \brief Configured date/time ie send policy option. */
|
||||
int datetime_send;
|
||||
#endif /* defined(HAVE_PRI_DATETIME_SEND) */
|
||||
int dialplan; /*!< Dialing plan */
|
||||
int localdialplan; /*!< Local dialing plan */
|
||||
int cpndialplan; /*!< Connected party dialing plan */
|
||||
|
@ -453,6 +469,12 @@ struct sig_pri_span {
|
|||
* \note String is split apart when span is started.
|
||||
*/
|
||||
char mwi_mailboxes[SIG_PRI_MAX_MWI_MAILBOX_STR];
|
||||
/*!
|
||||
* \brief Comma separated list of voicemail access controlling numbers for MWI.
|
||||
* \note Format: vm_number{,vm_number}
|
||||
* \note String is split apart when span is started.
|
||||
*/
|
||||
char mwi_vm_numbers[SIG_PRI_MAX_MWI_VM_NUMBER_STR];
|
||||
#endif /* defined(HAVE_PRI_MWI) */
|
||||
/*!
|
||||
* \brief Initial user tag for party id's sent from this device driver.
|
||||
|
@ -597,6 +619,9 @@ void sig_pri_chan_delete(struct sig_pri_chan *doomed);
|
|||
|
||||
int pri_is_up(struct sig_pri_span *pri);
|
||||
|
||||
struct mansession;
|
||||
int sig_pri_ami_show_spans(struct mansession *s, const char *show_cmd, struct sig_pri_span *pri, const int *dchannels, const char *action_id);
|
||||
|
||||
void sig_pri_cli_show_channels_header(int fd);
|
||||
void sig_pri_cli_show_channels(int fd, struct sig_pri_span *pri);
|
||||
void sig_pri_cli_show_spans(int fd, int span, struct sig_pri_span *pri);
|
||||
|
|
|
@ -697,6 +697,11 @@ void *ss7_linkset(void *data)
|
|||
if (p->call_level < SIG_SS7_CALL_LEVEL_ALERTING) {
|
||||
p->call_level = SIG_SS7_CALL_LEVEL_ALERTING;
|
||||
}
|
||||
sig_ss7_lock_owner(linkset, chanpos);
|
||||
if (p->owner) {
|
||||
ast_setstate(p->owner, AST_STATE_RINGING);
|
||||
ast_channel_unlock(p->owner);
|
||||
}
|
||||
sig_ss7_queue_control(linkset, chanpos, AST_CONTROL_RINGING);
|
||||
break;
|
||||
case CPG_EVENT_PROGRESS:
|
||||
|
@ -948,6 +953,11 @@ void *ss7_linkset(void *data)
|
|||
if (p->call_level < SIG_SS7_CALL_LEVEL_ALERTING) {
|
||||
p->call_level = SIG_SS7_CALL_LEVEL_ALERTING;
|
||||
}
|
||||
sig_ss7_lock_owner(linkset, chanpos);
|
||||
if (p->owner) {
|
||||
ast_setstate(p->owner, AST_STATE_RINGING);
|
||||
ast_channel_unlock(p->owner);
|
||||
}
|
||||
sig_ss7_queue_control(linkset, chanpos, AST_CONTROL_RINGING);
|
||||
}
|
||||
sig_ss7_unlock_private(p);
|
||||
|
|
|
@ -59,6 +59,9 @@
|
|||
#define DEFAULT_REGISTRATION_TIMEOUT 20
|
||||
#define DEFAULT_MAX_FORWARDS 70
|
||||
|
||||
#define DEFAULT_AUTHLIMIT 100
|
||||
#define DEFAULT_AUTHTIMEOUT 30
|
||||
|
||||
/* guard limit must be larger than guard secs */
|
||||
/* guard min must be < 1000, and should be >= 250 */
|
||||
#define EXPIRY_GUARD_SECS 15 /*!< How long before expiry do we reregister */
|
||||
|
@ -208,7 +211,10 @@
|
|||
#define DEFAULT_CALLEVENTS FALSE /*!< Extra manager SIP call events */
|
||||
#define DEFAULT_ALWAYSAUTHREJECT TRUE /*!< Don't reject authentication requests always */
|
||||
#define DEFAULT_AUTH_OPTIONS FALSE
|
||||
#define DEFAULT_AUTH_MESSAGE TRUE
|
||||
#define DEFAULT_ACCEPT_OUTOFCALL_MESSAGE TRUE
|
||||
#define DEFAULT_REGEXTENONQUALIFY FALSE
|
||||
#define DEFAULT_LEGACY_USEROPTION_PARSING FALSE
|
||||
#define DEFAULT_T1MIN 100 /*!< 100 MS for minimal roundtrip time */
|
||||
#define DEFAULT_MAX_CALL_BITRATE (384) /*!< Max bitrate for video */
|
||||
#ifndef DEFAULT_USERAGENT
|
||||
|
@ -591,7 +597,8 @@ enum t38state {
|
|||
T38_DISABLED = 0, /*!< Not enabled */
|
||||
T38_LOCAL_REINVITE, /*!< Offered from local - REINVITE */
|
||||
T38_PEER_REINVITE, /*!< Offered from peer - REINVITE */
|
||||
T38_ENABLED /*!< Negotiated (enabled) */
|
||||
T38_ENABLED, /*!< Negotiated (enabled) */
|
||||
T38_REJECTED /*!< Refused */
|
||||
};
|
||||
|
||||
/*! \brief Parameters to know status of transfer */
|
||||
|
@ -675,10 +682,13 @@ struct sip_settings {
|
|||
int allowguest; /*!< allow unauthenticated peers to connect? */
|
||||
int alwaysauthreject; /*!< Send 401 Unauthorized for all failing requests */
|
||||
int auth_options_requests; /*!< Authenticate OPTIONS requests */
|
||||
int auth_message_requests; /*!< Authenticate MESSAGE requests */
|
||||
int accept_outofcall_message; /*!< Accept MESSAGE outside of a call */
|
||||
int compactheaders; /*!< send compact sip headers */
|
||||
int allow_external_domains; /*!< Accept calls to external SIP domains? */
|
||||
int callevents; /*!< Whether we send manager events or not */
|
||||
int regextenonqualify; /*!< Whether to add/remove regexten when qualifying peers */
|
||||
int legacy_useroption_parsing; /*!< Whether to strip useroptions in URI via semicolons */
|
||||
int matchexternaddrlocally; /*!< Match externaddr/externhost setting against localnet setting */
|
||||
char regcontext[AST_MAX_CONTEXT]; /*!< Context for auto-extensions */
|
||||
unsigned int disallowed_methods; /*!< methods that we should never try to use */
|
||||
|
@ -743,6 +753,7 @@ struct sip_request {
|
|||
char debug; /*!< print extra debugging if non zero */
|
||||
char has_to_tag; /*!< non-zero if packet has To: tag */
|
||||
char ignore; /*!< if non-zero This is a re-transmit, ignore it */
|
||||
char authenticated; /*!< non-zero if this request was authenticated */
|
||||
ptrdiff_t header[SIP_MAX_HEADERS]; /*!< Array of offsets into the request string of each SIP header*/
|
||||
ptrdiff_t line[SIP_MAX_LINES]; /*!< Array of offsets into the request string of each SDP line*/
|
||||
struct ast_str *data;
|
||||
|
@ -959,6 +970,7 @@ struct sip_pvt {
|
|||
AST_STRING_FIELD(parkinglot); /*!< Parkinglot */
|
||||
AST_STRING_FIELD(engine); /*!< RTP engine to use */
|
||||
AST_STRING_FIELD(dialstring); /*!< The dialstring used to call this SIP endpoint */
|
||||
AST_STRING_FIELD(msg_body); /*!< Text for a MESSAGE body */
|
||||
);
|
||||
char via[128]; /*!< Via: header */
|
||||
int maxforwards; /*!< SIP Loop prevention */
|
||||
|
@ -1157,6 +1169,7 @@ struct sip_peer {
|
|||
AST_DECLARE_STRING_FIELDS(
|
||||
AST_STRING_FIELD(secret); /*!< Password for inbound auth */
|
||||
AST_STRING_FIELD(md5secret); /*!< Password in MD5 */
|
||||
AST_STRING_FIELD(description); /*!< Description of this peer */
|
||||
AST_STRING_FIELD(remotesecret); /*!< Remote secret (trunks, remote devices) */
|
||||
AST_STRING_FIELD(context); /*!< Default context for incoming calls */
|
||||
AST_STRING_FIELD(subscribecontext); /*!< Default context for subscriptions */
|
||||
|
|
|
@ -42,6 +42,27 @@ int parse_uri_full(char *uri, const char *scheme, char **user, char **pass,
|
|||
char *c = NULL;
|
||||
int error = 0;
|
||||
|
||||
/*
|
||||
* Initialize requested strings - some functions don't care if parse_uri fails
|
||||
* and will attempt to use string pointers passed into parse_uri even after a
|
||||
* parse_uri failure
|
||||
*/
|
||||
if (user) {
|
||||
*user = "";
|
||||
}
|
||||
if (pass) {
|
||||
*pass = "";
|
||||
}
|
||||
if (domain) {
|
||||
*domain = "";
|
||||
}
|
||||
if (headers) {
|
||||
*headers = "";
|
||||
}
|
||||
if (residue) {
|
||||
*residue = "";
|
||||
}
|
||||
|
||||
/* check for valid input */
|
||||
if (ast_strlen_zero(uri)) {
|
||||
return -1;
|
||||
|
@ -2253,10 +2274,7 @@ void free_via(struct sip_via *v)
|
|||
return;
|
||||
}
|
||||
|
||||
if (v->via) {
|
||||
ast_free(v->via);
|
||||
}
|
||||
|
||||
ast_free(v->via);
|
||||
ast_free(v);
|
||||
}
|
||||
|
||||
|
@ -2305,8 +2323,9 @@ struct sip_via *parse_via(const char *header)
|
|||
}
|
||||
v->sent_by = ast_skip_blanks(v->sent_by);
|
||||
|
||||
/* store the port */
|
||||
if ((parm = strchr(v->sent_by, ':'))) {
|
||||
/* store the port, we have to handle ipv6 addresses containing ':'
|
||||
* characters gracefully */
|
||||
if (((parm = strchr(v->sent_by, ']')) && *(++parm) == ':') || (parm = strchr(v->sent_by, ':'))) {
|
||||
char *endptr;
|
||||
|
||||
v->port = strtol(++parm, &endptr, 10);
|
||||
|
@ -2392,6 +2411,13 @@ AST_TEST_DEFINE(parse_via_test)
|
|||
.expected_maddr = "224.0.0.1",
|
||||
.expected_ttl = 1,
|
||||
};
|
||||
struct testdata t7 = {
|
||||
.in = "SIP/2.0/UDP [::1]:5060",
|
||||
.expected_protocol = "SIP/2.0/UDP",
|
||||
.expected_sent_by = "[::1]:5060",
|
||||
.expected_port = 5060,
|
||||
.expected_branch = "",
|
||||
};
|
||||
switch (cmd) {
|
||||
case TEST_INIT:
|
||||
info->name = "parse_via_test";
|
||||
|
@ -2411,6 +2437,7 @@ AST_TEST_DEFINE(parse_via_test)
|
|||
AST_LIST_INSERT_TAIL(&testdatalist, &t4, list);
|
||||
AST_LIST_INSERT_TAIL(&testdatalist, &t5, list);
|
||||
AST_LIST_INSERT_TAIL(&testdatalist, &t6, list);
|
||||
AST_LIST_INSERT_TAIL(&testdatalist, &t7, list);
|
||||
|
||||
|
||||
AST_LIST_TRAVERSE(&testdatalist, testdataptr, list) {
|
||||
|
|
|
@ -191,7 +191,6 @@ err:
|
|||
int sdp_crypto_process(struct sdp_crypto *p, const char *attr, struct ast_rtp_instance *rtp)
|
||||
{
|
||||
char *str = NULL;
|
||||
char *name = NULL;
|
||||
char *tag = NULL;
|
||||
char *suite = NULL;
|
||||
char *key_params = NULL;
|
||||
|
@ -211,7 +210,7 @@ int sdp_crypto_process(struct sdp_crypto *p, const char *attr, struct ast_rtp_in
|
|||
|
||||
str = ast_strdupa(attr);
|
||||
|
||||
name = strsep(&str, ":");
|
||||
strsep(&str, ":");
|
||||
tag = strsep(&str, " ");
|
||||
suite = strsep(&str, " ");
|
||||
key_params = strsep(&str, " ");
|
||||
|
|
|
@ -56,6 +56,20 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
|||
#define G723_SAMPLES 240
|
||||
#define G729_SAMPLES 160
|
||||
|
||||
#ifndef DAHDI_FORMAT_MAX_AUDIO
|
||||
#define DAHDI_FORMAT_G723_1 (1 << 0)
|
||||
#define DAHDI_FORMAT_GSM (1 << 1)
|
||||
#define DAHDI_FORMAT_ULAW (1 << 2)
|
||||
#define DAHDI_FORMAT_ALAW (1 << 3)
|
||||
#define DAHDI_FORMAT_G726 (1 << 4)
|
||||
#define DAHDI_FORMAT_ADPCM (1 << 5)
|
||||
#define DAHDI_FORMAT_SLINEAR (1 << 6)
|
||||
#define DAHDI_FORMAT_LPC10 (1 << 7)
|
||||
#define DAHDI_FORMAT_G729A (1 << 8)
|
||||
#define DAHDI_FORMAT_SPEEX (1 << 9)
|
||||
#define DAHDI_FORMAT_ILBC (1 << 10)
|
||||
#endif
|
||||
|
||||
static struct channel_usage {
|
||||
int total;
|
||||
int encoders;
|
||||
|
@ -598,13 +612,13 @@ static int find_transcoders(void)
|
|||
* module. Also, do not allow direct ulaw/alaw to complex
|
||||
* codec translation, since that will prevent the generic PLC
|
||||
* functions from working. */
|
||||
if (info.dstfmts & (AST_FORMAT_ULAW | AST_FORMAT_ALAW)) {
|
||||
info.dstfmts |= AST_FORMAT_SLINEAR;
|
||||
info.dstfmts &= ~(AST_FORMAT_ULAW | AST_FORMAT_ALAW);
|
||||
if (info.dstfmts & (DAHDI_FORMAT_ULAW | DAHDI_FORMAT_ALAW)) {
|
||||
info.dstfmts |= DAHDI_FORMAT_SLINEAR;
|
||||
info.dstfmts &= ~(DAHDI_FORMAT_ULAW | DAHDI_FORMAT_ALAW);
|
||||
}
|
||||
if (info.srcfmts & (AST_FORMAT_ULAW | AST_FORMAT_ALAW)) {
|
||||
info.srcfmts |= AST_FORMAT_SLINEAR;
|
||||
info.srcfmts &= ~(AST_FORMAT_ULAW | AST_FORMAT_ALAW);
|
||||
if (info.srcfmts & (DAHDI_FORMAT_ULAW | DAHDI_FORMAT_ALAW)) {
|
||||
info.srcfmts |= DAHDI_FORMAT_SLINEAR;
|
||||
info.srcfmts &= ~(DAHDI_FORMAT_ULAW | DAHDI_FORMAT_ALAW);
|
||||
}
|
||||
|
||||
build_translators(&map, info.dstfmts, info.srcfmts);
|
||||
|
|
|
@ -71,7 +71,12 @@ static int resamp_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
|
|||
{
|
||||
SpeexResamplerState *resamp_pvt = pvt->pvt;
|
||||
unsigned int out_samples = (OUTBUF_SIZE / sizeof(int16_t)) - pvt->samples;
|
||||
unsigned int in_samples = f->samples;
|
||||
unsigned int in_samples;
|
||||
|
||||
if (!f->datalen) {
|
||||
return -1;
|
||||
}
|
||||
in_samples = f->datalen / 2;
|
||||
|
||||
speex_resampler_process_int(resamp_pvt,
|
||||
0,
|
||||
|
|
|
@ -143,7 +143,7 @@ extern struct {
|
|||
/* Local variables */
|
||||
integer pbar;
|
||||
real sbar;
|
||||
integer path[2], iptr, i__, j;
|
||||
integer iptr, i__, j;
|
||||
real alpha, minsc, maxsc;
|
||||
|
||||
/* Arguments */
|
||||
|
@ -389,7 +389,6 @@ n*/
|
|||
for (i__ = 1; i__ <= 2; ++i__) {
|
||||
j = j % 2 + 1;
|
||||
*pitch = p[*pitch + j * 60 - 61];
|
||||
path[i__ - 1] = *pitch;
|
||||
}
|
||||
|
||||
/* The following statement subtracts one from IPOINT, mod DEPTH. I
|
||||
|
|
|
@ -6,12 +6,54 @@
|
|||
;
|
||||
|
||||
[general]
|
||||
; There is only a single option that may be defined in this file.
|
||||
; The cc_max_requests option is a global limit on the number of
|
||||
; CC requests that may be in the Asterisk system at any time.
|
||||
;
|
||||
;cc_max_requests = 20
|
||||
;
|
||||
; The cc_STATE_devstate variables listed below can be used to change the
|
||||
; default mapping of the internal state machine tracking the state of
|
||||
; call completion to an Asterisk Device State value. The acceptable values
|
||||
; that can be provided are as follows, with a description of what the
|
||||
; equivalent device BLF that this maps to:
|
||||
;
|
||||
; UNKNOWN ; Device is valid but channel didn't know state
|
||||
; NOT_INUSE ; Device is not used
|
||||
; INUSE ; Device is in use
|
||||
; BUSY ; Device is busy
|
||||
; INVALID ; Device is invalid
|
||||
; UNAVAILABLE ; Device is unavailable
|
||||
; RINGING ; Device is ringing
|
||||
; RINGINUSE ; Device is ringing *and* in use
|
||||
; ONHOLD ; Device is on hold
|
||||
;
|
||||
; These states are used to generate DEVICE_STATE information that can be
|
||||
; included with Asterisk hints for phones to subscribe to the state information
|
||||
; or dialplan to check the state using the EXTENSION_STATE() function or
|
||||
; the DEVICE_STATE() function.
|
||||
;
|
||||
; The states are in the format of: "ccss:TECH/ID" so an example of device
|
||||
; SIP/3000 making a CallCompletionRequest() could be checked by looking at
|
||||
; DEVICE_STATE(ccss:SIP/3000) or an Asterisk Hint could be generated such as
|
||||
;
|
||||
; [hint-context]
|
||||
; exten => *843000,hint,ccss:SIP/3000
|
||||
;
|
||||
; and then accessed with EXTENSION_STATE(*843000@hint-context)
|
||||
; or subscribed to with a BLF button on a phone.
|
||||
;
|
||||
; The available state mapping and default values are:
|
||||
;
|
||||
; cc_available_devstate = NOT_INUSE
|
||||
; cc_offered_devstate = NOT_INUSE
|
||||
; cc_caller_requested_devstate = NOT_INUSE
|
||||
; cc_active_devstate = INUSE
|
||||
; cc_callee_ready_devstate = INUSE
|
||||
; cc_caller_busy_devstate = ONHOLD
|
||||
; cc_recalling_devstate = RINGING
|
||||
; cc_complete_devstate = NOT_INUSE
|
||||
; cc_failed_devstate = NOT_INUSE
|
||||
|
||||
;
|
||||
;============================================
|
||||
; PLEASE READ THIS!!!
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
; Channel Event Logging is a mechanism to provide fine-grained event information
|
||||
; that can be used to generate billing information. Such event information can
|
||||
; be recorded to databases and files via pluggable backend modules.
|
||||
; be recorded to various backend modules.
|
||||
;
|
||||
|
||||
[general]
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
; amaflag (an int)
|
||||
; userfield
|
||||
; peer
|
||||
|
||||
; extra
|
||||
|
||||
[global]
|
||||
;hostname=localhost
|
||||
|
|
|
@ -236,6 +236,19 @@
|
|||
;
|
||||
;mcid_send=yes
|
||||
|
||||
; Send ISDN date/time IE in CONNECT message option. Only valid on NT spans.
|
||||
;
|
||||
; no: Do not send date/time IE in CONNECT message.
|
||||
; date: Send date only.
|
||||
; date_hh Send date and hour.
|
||||
; date_hhmm Send date, hour, and minute.
|
||||
; date_hhmmss Send date, hour, minute, and second.
|
||||
;
|
||||
; Default is an empty string which lets libpri pick the default
|
||||
; date/time IE send policy.
|
||||
;
|
||||
;datetime_send=
|
||||
|
||||
; Allow inband audio (progress) when a call is DISCONNECTed by the far end of a PRI
|
||||
;
|
||||
;inbanddisconnect=yes
|
||||
|
@ -581,13 +594,28 @@ callwaiting=yes
|
|||
; Allow incoming ISDN call waiting calls.
|
||||
; A call waiting call is a SETUP message with no B channel selected.
|
||||
;allow_call_waiting_calls=no
|
||||
;
|
||||
|
||||
; Configure the ISDN span to indicate MWI for the list of mailboxes.
|
||||
; You can give a comma separated list of up to 8 mailboxes per span.
|
||||
; An empty list disables MWI.
|
||||
; The default is an empty list.
|
||||
;mwi_mailboxes=mailbox_number[@context]{,mailbox_number[@context]}
|
||||
;
|
||||
; Configure the ISDN span voicemail numbers for MWI mailboxes. What number
|
||||
; to call for a user to retrieve voicemail messages.
|
||||
;
|
||||
; You can give a comma separated list of numbers. The position of the number
|
||||
; corresponds to the position in mwi_mailboxes. If a position is empty then
|
||||
; the last number is reused.
|
||||
;
|
||||
; For example:
|
||||
; mwi_vm_numbers=700,,800,,900
|
||||
; is equivalent to:
|
||||
; mwi_vm_numbers=700,700,800,800,900
|
||||
;
|
||||
; The default is no number.
|
||||
;mwi_vm_numbers=
|
||||
|
||||
; Whether or not restrict outgoing caller ID (will be sent as ANI only, not
|
||||
; available for the user)
|
||||
; Mostly use with FXS ports
|
||||
|
@ -820,6 +848,11 @@ pickupgroup=1
|
|||
;
|
||||
;useincomingcalleridondahditransfer = yes
|
||||
;
|
||||
; Add a description for the channel which can be shown through the Asterisk
|
||||
; console when executing the 'dahdi show channels' command is run.
|
||||
;
|
||||
;description=Phone located in lobby
|
||||
;
|
||||
; AMA flags affects the recording of Call Detail Records. If specified
|
||||
; it may be 'default', 'omit', 'billing', or 'documentation'.
|
||||
;
|
||||
|
@ -1068,10 +1101,13 @@ pickupgroup=1
|
|||
;
|
||||
;
|
||||
;callerid="Green Phone"<(256) 428-6121>
|
||||
;description=Reception Phone ; add a description for 'dahdi show channels'
|
||||
;channel => 1
|
||||
;callerid="Black Phone"<(256) 428-6122>
|
||||
;description=Courtesy Phone
|
||||
;channel => 2
|
||||
;callerid="CallerID Phone" <(630) 372-1564>
|
||||
;description= ; reset the description for following channels
|
||||
;channel => 3
|
||||
;callerid="Pac Tel Phone" <(256) 428-6124>
|
||||
;channel => 4
|
||||
|
|
|
@ -0,0 +1,302 @@
|
|||
[general]
|
||||
; The general section of this config
|
||||
; is not currently used, but reserved
|
||||
; for future use.
|
||||
|
||||
;
|
||||
; --- Default Information ---
|
||||
; The default_user and default_bridge sections are applied
|
||||
; automatically to all ConfBridge instances invoked without
|
||||
; a user, or bridge argument. No menu is applied by default.
|
||||
;
|
||||
|
||||
; --- ConfBridge User Profile Options ---
|
||||
[default_user]
|
||||
type=user
|
||||
;admin=yes ; Sets if the user is an admin or not. Off by default.
|
||||
;marked=yes ; Sets if this is a marked user or not. Off by default.
|
||||
;startmuted=yes; Sets if all users should start out muted. Off by default
|
||||
;music_on_hold_when_empty=yes ; Sets whether MOH should be played when only
|
||||
; one person is in the conference or when the
|
||||
; the user is waiting on a marked user to enter
|
||||
; the conference. Off by default.
|
||||
;music_on_hold_class=default ; The MOH class to use for this user.
|
||||
;quiet=yes ; When enabled enter/leave prompts and user intros are not played.
|
||||
; There are some prompts, such as the prompt to enter a PIN number,
|
||||
; that must be played regardless of what this option is set to.
|
||||
; Off by default
|
||||
;announce_user_count=yes ; Sets if the number of users should be announced to the
|
||||
; caller. Off by default.
|
||||
;announce_user_count_all=yes ; Sets if the number of users should be announced to
|
||||
; all the other users in the conference when someone joins.
|
||||
; This option can be either set to 'yes' or a number.
|
||||
; When set to a number, the announcement will only occur
|
||||
; once the user count is above the specified number.
|
||||
;announce_only_user=yes ; Sets if the only user announcement should be played
|
||||
; when a channel enters a empty conference. On by default.
|
||||
;wait_marked=yes ; Sets if the user must wait for a marked user to enter before
|
||||
; joining the conference. Off by default.
|
||||
;end_marked=yes ; This option will kick every user with this option set in their
|
||||
; user profile after the last Marked user exists the conference.
|
||||
|
||||
;dsp_drop_silence=yes ; This option drops what Asterisk detects as silence from
|
||||
; entering into the bridge. Enabling this option will drastically
|
||||
; improve performance and help remove the buildup of background
|
||||
; noise from the conference. Highly recommended for large conferences
|
||||
; due to its performance enhancements.
|
||||
|
||||
;dsp_talking_threshold=128 ; The time in milliseconds of sound above what the dsp has
|
||||
; established as base line silence for a user before a user
|
||||
; is considered to be talking. This value affects several
|
||||
; operations and should not be changed unless the impact on
|
||||
; call quality is fully understood.
|
||||
;
|
||||
; What this value affects internally:
|
||||
;
|
||||
; 1. Audio is only mixed out of a user's incoming audio stream
|
||||
; if talking is detected. If this value is set too
|
||||
; loose the user will hear themselves briefly each
|
||||
; time they begin talking until the dsp has time to
|
||||
; establish that they are in fact talking.
|
||||
; 2. When talk detection AMI events are enabled, this value
|
||||
; determines when talking has begun which results in
|
||||
; an AMI event to fire. If this value is set too tight
|
||||
; AMI events may be falsely triggered by variants in
|
||||
; room noise.
|
||||
; 3. The drop_silence option depends on this value to determine
|
||||
; when the user's audio should be mixed into the bridge
|
||||
; after periods of silence. If this value is too loose
|
||||
; the beginning of a user's speech will get cut off as they
|
||||
; transition from silence to talking.
|
||||
;
|
||||
; By default this value is 160 ms. Valid values are 1 through 2^31
|
||||
|
||||
;dsp_silence_threshold=2000 ; The time in milliseconds of sound falling within the what
|
||||
; the dsp has established as baseline silence before a user
|
||||
; is considered be silent. This value affects several
|
||||
; operations and should not be changed unless the impact
|
||||
; on call quality is fully understood.
|
||||
;
|
||||
; What this value affects internally:
|
||||
;
|
||||
; 1. When talk detection AMI events are enabled, this value
|
||||
; determines when the user has stopped talking after a
|
||||
; period of talking. If this value is set too low
|
||||
; AMI events indicating the user has stopped talking
|
||||
; may get falsely sent out when the user briefly pauses
|
||||
; during mid sentence.
|
||||
; 2. The drop_silence option depends on this value to
|
||||
; determine when the user's audio should begin to be
|
||||
; dropped from the conference bridge after the user
|
||||
; stops talking. If this value is set too low the user's
|
||||
; audio stream may sound choppy to the other participants.
|
||||
; This is caused by the user transitioning constantly from
|
||||
; silence to talking during mid sentence.
|
||||
;
|
||||
; The best way to approach this option is to set it slightly above
|
||||
; the maximum amount of ms of silence a user may generate during
|
||||
; natural speech.
|
||||
;
|
||||
; By default this value is 2500ms. Valid values are 1 through 2^31
|
||||
|
||||
;talk_detection_events=yes ; This option sets whether or not notifications of when a user
|
||||
; begins and ends talking should be sent out as events over AMI.
|
||||
; By default this option is off.
|
||||
|
||||
;denoise=yes ; Sets whether or not a denoise filter should be applied
|
||||
; to the audio before mixing or not. Off by default. Requires
|
||||
; codec_speex to be built and installed. Do not confuse this option
|
||||
; with drop_silence. Denoise is useful if there is a lot of background
|
||||
; noise for a user as it attempts to remove the noise while preserving
|
||||
; the speech. This option does NOT remove silence from being mixed into
|
||||
; the conference and does come at the cost of a slight performance hit.
|
||||
|
||||
;jitterbuffer=yes ; Enabling this option places a jitterbuffer on the user's audio stream
|
||||
; before audio mixing is performed. This is highly recommended but will
|
||||
; add a slight delay to the audio. This option is using the JITTERBUFFER
|
||||
; dialplan function's default adaptive jitterbuffer. For a more fine tuned
|
||||
; jitterbuffer, disable this option and use the JITTERBUFFER dialplan function
|
||||
; on the user before entering the ConfBridge application.
|
||||
|
||||
;pin=1234 ; Sets if this user must enter a PIN number before entering
|
||||
; the conference. The PIN will be prompted for.
|
||||
;announce_join_leave=yes ; When enabled, this option will prompt the user for a
|
||||
; name when entering the conference. After the name is
|
||||
; recorded, it will be played as the user enters and exists
|
||||
; the conference. This option is off by default.
|
||||
;dtmf_passthrough=yes ; Sets whether or not DTMF should pass through the conference.
|
||||
; This option is off by default.
|
||||
|
||||
; --- ConfBridge Bridge Profile Options ---
|
||||
[default_bridge]
|
||||
type=bridge
|
||||
;max_members=50 ; This option limits the number of participants for a single
|
||||
; conference to a specific number. By default conferences
|
||||
; have no participant limit. After the limit is reached, the
|
||||
; conference will be locked until someone leaves. Note however
|
||||
; that an Admin user will always be alowed to join the conference
|
||||
; regardless if this limit is reached or not.
|
||||
|
||||
;record_conference=yes ; Records the conference call starting when the first user
|
||||
; enters the room, and ending when the last user exits the room.
|
||||
; The default recorded filename is
|
||||
; 'confbridge-<name of conference bridge>-<start time>.wav
|
||||
; and the default format is 8khz slinear. This file will be
|
||||
; located in the configured monitoring directory in asterisk.conf.
|
||||
|
||||
;record_file=</path/to/file> ; When record_conference is set to yes, the specific name of the
|
||||
; record file can be set using this option. Note that since multiple
|
||||
; conferences may use the same bridge profile, this may cause issues
|
||||
; depending on the configuration. It is recommended to only use this
|
||||
; option dynamically with the CONFBRIDGE() dialplan function. This
|
||||
; allows the record name to be specified and a unique name to be chosen.
|
||||
; By default, the record_file is stored in Asterisk's spool/monitor directory
|
||||
; with a unique filename starting with the 'confbridge' prefix.
|
||||
|
||||
;internal_sample_rate=auto ; Sets the internal native sample rate the
|
||||
; conference is mixed at. This is set to automatically
|
||||
; adjust the sample rate to the best quality by default.
|
||||
; Other values can be anything from 8000-192000. If a
|
||||
; sample rate is set that Asterisk does not support, the
|
||||
; closest sample rate Asterisk does support to the one requested
|
||||
; will be used.
|
||||
|
||||
;mixing_interval=40 ; Sets the internal mixing interval in milliseconds for the bridge. This
|
||||
; number reflects how tight or loose the mixing will be for the conference.
|
||||
; In order to improve performance a larger mixing interval such as 40ms may
|
||||
; be chosen. Using a larger mixing interval comes at the cost of introducing
|
||||
; larger amounts of delay into the bridge. Valid values here are 10, 20, 40,
|
||||
; or 80. By default 20ms is used.
|
||||
|
||||
; All sounds in the conference are customizable using the bridge profile options below.
|
||||
; Simply state the option followed by the filename or full path of the filename after
|
||||
; the option. Example: sound_had_joined=conf-hasjoin This will play the conf-hasjoin
|
||||
; sound file found in the sounds directory when announcing someone's name is joining the
|
||||
; conference.
|
||||
|
||||
;sound_join ; The sound played to everyone when someone enters the conference.
|
||||
;sound_leave ; The sound played to everyone when someone leaves the conference.
|
||||
;sound_has_joined ; The sound played before announcing someone's name has
|
||||
; joined the conference. This is used for user intros.
|
||||
; Example "_____ has joined the conference"
|
||||
;sound_has_left ; The sound played when announcing someone's name has
|
||||
; left the conference. This is used for user intros.
|
||||
; Example "_____ has left the conference"
|
||||
;sound_kicked ; The sound played to a user who has been kicked from the conference.
|
||||
;sound_muted ; The sound played when the mute option it toggled on.
|
||||
;sound_unmuted ; The sound played when the mute option it toggled off.
|
||||
;sound_only_person ; The sound played when the user is the only person in the conference.
|
||||
;sound_only_one ; The sound played to a user when there is only one other
|
||||
; person is in the conference.
|
||||
;sound_there_are ; The sound played when announcing how many users there
|
||||
; are in a conference.
|
||||
;sound_other_in_party; ; This file is used in conjunction with 'sound_there_are"
|
||||
; when announcing how many users there are in the conference.
|
||||
; The sounds are stringed together like this.
|
||||
; "sound_there_are" <number of participants> "sound_other_in_party"
|
||||
;sound_place_into_conference ; The sound played when someone is placed into the conference
|
||||
; after waiting for a marked user.
|
||||
;sound_wait_for_leader ; The sound played when a user is placed into a conference that
|
||||
; can not start until a marked user enters.
|
||||
;sound_leader_has_left ; The sound played when the last marked user leaves the conference.
|
||||
;sound_get_pin ; The sound played when prompting for a conference pin number.
|
||||
;sound_invalid_pin ; The sound played when an invalid pin is entered too many times.
|
||||
;sound_locked ; The sound played to a user trying to join a locked conference.
|
||||
;sound_locked_now ; The sound played to an admin after toggling the conference to locked mode.
|
||||
;sound_unlocked_now; The sound played to an admin after toggling the conference to unlocked mode.
|
||||
;sound_error_menu ; The sound played when an invalid menu option is entered.
|
||||
|
||||
; --- ConfBridge Menu Options ---
|
||||
; The ConfBridge application also has the ability to
|
||||
; apply custom DTMF menus to each channel using the
|
||||
; application. Like the User and Bridge profiles
|
||||
; a menu is passed in to ConfBridge as an argument in
|
||||
; the dialplan.
|
||||
;
|
||||
; Below is a list of menu actions that can be assigned
|
||||
; to a DTMF sequence.
|
||||
;
|
||||
; A single DTMF sequence can have multiple actions associated with it. This is
|
||||
; accomplished by stringing the actions together and using a ',' as the delimiter.
|
||||
; Example: Both listening and talking volume is reset when '5' is pressed.
|
||||
; 5=reset_talking_volume, reset_listening_volume
|
||||
;
|
||||
; playback(<name of audio file>&<name of audio file>)
|
||||
; Playback will play back an audio file to a channel
|
||||
; and then immediately return to the conference.
|
||||
; This file can not be interupted by DTMF.
|
||||
; Mutliple files can be chained together using the
|
||||
; '&' character.
|
||||
; playback_and_continue(<name of playback prompt>&<name of playback prompt>)
|
||||
; playback_and_continue will
|
||||
; play back a prompt while continuing to
|
||||
; collect the dtmf sequence. This is useful
|
||||
; when using a menu prompt that describes all
|
||||
; the menu options. Note however that any DTMF
|
||||
; during this action will terminate the prompts
|
||||
; playback. Prompt files can be chained together
|
||||
; using the '&' character as a delimiter.
|
||||
; toggle_mute ; Toggle turning on and off mute. Mute will make the user silent
|
||||
; to everyone else, but the user will still be able to listen in.
|
||||
; continue to collect the dtmf sequence.
|
||||
; no_op ; This action does nothing (No Operation). Its only real purpose exists for
|
||||
; being able to reserve a sequence in the config as a menu exit sequence.
|
||||
; decrease_listening_volume ; Decreases the channel's listening volume.
|
||||
; increase_listening_volume ; Increases the channel's listening volume.
|
||||
; reset_listening_volume ; Reset channel's listening volume to default level.
|
||||
|
||||
; decrease_talking_volume ; Decreases the channel's talking volume.
|
||||
; increase_talking_volume ; Icreases the channel's talking volume.
|
||||
; reset_talking_volume ; Reset channel's talking volume to default level.
|
||||
;
|
||||
; dialplan_exec(context,exten,priority) ; The dialplan_exec action allows a user
|
||||
; to escape from the conference and execute
|
||||
; commands in the dialplan. Once the dialplan
|
||||
; exits the user will be put back into the
|
||||
; conference. The possibilities are endless!
|
||||
; leave_conference ; This action allows a user to exit the conference and continue
|
||||
; execution in the dialplan.
|
||||
;
|
||||
; admin_kick_last ; This action allows an Admin to kick the last participant from the
|
||||
; conference. This action will only work for admins which allows
|
||||
; a single menu to be used for both users and admins.
|
||||
;
|
||||
; admin_toggle_conference_lock ; This action allows an Admin to toggle locking and
|
||||
; unlocking the conference. Non admins can not use
|
||||
; this action even if it is in their menu.
|
||||
|
||||
[sample_user_menu]
|
||||
type=menu
|
||||
*=playback_and_continue(conf-usermenu)
|
||||
*1=toggle_mute
|
||||
1=toggle_mute
|
||||
*4=decrease_listening_volume
|
||||
4=decrease_listening_volume
|
||||
*6=increase_listening_volume
|
||||
6=increase_listening_volume
|
||||
*7=decrease_talking_volume
|
||||
7=decrease_talking_volume
|
||||
*8=no_op
|
||||
8=no_op
|
||||
*9=increase_talking_volume
|
||||
9=increase_talking_volume
|
||||
|
||||
[sample_admin_menu]
|
||||
type=menu
|
||||
*=playback_and_continue(conf-adminmenu)
|
||||
*1=toggle_mute
|
||||
1=toggle_mute
|
||||
*2=admin_toggle_conference_lock ; only applied to admin users
|
||||
2=admin_toggle_conference_lock ; only applied to admin users
|
||||
*3=admin_kick_last ; only applied to admin users
|
||||
3=admin_kick_last ; only applied to admin users
|
||||
*4=decrease_listening_volume
|
||||
4=decrease_listening_volume
|
||||
*6=increase_listening_volume
|
||||
6=increase_listening_volume
|
||||
*7=decrease_talking_volume
|
||||
7=decrease_talking_volume
|
||||
*8=no_op
|
||||
8=no_op
|
||||
*9=increase_talking_volume
|
||||
9=increase_talking_volume
|
|
@ -88,12 +88,14 @@ TRUNKMSD = 1
|
|||
--
|
||||
-- More examples can be found below.
|
||||
--
|
||||
-- Before starting long running operations, an autoservice should be started
|
||||
-- using the autoservice_start() function. This autoservice will automatically
|
||||
-- be stopped before executing applications and dialplan functions and will be
|
||||
-- restarted afterwards. The autoservice can be stopped using
|
||||
-- autoservice_stop() and the autoservice_status() function will return true if
|
||||
-- an autoservice is currently running.
|
||||
-- An autoservice is automatically run while lua code is executing. The
|
||||
-- autoservice can be stopped and restarted using the autoservice_stop() and
|
||||
-- autoservice_start() functions. The autservice should be running before
|
||||
-- starting long running operations. The autoservice will automatically be
|
||||
-- stopped before executing applications and dialplan functions and will be
|
||||
-- restarted afterwards. The autoservice_status() function can be used to
|
||||
-- check the current status of the autoservice and will return true if an
|
||||
-- autoservice is currently running.
|
||||
--
|
||||
|
||||
function outgoing_local(c, e)
|
||||
|
|
|
@ -83,6 +83,9 @@ context => parkedcalls ; Which context parked calls are in (default parking lot
|
|||
; You can set parkinglot with the CHANNEL dialplan function
|
||||
; or by setting 'parkinglot' directly in the channel configuration file.
|
||||
;
|
||||
; (Note: Leading '0's and any non-numerical characters on parkpos extensions
|
||||
; will be ignored. Parkext on the other hand can be any string.)
|
||||
;
|
||||
;[parkinglot_edvina]
|
||||
;context => edvinapark
|
||||
;parkext => 799
|
||||
|
|
|
@ -34,6 +34,11 @@ bindaddr=127.0.0.1
|
|||
;
|
||||
;prefix=asterisk
|
||||
;
|
||||
; sessionlimit specifies the maximum number of httpsessions that will be
|
||||
; allowed to exist at any given time. (default: 100)
|
||||
;
|
||||
;sessionlimit=100
|
||||
;
|
||||
; Whether Asterisk should serve static content from http-static
|
||||
; Default is no.
|
||||
;
|
||||
|
|
|
@ -504,6 +504,7 @@ type=peer
|
|||
username=asterisk
|
||||
secret=supersecret
|
||||
host=216.207.245.47
|
||||
description=Demo System At Digium ; Description of this peer, as listed by 'iax2 show peers'
|
||||
;sendani=no
|
||||
;host=asterisk.linux-support.net
|
||||
;port=5036
|
||||
|
@ -544,6 +545,7 @@ host=216.207.245.47
|
|||
;[biggateway]
|
||||
;type=peer
|
||||
;host=192.168.0.1
|
||||
;description=Gateway to PSTN
|
||||
;context=*
|
||||
;secret=myscret
|
||||
;trunk=yes ; Use IAX2 trunking with this host
|
||||
|
|
|
@ -34,3 +34,6 @@
|
|||
; Messages stored longer than this value will be deleted by Asterisk.
|
||||
; This option applies to incoming messages only, which are intended to
|
||||
; be processed by the JABBER_RECEIVE dialplan function.
|
||||
;sendtodialplan=yes ; Send incoming messages into the dialplan. Off by default.
|
||||
;context=messages ; Dialplan context to send incoming messages to. If not set,
|
||||
; "default" will be used.
|
||||
|
|
|
@ -318,6 +318,8 @@ monitor-type = MixMonitor
|
|||
;queue-callswaiting = queue-callswaiting
|
||||
; ("The current est. holdtime is")
|
||||
;queue-holdtime = queue-holdtime
|
||||
; ("minute.")
|
||||
;queue-minute = queue-minute
|
||||
; ("minutes.")
|
||||
;queue-minutes = queue-minutes
|
||||
; ("seconds.")
|
||||
|
|
|
@ -202,6 +202,16 @@ tcpbindaddr=0.0.0.0 ; IP address for TCP server to bind to (0.0.0.0
|
|||
; For details how to construct a certificate for SIP see
|
||||
; http://tools.ietf.org/html/draft-ietf-sip-domain-certs
|
||||
|
||||
;tcpauthtimeout = 30 ; tcpauthtimeout specifies the maximum number
|
||||
; of seconds a client has to authenticate. If
|
||||
; the client does not authenticate beofre this
|
||||
; timeout expires, the client will be
|
||||
; disconnected. (default: 30 seconds)
|
||||
|
||||
;tcpauthlimit = 100 ; tcpauthlimit specifies the maximum number of
|
||||
; unauthenticated sessions that will be allowed
|
||||
; to connect at any given time. (default: 100)
|
||||
|
||||
srvlookup=yes ; Enable DNS SRV lookups on outbound calls
|
||||
; Note: Asterisk only uses the first host
|
||||
; in SRV records
|
||||
|
@ -375,6 +385,16 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls
|
|||
;auth_options_requests = yes ; Enabling this option will authenticate OPTIONS requests just like
|
||||
; INVITE requests are. By default this option is disabled.
|
||||
|
||||
;accept_outofcall_message = no ; Disable this option to reject all MESSAGE requests outside of a
|
||||
; call. By default, this option is enabled. When enabled, MESSAGE
|
||||
; requests are passed in to the dialplan.
|
||||
|
||||
;auth_message_requests = yes ; Enabling this option will authenticate MESSAGE requests.
|
||||
; By default this option is enabled. However, it can be disabled
|
||||
; should an application desire to not load the Asterisk server with
|
||||
; doing authentication and implement end to end security in the
|
||||
; message body.
|
||||
|
||||
;g726nonstandard = yes ; If the peer negotiates G726-32 audio, use AAL2 packing
|
||||
; order instead of RFC3551 packing order (this is required
|
||||
; for Sipura and Grandstream ATAs, among others). This is
|
||||
|
@ -422,6 +442,14 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls
|
|||
; If you have qualify on and the peer becomes unreachable
|
||||
; this setting will enforce inactivation of the regexten
|
||||
; extension for the peer
|
||||
;legacy_useroption_parsing=yes ; Default "no" ; If you have this option enabled and there are semicolons
|
||||
; in the user field of a sip URI, the field be truncated
|
||||
; at the first semicolon seen. This effectively makes
|
||||
; semicolon a non-usable character for peer names, extensions,
|
||||
; and maybe other, less tested things. This can be useful
|
||||
; for improving compatability with devices that like to use
|
||||
; user options for whatever reason. The behavior is similar to
|
||||
; how SIP URI's were typically handled in 1.6.2, hence the name.
|
||||
|
||||
; The shrinkcallerid function removes '(', ' ', ')', non-trailing '.', and '-' not
|
||||
; in square brackets. For example, the caller id value 555.5555 becomes 5555555
|
||||
|
@ -1100,6 +1128,7 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls
|
|||
; use_q850_reason
|
||||
; maxforwards
|
||||
; encryption
|
||||
; description ; Used to provide a description of the peer in console output
|
||||
|
||||
;[sip_proxy]
|
||||
; For incoming calls only. Example: FWD (Free World Dialup)
|
||||
|
@ -1195,6 +1224,7 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls
|
|||
;context=from-sip ; Where to start in the dialplan when this phone calls
|
||||
;callerid=John Doe <1234> ; Full caller ID, to override the phones config
|
||||
; on incoming calls to Asterisk
|
||||
;description=Courtesy Phone ; Description of the peer. Shown when doing 'sip show peers'.
|
||||
;host=192.168.0.23 ; we have a static but private IP address
|
||||
; No registration allowed
|
||||
;nat=no ; there is not NAT between phone and Asterisk
|
||||
|
|
|
@ -44,7 +44,7 @@ Event=>report
|
|||
Event=>check-sync\;reboot=false
|
||||
|
||||
[snom-reboot]
|
||||
Event=>reboot
|
||||
Event=>check-sync\;reboot=true
|
||||
|
||||
; Cisco
|
||||
|
||||
|
|
|
@ -9,6 +9,15 @@ dateformat=M-D-Y ; M,D,Y in any order (6 chars max)
|
|||
; Use M for month, D for day, Y for year, A for 12-hour time.
|
||||
keepalive=120
|
||||
|
||||
;authtimeout = 30 ; authtimeout specifies the maximum number of seconds a
|
||||
; client has to authenticate. If the client does not
|
||||
; authenticate beofre this timeout expires, the client
|
||||
; will be disconnected. (default: 30 seconds)
|
||||
|
||||
;authlimit = 50 ; authlimit specifies the maximum number of
|
||||
; unauthenticated sessions that will be allowed to
|
||||
; connect at any given time. (default: 50)
|
||||
|
||||
;vmexten=8500 ; Systemwide voicemailmain pilot number
|
||||
; It must be in the same context as the calling
|
||||
; device/line
|
||||
|
|
|
@ -87,6 +87,8 @@ pickupgroup = 1
|
|||
|
||||
;[6000]
|
||||
;fullname = Joe User
|
||||
;description = Courtesy Phone In Lobby ; Used to provide a description of the
|
||||
; peer in console output
|
||||
;email = joe@foo.bar
|
||||
;secret = 1234
|
||||
;dahdichan = 1
|
||||
|
|
33
configure.ac
33
configure.ac
|
@ -415,6 +415,8 @@ AST_EXT_LIB_SETUP([PGSQL], [PostgreSQL], [postgres])
|
|||
AST_EXT_LIB_SETUP([POPT], [popt], [popt])
|
||||
AST_EXT_LIB_SETUP([PORTAUDIO], [PortAudio], [portaudio])
|
||||
AST_EXT_LIB_SETUP([PRI], [ISDN PRI], [pri])
|
||||
AST_EXT_LIB_SETUP_DEPENDENT([PRI_DATETIME_SEND], [ISDN PRI Date/time ie send policy], [PRI], [pri])
|
||||
AST_EXT_LIB_SETUP_DEPENDENT([PRI_MWI_V2], [ISDN PRI Message Waiting Indication (Fixed)], [PRI], [pri])
|
||||
AST_EXT_LIB_SETUP_DEPENDENT([PRI_DISPLAY_TEXT], [ISDN PRI user display text IE contents during call], [PRI], [pri])
|
||||
AST_EXT_LIB_SETUP_DEPENDENT([PRI_MWI], [ISDN PRI Message Waiting Indication], [PRI], [pri])
|
||||
AST_EXT_LIB_SETUP_DEPENDENT([PRI_MCID], [ISDN PRI Malicious Call ID], [PRI], [pri])
|
||||
|
@ -1141,6 +1143,8 @@ if test "${USE_GSM}" != "no"; then
|
|||
fi
|
||||
|
||||
AST_EXT_LIB_CHECK([ICONV], [iconv], [iconv_open], [iconv.h])
|
||||
# GNU libiconv #define's iconv_open to libiconv_open, so we need to search for that symbol
|
||||
AST_EXT_LIB_CHECK([ICONV], [iconv], [libiconv_open], [iconv.h])
|
||||
# Some versions of Linux package iconv in glibc
|
||||
AST_EXT_LIB_CHECK([ICONV], [c], [iconv_close], [iconv.h])
|
||||
|
||||
|
@ -1823,6 +1827,8 @@ AST_EXT_LIB_CHECK([POPT], [popt], [poptStrerror], [popt.h])
|
|||
AST_EXT_LIB_CHECK([PORTAUDIO], [portaudio], [Pa_GetDeviceCount], [portaudio.h])
|
||||
|
||||
AST_EXT_LIB_CHECK([PRI], [pri], [pri_connected_line_update], [libpri.h])
|
||||
AST_EXT_LIB_CHECK([PRI_DATETIME_SEND], [pri], [pri_date_time_send_option], [libpri.h])
|
||||
AST_EXT_LIB_CHECK([PRI_MWI_V2], [pri], [pri_mwi_indicate_v2], [libpri.h])
|
||||
AST_EXT_LIB_CHECK([PRI_DISPLAY_TEXT], [pri], [pri_display_text], [libpri.h])
|
||||
AST_EXT_LIB_CHECK([PRI_MWI], [pri], [pri_mwi_indicate], [libpri.h])
|
||||
AST_EXT_LIB_CHECK([PRI_MCID], [pri], [pri_mcid_enable], [libpri.h])
|
||||
|
@ -1971,7 +1977,7 @@ AST_EXT_LIB_CHECK([CRYPTO], [crypto], [AES_encrypt], [openssl/aes.h])
|
|||
|
||||
if test "$PBX_CRYPTO" = "1";
|
||||
then
|
||||
AST_EXT_LIB_CHECK([OPENSSL], [ssl], [ssl2_connect], [openssl/ssl.h], [-lcrypto])
|
||||
AST_EXT_LIB_CHECK([OPENSSL], [ssl], [SSL_connect], [openssl/ssl.h], [-lcrypto])
|
||||
fi
|
||||
|
||||
if test "$PBX_OPENSSL" = "1";
|
||||
|
@ -2017,20 +2023,19 @@ then
|
|||
fi
|
||||
|
||||
AST_EXT_TOOL_CHECK([GMIME], [gmime-config], [], [], [#include <gmime/gmime.h>], [gboolean q = g_mime_check_version(0,0,0);])
|
||||
if test "x${PBX_GMIME}" = "x0"; then
|
||||
if test "x${PBX_GMIME}" = "x0" -a "${PKGCONFIG}" != "No"; then
|
||||
# Later versions of GMime use pkg-config
|
||||
if test "x${PKGCONFIG}" = xNo; then :; else
|
||||
GMIME_INCLUDE=$(${PKGCONFIG} gmime-2.0 --cflags 2>/dev/null)
|
||||
GMIME_LIB=$(${PKGCONFIG} gmime-2.0 --libs)
|
||||
if test "x${GMIME_INCLUDE}${GMIME_LIB}" = "x"; then
|
||||
GMIME_INCLUDE=$(${PKGCONFIG} gmime-2.2 --cflags 2>/dev/null)
|
||||
GMIME_LIB=$(${PKGCONFIG} gmime-2.2 --libs)
|
||||
for ver in 2.0 2.2 2.4; do
|
||||
if ! ${PKGCONFIG} --exists gmime-$ver; then
|
||||
continue
|
||||
fi
|
||||
if test "x${GMIME_INCLUDE}${GMIME_LIB}" != "x"; then
|
||||
PBX_GMIME=1
|
||||
AC_DEFINE([HAVE_GMIME], 1, [Define if your system has the GMIME libraries.])
|
||||
fi
|
||||
fi
|
||||
# If we got here, we have this version:
|
||||
GMIME_INCLUDE=$(${PKGCONFIG} gmime-$ver --cflags 2>/dev/null)
|
||||
GMIME_LIB=$(${PKGCONFIG} gmime-$ver --libs)
|
||||
PBX_GMIME=1
|
||||
AC_DEFINE([HAVE_GMIME], 1, [Define if your system has the GMIME libraries.])
|
||||
break;
|
||||
done
|
||||
fi
|
||||
|
||||
AST_EXT_LIB_CHECK([HOARD], [hoard], [malloc], [])
|
||||
|
@ -2172,7 +2177,7 @@ fi
|
|||
AC_SUBST(PBX_LAUNCHD)
|
||||
|
||||
PBX_GTK2=0
|
||||
if test ! "x${PKGCONFIG}" = xNo; then
|
||||
if test "${PKGCONFIG}" != "No"; then
|
||||
GTK2_INCLUDE=$(${PKGCONFIG} gtk+-2.0 --cflags 2>/dev/null)
|
||||
GTK2_LIB=$(${PKGCONFIG} gtk+-2.0 --libs)
|
||||
PBX_GTK2=1
|
||||
|
|
|
@ -132,9 +132,12 @@ case "$1" in
|
|||
$0 start
|
||||
# "restart|force-reload" starts Asterisk and returns 0 even if Asterisk was stopped (as LSB expects).
|
||||
;;
|
||||
status)
|
||||
status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
|
||||
;;
|
||||
*)
|
||||
N=/etc/init.d/$NAME
|
||||
echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2
|
||||
echo "Usage: $N {start|stop|restart|reload|force-reload|status}" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
|
|
@ -15,7 +15,7 @@ CREATE TABLE meetme (
|
|||
recordingformat char(10) NULL,
|
||||
maxusers int(11) NULL,
|
||||
members integer DEFAULT 0 NOT NULL,
|
||||
index confno (confno,starttime,endtime)
|
||||
PRIMARY KEY (bookid),
|
||||
index confno (confno,starttime,endtime),
|
||||
PRIMARY KEY (bookid)
|
||||
);
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue