mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-05 12:16:00 +00:00
Merge changes from svn/asterisk/team/russell/sla_updates
* Originally, I put in the documentation that only Zap interfaces would be supported on the trunk side. However, after a discussion with Qwell, we came up with a way to make IP trunks work as well, using some things already in Asterisk. So, here it is, this now officially supports IP trunks. * Update the SLA documentation to reflect how to setup IP trunks. * Add a section in sla.txt that describes how to set up an SLA system with voicemail. * Simplify the way DTMF passthrough is handled in MeetMe. * Fix a bug that exposed itself when using a Local channel on the trunk side in SLA. The station's channel needs to be passed to the dial API when dialing the trunk. * Change a WARNING message to DEBUG in channel.h. This message is of no use to users. git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.4@57364 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -353,7 +353,6 @@ struct ast_conf_user {
|
||||
time_t jointime; /*!< Time the user joined the conference */
|
||||
struct volume talk;
|
||||
struct volume listen;
|
||||
AST_LIST_HEAD_NOLOCK(, ast_frame) frame_q;
|
||||
AST_LIST_ENTRY(ast_conf_user) list;
|
||||
};
|
||||
|
||||
@@ -1240,17 +1239,15 @@ static int conf_free(struct ast_conference *conf)
|
||||
}
|
||||
|
||||
static void conf_queue_dtmf(const struct ast_conference *conf,
|
||||
const struct ast_conf_user *sender, const struct ast_frame *_f)
|
||||
const struct ast_conf_user *sender, struct ast_frame *f)
|
||||
{
|
||||
struct ast_frame *f;
|
||||
struct ast_conf_user *user;
|
||||
|
||||
AST_LIST_TRAVERSE(&conf->userlist, user, list) {
|
||||
if (user == sender)
|
||||
continue;
|
||||
if (!(f = ast_frdup(_f)))
|
||||
return;
|
||||
AST_LIST_INSERT_TAIL(&user->frame_q, f, frame_list);
|
||||
if (ast_write(user->chan, f) < 0)
|
||||
ast_log(LOG_WARNING, "Error writing frame to channel %s\n", user->chan->name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1869,14 +1866,6 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int c
|
||||
f = ast_read(c);
|
||||
if (!f)
|
||||
break;
|
||||
if (!AST_LIST_EMPTY(&user->frame_q)) {
|
||||
struct ast_frame *f;
|
||||
f = AST_LIST_REMOVE_HEAD(&user->frame_q, frame_list);
|
||||
if (ast_write(chan, f) < 0) {
|
||||
ast_log(LOG_WARNING, "Error writing frame to channel!\n");
|
||||
}
|
||||
ast_frfree(f);
|
||||
}
|
||||
if ((f->frametype == AST_FRAME_VOICE) && (f->subclass == AST_FORMAT_SLINEAR)) {
|
||||
if (user->talk.actual)
|
||||
ast_frame_adjust_volume(f, user->talk.actual);
|
||||
@@ -3931,7 +3920,7 @@ static void *sla_thread(void *data)
|
||||
}
|
||||
|
||||
struct dial_trunk_args {
|
||||
struct sla_trunk *trunk;
|
||||
struct sla_trunk_ref *trunk_ref;
|
||||
struct sla_station *station;
|
||||
ast_mutex_t *cond_lock;
|
||||
ast_cond_t *cond;
|
||||
@@ -3946,7 +3935,7 @@ static void *dial_trunk(void *data)
|
||||
char conf_name[MAX_CONFNUM];
|
||||
struct ast_conference *conf;
|
||||
struct ast_flags conf_flags = { 0 };
|
||||
struct sla_trunk *trunk = args->trunk;
|
||||
struct sla_trunk_ref *trunk_ref = args->trunk_ref;
|
||||
|
||||
if (!(dial = ast_dial_create())) {
|
||||
ast_mutex_lock(args->cond_lock);
|
||||
@@ -3955,7 +3944,7 @@ static void *dial_trunk(void *data)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tech_data = ast_strdupa(trunk->device);
|
||||
tech_data = ast_strdupa(trunk_ref->trunk->device);
|
||||
tech = strsep(&tech_data, "/");
|
||||
if (ast_dial_append(dial, tech, tech_data) == -1) {
|
||||
ast_mutex_lock(args->cond_lock);
|
||||
@@ -3965,7 +3954,7 @@ static void *dial_trunk(void *data)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dial_res = ast_dial_run(dial, NULL, 1);
|
||||
dial_res = ast_dial_run(dial, trunk_ref->chan, 1);
|
||||
if (dial_res != AST_DIAL_RESULT_TRYING) {
|
||||
ast_mutex_lock(args->cond_lock);
|
||||
ast_cond_signal(args->cond);
|
||||
@@ -3978,7 +3967,7 @@ static void *dial_trunk(void *data)
|
||||
unsigned int done = 0;
|
||||
switch ((dial_res = ast_dial_state(dial))) {
|
||||
case AST_DIAL_RESULT_ANSWERED:
|
||||
trunk->chan = ast_dial_answered(dial);
|
||||
trunk_ref->trunk->chan = ast_dial_answered(dial);
|
||||
case AST_DIAL_RESULT_HANGUP:
|
||||
case AST_DIAL_RESULT_INVALID:
|
||||
case AST_DIAL_RESULT_FAILED:
|
||||
@@ -3995,7 +3984,7 @@ static void *dial_trunk(void *data)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!trunk->chan) {
|
||||
if (!trunk_ref->trunk->chan) {
|
||||
ast_mutex_lock(args->cond_lock);
|
||||
ast_cond_signal(args->cond);
|
||||
ast_mutex_unlock(args->cond_lock);
|
||||
@@ -4004,7 +3993,7 @@ static void *dial_trunk(void *data)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk->name);
|
||||
snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
|
||||
ast_set_flag(&conf_flags,
|
||||
CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_MARKEDUSER |
|
||||
CONFFLAG_PASS_DTMF | CONFFLAG_SLA_TRUNK);
|
||||
@@ -4015,12 +4004,12 @@ static void *dial_trunk(void *data)
|
||||
ast_mutex_unlock(args->cond_lock);
|
||||
|
||||
if (conf) {
|
||||
conf_run(trunk->chan, conf, conf_flags.flags, NULL);
|
||||
conf_run(trunk_ref->trunk->chan, conf, conf_flags.flags, NULL);
|
||||
dispose_conf(conf);
|
||||
conf = NULL;
|
||||
}
|
||||
|
||||
trunk->chan = NULL;
|
||||
trunk_ref->trunk->chan = NULL;
|
||||
|
||||
ast_dial_join(dial);
|
||||
ast_dial_destroy(dial);
|
||||
@@ -4095,13 +4084,15 @@ static int sla_station_exec(struct ast_channel *chan, void *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
trunk_ref->chan = chan;
|
||||
|
||||
if (!trunk_ref->trunk->chan) {
|
||||
ast_mutex_t cond_lock;
|
||||
ast_cond_t cond;
|
||||
pthread_t dont_care;
|
||||
pthread_attr_t attr;
|
||||
struct dial_trunk_args args = {
|
||||
.trunk = trunk_ref->trunk,
|
||||
.trunk_ref = trunk_ref,
|
||||
.station = station,
|
||||
.cond_lock = &cond_lock,
|
||||
.cond = &cond,
|
||||
@@ -4127,6 +4118,7 @@ static int sla_station_exec(struct ast_channel *chan, void *data)
|
||||
ast_log(LOG_DEBUG, "Trunk didn't get created. chan: %lx\n", (long) trunk_ref->trunk->chan);
|
||||
pbx_builtin_setvar_helper(chan, "SLASTATION_STATUS", "CONGESTION");
|
||||
sla_change_trunk_state(trunk_ref->trunk, SLA_TRUNK_STATE_IDLE, ALL_TRUNK_REFS);
|
||||
trunk_ref->chan = NULL;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -4135,7 +4127,6 @@ static int sla_station_exec(struct ast_channel *chan, void *data)
|
||||
snprintf(conf_name, sizeof(conf_name), "SLA_%s", trunk_ref->trunk->name);
|
||||
ast_set_flag(&conf_flags,
|
||||
CONFFLAG_QUIET | CONFFLAG_MARKEDEXIT | CONFFLAG_PASS_DTMF | CONFFLAG_SLA_STATION);
|
||||
trunk_ref->chan = chan;
|
||||
ast_answer(chan);
|
||||
conf = build_conf(conf_name, "", "", 0, 0, 1);
|
||||
if (conf) {
|
||||
|
@@ -18,7 +18,10 @@
|
||||
;type=trunk ; This line is what marks this entry as a trunk.
|
||||
|
||||
;device=Zap/3 ; Map this trunk declaration to a specific device.
|
||||
; NOTE: At this point, this *must* be a zap channel!
|
||||
; NOTE: You can not just put any type of channel here.
|
||||
; Zap channels can be directly used. IP trunks
|
||||
; require some indirect configuration which is
|
||||
; described in doc/sla.txt.
|
||||
|
||||
;autocontext=line1 ; This supports automatic generation of the dialplan entries
|
||||
; if the autocontext option is used. Each trunk should have
|
||||
@@ -52,7 +55,10 @@
|
||||
|
||||
;[line4]
|
||||
;type=trunk
|
||||
;device=Zap/4
|
||||
;device=Local/disa@line4_outbound ; A Local channel in combination with the Disa
|
||||
; application can be used to support IP trunks.
|
||||
; See doc/sla.txt on more information on how
|
||||
; IP trunks work.
|
||||
;autocontext=line4
|
||||
; --------------------------------------
|
||||
|
||||
|
142
doc/sla.txt
142
doc/sla.txt
@@ -18,7 +18,10 @@ The SLA implementation can automatically generate the dialplan necessary for
|
||||
basic operation if the "autocontext" option is set for trunks and stations in
|
||||
sla.conf. However, for reference, here is an automatically generated dialplan
|
||||
to help with custom building of the dialplan to include other features, such as
|
||||
voicemail:
|
||||
voicemail.
|
||||
|
||||
However, note that there is a little bit of additional configuration needed if
|
||||
the trunk is an IP channel. This is discussed in the TRUNKS section.
|
||||
|
||||
[line1]
|
||||
exten => s,1,SLATrunk(line1)
|
||||
@@ -49,14 +52,52 @@ exten => station3_line2,1,SLAStation(station3_line2)
|
||||
-------------------------------------------------------------------------------
|
||||
TRUNKS
|
||||
|
||||
For the trunk side of SLA, the only channels that are currently supported are
|
||||
Zap channels. Support for IP trunks is planned, but not yet implemented.
|
||||
|
||||
Be sure to configure the trunk's context to be the same one that is set for the
|
||||
"autocontext" option in sla.conf if automatic dialplan configuration is used.
|
||||
This would be done in the regular device entry in zapata.conf, sip.conf, etc.
|
||||
Note that the automatic dialplan generation creates the SLATrunk() extension
|
||||
at extension 's'. This is perfect for Zap channels that are FXO trunks, for
|
||||
example. However, it may not be good enough for an IP trunk, since the call
|
||||
coming in over the trunk may specify an actual number.
|
||||
|
||||
If the dialplan is being built manually, ensure that calls coming in on a trunk
|
||||
execute the SLATrunk() application with an argument of the trunk name.
|
||||
execute the SLATrunk() application with an argument of the trunk name, as shown
|
||||
in the dialplan example before.
|
||||
|
||||
IP trunks can be used, but they require some additional configuration to work.
|
||||
|
||||
For this example, let's say we have a SIP trunk called "mytrunk" that is going
|
||||
to be used as line4. Furthermore, when calls come in on this trunk, they are
|
||||
going to say that they are calling the number "12564286000". Also, let's say
|
||||
that the numbers that are valid for calling out this trunk are NANP numbers,
|
||||
of the form _1NXXNXXXXXX.
|
||||
|
||||
In sip.conf, there would be an entry for [mytrunk]. For [mytrunk],
|
||||
set context=line4.
|
||||
|
||||
|
||||
sla.conf:
|
||||
|
||||
[line4]
|
||||
type=trunk
|
||||
device=Local/disa@line4_outbound
|
||||
|
||||
|
||||
extensions.conf:
|
||||
|
||||
[line4]
|
||||
exten => 12564286000,1,SLATrunk(line4)
|
||||
|
||||
[line4_outbound]
|
||||
exten => disa,1,Disa(no-password|line4_outbound)
|
||||
exten => _1NXXNXXXXXX,1,Dial(SIP/${EXTEN}@mytrunk)
|
||||
|
||||
|
||||
So, when a station picks up their phone and connects to line 4, they are
|
||||
connected to the local dialplan. The Disa application plays dialtone to the
|
||||
phone and collects digits until it matches an extension. In this case, once
|
||||
the phone dials a number like 12565551212, the call will proceed out the
|
||||
SIP trunk.
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -91,3 +132,94 @@ a SIP phone for use with SLA:
|
||||
is taken off hook, then the phone should be automatically configured to
|
||||
dial "station1" when it is taken off hook.
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
VOICEMAIL
|
||||
|
||||
This is an example of how you could set up a single voicemail box for the
|
||||
phone system. The voicemail box number used in this example is 1234, which
|
||||
would be configured in voicemail.conf.
|
||||
|
||||
For this example, assume that there are 2 trunks and 3 stations. The trunks
|
||||
are Zap/1 and Zap/2. The stations are SIP/station1, SIP/station2, and
|
||||
SIP/station3.
|
||||
|
||||
In zapata.conf, channel 1 has context=line1 and channel 2 has context=line2.
|
||||
|
||||
In sip.conf, all three stations are configured with context=sla_stations.
|
||||
|
||||
When the stations pick up their phones to dial, they are allowed to dial
|
||||
NANP numbers for outbound calls, or 8500 for checking voicemail.
|
||||
|
||||
|
||||
sla.conf:
|
||||
|
||||
[line1]
|
||||
type=trunk
|
||||
device=Local/disa@line1_outbound
|
||||
|
||||
[line2]
|
||||
type=trunk
|
||||
device=Local/disa@line2_outbound
|
||||
|
||||
[station](!)
|
||||
type=station
|
||||
trunk=line1
|
||||
trunk=line2
|
||||
|
||||
[station1](station)
|
||||
device=SIP/station1
|
||||
|
||||
[station2](station)
|
||||
device=SIP/station2
|
||||
|
||||
[station3](station)
|
||||
device=SIP/station3
|
||||
|
||||
|
||||
extensions.conf:
|
||||
|
||||
[macro-slaline]
|
||||
exten => s,1,SLATrunk(${ARG1})
|
||||
exten => s,n,Goto(s-${SLATRUNK_STATUS}|1)
|
||||
exten => s-FAILURE,1,Voicemail(1234|u)
|
||||
exten => s-UNANSWERED,1,Voicemail(1234|u)
|
||||
|
||||
[line1]
|
||||
exten => s,1,Macro(slaline|line1)
|
||||
|
||||
[line2]
|
||||
exten => s,2,Macro(slaline|line2)
|
||||
|
||||
[line1_outbound]
|
||||
exten => disa,1,Disa(no-password|line1_outbound)
|
||||
exten => _1NXXNXXXXXX,1,Dial(Zap/1/${EXTEN})
|
||||
exten => 8500,1,VoicemailMain(1234)
|
||||
|
||||
[line2_outbound]
|
||||
exten => disa,1,Disa(no-password|line2_outbound)
|
||||
exten => _1NXXNXXXXXX,1,Dial(Zap/2/${EXTEN})
|
||||
exten => 8500,1,VoicemailMain(1234)
|
||||
|
||||
[sla_stations]
|
||||
|
||||
exten => station1,1,SLAStation(station1)
|
||||
exten => station1_line1,hint,SLA:station1_line1
|
||||
exten => station1_line1,1,SLAStation(station1_line1)
|
||||
exten => station1_line2,hint,SLA:station1_line2
|
||||
exten => station1_line2,1,SLAStation(station1_line2)
|
||||
|
||||
exten => station2,1,SLAStation(station2)
|
||||
exten => station2_line1,hint,SLA:station2_line1
|
||||
exten => station2_line1,1,SLAStation(station2_line1)
|
||||
exten => station2_line2,hint,SLA:station2_line2
|
||||
exten => station2_line2,1,SLAStation(station2_line2)
|
||||
|
||||
exten => station3,1,SLAStation(station3)
|
||||
exten => station3_line1,hint,SLA:station3_line1
|
||||
exten => station3_line1,1,SLAStation(station3_line1)
|
||||
exten => station3_line2,hint,SLA:station3_line2
|
||||
exten => station3_line2,1,SLAStation(station3_line2)
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
@@ -1308,15 +1308,16 @@ static inline int ast_select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds,
|
||||
#define CRASH do { } while(0)
|
||||
#endif
|
||||
|
||||
#define CHECK_BLOCKING(c) { \
|
||||
if (ast_test_flag(c, AST_FLAG_BLOCKING)) {\
|
||||
ast_log(LOG_WARNING, "Thread %ld Blocking '%s', already blocked by thread %ld in procedure %s\n", (long) pthread_self(), (c)->name, (long) (c)->blocker, (c)->blockproc); \
|
||||
CRASH; \
|
||||
} else { \
|
||||
(c)->blocker = pthread_self(); \
|
||||
(c)->blockproc = __PRETTY_FUNCTION__; \
|
||||
ast_set_flag(c, AST_FLAG_BLOCKING); \
|
||||
} }
|
||||
#define CHECK_BLOCKING(c) do { \
|
||||
if (ast_test_flag(c, AST_FLAG_BLOCKING)) {\
|
||||
if (option_debug) \
|
||||
ast_log(LOG_DEBUG, "Thread %ld Blocking '%s', already blocked by thread %ld in procedure %s\n", (long) pthread_self(), (c)->name, (long) (c)->blocker, (c)->blockproc); \
|
||||
CRASH; \
|
||||
} else { \
|
||||
(c)->blocker = pthread_self(); \
|
||||
(c)->blockproc = __PRETTY_FUNCTION__; \
|
||||
ast_set_flag(c, AST_FLAG_BLOCKING); \
|
||||
} } while (0)
|
||||
|
||||
ast_group_t ast_get_group(const char *s);
|
||||
|
||||
|
Reference in New Issue
Block a user