aboutsummaryrefslogtreecommitdiffstats
path: root/channels
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2011-06-17 08:11:11 +0200
committerPatrick McHardy <kaber@trash.net>2011-06-17 08:11:11 +0200
commit9364aaccb699c6d19ac2cbe760c208b34ba7838a (patch)
tree28c0aef25a69f14117caf64e09fc9597d2c915ea /channels
parent84c94e92c153057470194aadf7ae22a2569f1bd4 (diff)
parent62b90dd0a4ea809bdb11bc27288b6acf717edcd8 (diff)
Merge 192.168.0.100:/repos/git/asterisk
Diffstat (limited to 'channels')
-rw-r--r--channels/chan_local.c22
-rw-r--r--channels/chan_sip.c100
-rw-r--r--channels/chan_skinny.c160
-rw-r--r--channels/sip/include/sip.h3
4 files changed, 170 insertions, 115 deletions
diff --git a/channels/chan_local.c b/channels/chan_local.c
index 0ceb432b0..3c16fc51a 100644
--- a/channels/chan_local.c
+++ b/channels/chan_local.c
@@ -217,6 +217,7 @@ static void awesome_locking(struct local_pvt *p, struct ast_channel **outchan, s
*outchan = p->chan;
}
+/* Called with ast locked */
static int local_setoption(struct ast_channel *ast, int option, void * data, int datalen)
{
int res = 0;
@@ -225,27 +226,22 @@ static int local_setoption(struct ast_channel *ast, int option, void * data, int
ast_chan_write_info_t *write_info;
if (option != AST_OPTION_CHANNEL_WRITE) {
- res = -1;
- goto setoption_cleanup;
+ return -1;
}
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");
- res = -1;
- goto setoption_cleanup;
+ return -1;
}
/* get the tech pvt */
- ast_channel_lock(ast);
if (!(p = ast->tech_pvt)) {
- ast_channel_unlock(ast);
- res = -1;
- goto setoption_cleanup;
+ return -1;
}
ao2_ref(p, 1);
- ast_channel_unlock(ast);
+ ast_channel_unlock(ast); /* Held when called, unlock before locking another channel */
/* get the channel we are supposed to write to */
ao2_lock(p);
@@ -272,6 +268,7 @@ setoption_cleanup:
if (otherchan) {
ast_channel_unref(otherchan);
}
+ ast_channel_lock(ast); /* Lock back before we leave */
return res;
}
@@ -348,6 +345,7 @@ static struct ast_channel *local_bridgedchannel(struct ast_channel *chan, struct
return bridged;
}
+/* Called with ast locked */
static int local_queryoption(struct ast_channel *ast, int option, void *data, int *datalen)
{
struct local_pvt *p;
@@ -361,21 +359,18 @@ static int local_queryoption(struct ast_channel *ast, int option, void *data, in
}
/* 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);
if (!(tmp = IS_OUTBOUND(ast, p) ? p->owner : p->chan)) {
ao2_unlock(p);
- ast_channel_unlock(ast);
return -1;
}
ast_channel_ref(tmp);
ao2_unlock(p);
- ast_channel_unlock(ast);
+ ast_channel_unlock(ast); /* Held when called, unlock before locking another channel */
ast_channel_lock(tmp);
if (!(bridged = ast_bridged_channel(tmp))) {
@@ -394,6 +389,7 @@ query_cleanup:
if (tmp) {
tmp = ast_channel_unref(tmp);
}
+ ast_channel_lock(ast); /* Lock back before we leave */
return res;
}
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index bcb4ea73a..4c0e2a66c 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -4262,15 +4262,23 @@ static int sip_setoption(struct ast_channel *chan, int option, void *data, int d
int res = -1;
struct sip_pvt *p = chan->tech_pvt;
+ sip_pvt_lock(p);
+
switch (option) {
case AST_OPTION_FORMAT_READ:
- res = ast_rtp_instance_set_read_format(p->rtp, (struct ast_format *) data);
+ if (p->rtp) {
+ res = ast_rtp_instance_set_read_format(p->rtp, (struct ast_format *) data);
+ }
break;
case AST_OPTION_FORMAT_WRITE:
- res = ast_rtp_instance_set_write_format(p->rtp, (struct ast_format *) data);
+ if (p->rtp) {
+ res = ast_rtp_instance_set_write_format(p->rtp, (struct ast_format *) data);
+ }
break;
case AST_OPTION_MAKE_COMPATIBLE:
- res = ast_rtp_instance_make_compatible(chan, p->rtp, (struct ast_channel *) data);
+ if (p->rtp) {
+ res = ast_rtp_instance_make_compatible(chan, p->rtp, (struct ast_channel *) data);
+ }
break;
case AST_OPTION_DIGIT_DETECT:
if ((ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_INBAND) ||
@@ -4298,6 +4306,8 @@ static int sip_setoption(struct ast_channel *chan, int option, void *data, int d
break;
}
+ sip_pvt_unlock(p);
+
return res;
}
@@ -4309,16 +4319,16 @@ static int sip_queryoption(struct ast_channel *chan, int option, void *data, int
struct sip_pvt *p = (struct sip_pvt *) chan->tech_pvt;
char *cp;
+ sip_pvt_lock(p);
+
switch (option) {
case AST_OPTION_T38_STATE:
/* Make sure we got an ast_t38_state enum passed in */
if (*datalen != sizeof(enum ast_t38_state)) {
ast_log(LOG_ERROR, "Invalid datalen for AST_OPTION_T38_STATE option. Expected %d, got %d\n", (int)sizeof(enum ast_t38_state), *datalen);
- return -1;
+ break;
}
- sip_pvt_lock(p);
-
/* Now if T38 support is enabled we need to look and see what the current state is to get what we want to report back */
if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT)) {
switch (p->t38.state) {
@@ -4337,8 +4347,6 @@ static int sip_queryoption(struct ast_channel *chan, int option, void *data, int
}
}
- sip_pvt_unlock(p);
-
*((enum ast_t38_state *) data) = state;
res = 0;
@@ -4370,6 +4378,8 @@ static int sip_queryoption(struct ast_channel *chan, int option, void *data, int
break;
}
+ sip_pvt_unlock(p);
+
return res;
}
@@ -5061,6 +5071,7 @@ static int dialog_initialize_rtp(struct sip_pvt *dialog)
}
ast_rtp_instance_set_timeout(dialog->vrtp, global_rtptimeout);
ast_rtp_instance_set_hold_timeout(dialog->vrtp, global_rtpholdtimeout);
+ ast_rtp_instance_set_keepalive(dialog->vrtp, global_rtpholdtimeout);
ast_rtp_instance_set_prop(dialog->vrtp, AST_RTP_PROPERTY_RTCP, 1);
}
@@ -5071,12 +5082,14 @@ static int dialog_initialize_rtp(struct sip_pvt *dialog)
}
ast_rtp_instance_set_timeout(dialog->trtp, global_rtptimeout);
ast_rtp_instance_set_hold_timeout(dialog->trtp, global_rtpholdtimeout);
+ ast_rtp_instance_set_keepalive(dialog->trtp, global_rtpholdtimeout);
ast_rtp_instance_set_prop(dialog->trtp, AST_RTP_PROPERTY_RTCP, 1);
}
ast_rtp_instance_set_timeout(dialog->rtp, global_rtptimeout);
ast_rtp_instance_set_hold_timeout(dialog->rtp, global_rtpholdtimeout);
+ ast_rtp_instance_set_keepalive(dialog->rtp, global_rtpkeepalive);
ast_rtp_instance_set_prop(dialog->rtp, AST_RTP_PROPERTY_RTCP, 1);
ast_rtp_instance_set_prop(dialog->rtp, AST_RTP_PROPERTY_DTMF, ast_test_flag(&dialog->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833);
@@ -5144,6 +5157,7 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer)
ast_rtp_instance_set_prop(dialog->rtp, AST_RTP_PROPERTY_DTMF_COMPENSATE, ast_test_flag(&dialog->flags[1], SIP_PAGE2_RFC2833_COMPENSATE));
ast_rtp_instance_set_timeout(dialog->rtp, peer->rtptimeout);
ast_rtp_instance_set_hold_timeout(dialog->rtp, peer->rtpholdtimeout);
+ ast_rtp_instance_set_keepalive(dialog->rtp, peer->rtpkeepalive);
/* Set Frame packetization */
ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(dialog->rtp), dialog->rtp, &dialog->prefs);
dialog->autoframing = peer->autoframing;
@@ -5151,10 +5165,12 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer)
if (dialog->vrtp) { /* Video */
ast_rtp_instance_set_timeout(dialog->vrtp, peer->rtptimeout);
ast_rtp_instance_set_hold_timeout(dialog->vrtp, peer->rtpholdtimeout);
+ ast_rtp_instance_set_keepalive(dialog->vrtp, peer->rtpkeepalive);
}
if (dialog->trtp) { /* Realtime text */
ast_rtp_instance_set_timeout(dialog->trtp, peer->rtptimeout);
ast_rtp_instance_set_hold_timeout(dialog->trtp, peer->rtpholdtimeout);
+ ast_rtp_instance_set_keepalive(dialog->trtp, peer->rtpkeepalive);
}
/* XXX TODO: get fields directly from peer only as they are needed using dialog->relatedpeer */
@@ -6344,7 +6360,11 @@ static int sip_write(struct ast_channel *ast, struct ast_frame *frame)
}
if (p) {
sip_pvt_lock(p);
- if (p->rtp) {
+ if (p->t38.state == T38_ENABLED) {
+ /* drop frame, can't sent VOICE frames while in T.38 mode */
+ sip_pvt_unlock(p);
+ break;
+ } else if (p->rtp) {
/* If channel is not up, activate early media session */
if ((ast->_state != AST_STATE_UP) &&
!ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) &&
@@ -6355,12 +6375,9 @@ static int sip_write(struct ast_channel *ast, struct ast_frame *frame)
transmit_provisional_response(p, "183 Session Progress", &p->initreq, TRUE);
ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
}
- } else if (p->t38.state == T38_ENABLED) {
- /* drop frame, can't sent VOICE frames while in T.38 mode */
- } else {
- p->lastrtptx = time(NULL);
- res = ast_rtp_instance_write(p->rtp, frame);
}
+ p->lastrtptx = time(NULL);
+ res = ast_rtp_instance_write(p->rtp, frame);
}
sip_pvt_unlock(p);
}
@@ -7274,12 +7291,19 @@ static struct ast_frame *sip_read(struct ast_channel *ast)
/* If we detect a CNG tone and fax detection is enabled then send us off to the fax extension */
if (faxdetected && ast_test_flag(&p->flags[1], SIP_PAGE2_FAX_DETECT_CNG)) {
- ast_channel_lock(ast);
if (strcmp(ast->exten, "fax")) {
const char *target_context = S_OR(ast->macrocontext, ast->context);
+ /* We need to unlock 'ast' here because
+ * ast_exists_extension has the potential to start and
+ * stop an autoservice on the channel. Such action is
+ * prone to deadlock if the channel is locked.
+ */
+ sip_pvt_unlock(p);
ast_channel_unlock(ast);
if (ast_exists_extension(ast, target_context, "fax", 1,
S_COR(ast->caller.id.number.valid, ast->caller.id.number.str, NULL))) {
+ ast_channel_lock(ast);
+ sip_pvt_lock(p);
ast_verbose(VERBOSE_PREFIX_2 "Redirecting '%s' to fax extension due to CNG detection\n", ast->name);
pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast->exten);
if (ast_async_goto(ast, target_context, "fax", 1)) {
@@ -7287,10 +7311,10 @@ static struct ast_frame *sip_read(struct ast_channel *ast)
}
fr = &ast_null_frame;
} else {
+ ast_channel_lock(ast);
+ sip_pvt_lock(p);
ast_log(LOG_NOTICE, "FAX CNG detected but no fax extension\n");
}
- } else {
- ast_channel_unlock(ast);
}
}
@@ -15749,8 +15773,12 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of,
p->callingpres = peer->callingpres;
}
ast_string_field_set(p, fullcontact, peer->fullcontact);
- if (!ast_strlen_zero(peer->context))
+ if (!ast_strlen_zero(peer->context)) {
ast_string_field_set(p, context, peer->context);
+ }
+ if (!ast_strlen_zero(peer->messagecontext)) {
+ ast_string_field_set(p, messagecontext, peer->messagecontext);
+ }
ast_string_field_set(p, peersecret, peer->secret);
ast_string_field_set(p, peermd5secret, peer->md5secret);
ast_string_field_set(p, language, peer->language);
@@ -16080,6 +16108,10 @@ static void receive_message(struct sip_pvt *p, struct sip_request *req, struct a
if (ast_strlen_zero(peer->secret) && ast_strlen_zero(peer->md5secret)) {
ast_string_field_set(p, context, peer->context);
}
+ if (!ast_strlen_zero(peer->messagecontext)) {
+ ast_string_field_set(p, messagecontext, peer->messagecontext);
+ }
+ ast_string_field_set(p, peername, peer->name);
peer = unref_peer(peer, "from find_peer() in receive_message");
}
}
@@ -16100,7 +16132,19 @@ static void receive_message(struct sip_pvt *p, struct sip_request *req, struct a
res = ast_msg_set_to(msg, "%s", to);
res |= ast_msg_set_from(msg, "%s", get_in_brackets(from));
res |= ast_msg_set_body(msg, "%s", ast_str_buffer(buf));
- res |= ast_msg_set_context(msg, "%s", p->context);
+
+ if (!ast_strlen_zero(p->messagecontext)) {
+ res |= ast_msg_set_context(msg, "%s", p->messagecontext);
+ } else if (!ast_strlen_zero(sip_cfg.messagecontext)) {
+ res |= ast_msg_set_context(msg, "%s", sip_cfg.messagecontext);
+ } else {
+ res |= ast_msg_set_context(msg, "%s", p->context);
+ }
+
+ if (!ast_strlen_zero(p->peername)) {
+ res |= ast_msg_set_var(msg, "SIP_PEERNAME", p->peername);
+ }
+
res |= ast_msg_set_exten(msg, "%s", p->exten);
if (res) {
@@ -25368,11 +25412,19 @@ static void check_rtp_timeout(struct sip_pvt *dialog, time_t t)
}
/* If we have no timers set, return now */
- if (!ast_rtp_instance_get_timeout(dialog->rtp) && !ast_rtp_instance_get_hold_timeout(dialog->rtp)) {
+ if (!ast_rtp_instance_get_keepalive(dialog->rtp) && !ast_rtp_instance_get_timeout(dialog->rtp) && !ast_rtp_instance_get_hold_timeout(dialog->rtp)) {
dialog_unlink_rtpcheck(dialog);
return;
}
+ /* Check AUDIO RTP keepalives */
+ if (dialog->lastrtptx && ast_rtp_instance_get_keepalive(dialog->rtp) &&
+ (t > dialog->lastrtptx + ast_rtp_instance_get_keepalive(dialog->rtp))) {
+ /* Need to send an empty RTP packet */
+ dialog->lastrtptx = time(NULL);
+ ast_rtp_instance_sendcng(dialog->rtp, 0);
+ }
+
/*! \todo Check video RTP keepalives
Do we need to move the lastrtptx to the RTP structure to have one for audio and one
@@ -26671,6 +26723,7 @@ static void set_peer_defaults(struct sip_peer *peer)
ast_copy_flags(&peer->flags[1], &global_flags[1], SIP_PAGE2_FLAGS_TO_COPY);
ast_copy_flags(&peer->flags[2], &global_flags[2], SIP_PAGE3_FLAGS_TO_COPY);
ast_string_field_set(peer, context, sip_cfg.default_context);
+ ast_string_field_set(peer, messagecontext, sip_cfg.messagecontext);
ast_string_field_set(peer, subscribecontext, sip_cfg.default_subscribecontext);
ast_string_field_set(peer, language, default_language);
ast_string_field_set(peer, mohinterpret, default_mohinterpret);
@@ -26965,6 +27018,8 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
} else if (!strcasecmp(v->name, "context")) {
ast_string_field_set(peer, context, v->value);
ast_set_flag(&peer->flags[1], SIP_PAGE2_HAVEPEERCONTEXT);
+ } else if (!strcasecmp(v->name, "outofcall_message_context")) {
+ ast_string_field_set(peer, messagecontext, v->value);
} else if (!strcasecmp(v->name, "subscribecontext")) {
ast_string_field_set(peer, subscribecontext, v->value);
} else if (!strcasecmp(v->name, "fromdomain")) {
@@ -27351,7 +27406,7 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str
* specified, use that address instead. */
/* XXX May need to revisit the final argument; does the realtime DB store whether
* the original contact was over TLS or not? XXX */
- if (!ast_test_flag(&peer->flags[0], SIP_NAT_RPORT_PRESENT) || ast_sockaddr_isnull(&peer->addr)) {
+ if (!ast_test_flag(&peer->flags[0], SIP_NAT_FORCE_RPORT) || ast_sockaddr_isnull(&peer->addr)) {
__set_address_from_contact(fullcontact->str, &peer->addr, 0);
}
}
@@ -27653,6 +27708,7 @@ static int reload_config(enum channelreloadreason reason)
sip_cfg.alwaysauthreject = DEFAULT_ALWAYSAUTHREJECT;
sip_cfg.auth_options_requests = DEFAULT_AUTH_OPTIONS;
sip_cfg.auth_message_requests = DEFAULT_AUTH_MESSAGE;
+ sip_cfg.messagecontext[0] = '\0';
sip_cfg.accept_outofcall_message = DEFAULT_ACCEPT_OUTOFCALL_MESSAGE;
sip_cfg.allowsubscribe = FALSE;
sip_cfg.disallowed_methods = SIP_UNKNOWN;
@@ -27906,6 +27962,8 @@ static int reload_config(enum channelreloadreason reason)
sip_cfg.auth_message_requests = ast_true(v->value) ? 1 : 0;
} else if (!strcasecmp(v->name, "accept_outofcall_message")) {
sip_cfg.accept_outofcall_message = ast_true(v->value) ? 1 : 0;
+ } else if (!strcasecmp(v->name, "outofcall_message_context")) {
+ ast_copy_string(sip_cfg.messagecontext, v->value, sizeof(sip_cfg.messagecontext));
} else if (!strcasecmp(v->name, "mohinterpret")) {
ast_copy_string(default_mohinterpret, v->value, sizeof(default_mohinterpret));
} else if (!strcasecmp(v->name, "mohsuggest")) {
diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c
index b90ba7eba..ea7d16c9e 100644
--- a/channels/chan_skinny.c
+++ b/channels/chan_skinny.c
@@ -1126,6 +1126,10 @@ static int callnums = 1;
#define SKINNY_ALERT 0x24
#define SKINNY_REORDER 0x25
#define SKINNY_CALLWAITTONE 0x2D
+#define SKINNY_ZIPZIP 0x31
+#define SKINNY_ZIP 0x32
+#define SKINNY_BEEPBONK 0x33
+#define SKINNY_BARGIN 0x43
#define SKINNY_NOTONE 0x7F
#define SKINNY_LAMP_OFF 1
@@ -1164,18 +1168,10 @@ static const char * const skinny_cxmodes[] = {
/* driver scheduler */
static struct ast_sched_context *sched = NULL;
-static struct io_context *io;
-/* Protect the monitoring thread, so only one process can kill or start it, and not
- when it's doing something critical. */
-AST_MUTEX_DEFINE_STATIC(monlock);
/* Protect the network socket */
AST_MUTEX_DEFINE_STATIC(netlock);
-/* This is the thread for the monitor which checks for input on the channels
- which are not currently in use. */
-static pthread_t monitor_thread = AST_PTHREADT_NULL;
-
/* Wait up to 16 seconds for first digit */
static int firstdigittimeout = 16000;
@@ -1215,7 +1211,9 @@ struct skinny_subchannel {
int blindxfer;
int xferor;
int substate;
-
+ int aa_sched;
+ int aa_beep;
+ int aa_mute;
AST_LIST_ENTRY(skinny_subchannel) list;
struct skinny_subchannel *related;
@@ -1712,6 +1710,16 @@ static struct ast_variable *add_var(const char *buf, struct ast_variable *list)
return list;
}
+static int skinny_sched_del(int sched_id)
+{
+ return ast_sched_del(sched, sched_id);
+}
+
+static int skinny_sched_add(int when, ast_sched_cb callback, const void *data)
+{
+ return ast_sched_add(sched, when, callback, data);
+}
+
/* It's quicker/easier to find the subchannel when we know the instance number too */
static struct skinny_subchannel *find_subchannel_by_instance_reference(struct skinny_device *d, int instance, int reference)
{
@@ -2235,7 +2243,7 @@ static void transmit_speaker_mode(struct skinny_device *d, int mode)
req->data.setspeaker.mode = htolel(mode);
transmit_response(d, req);
}
-/*
+
static void transmit_microphone_mode(struct skinny_device *d, int mode)
{
struct skinny_req *req;
@@ -2246,7 +2254,6 @@ static void transmit_microphone_mode(struct skinny_device *d, int mode)
req->data.setmicrophone.mode = htolel(mode);
transmit_response(d, req);
}
-*/
static void transmit_callinfo(struct skinny_subchannel *sub)
{
@@ -4044,7 +4051,13 @@ static void *skinny_ss(void *data)
return NULL;
}
-
+static int skinny_autoanswer_cb(const void *data)
+{
+ struct skinny_subchannel *sub = (struct skinny_subchannel *)data;
+ sub->aa_sched = 0;
+ setsubstate(sub, SKINNY_CONNECTED);
+ return 0;
+}
static int skinny_call(struct ast_channel *ast, char *dest, int timeout)
{
@@ -4052,6 +4065,8 @@ static int skinny_call(struct ast_channel *ast, char *dest, int timeout)
struct skinny_subchannel *sub = ast->tech_pvt;
struct skinny_line *l = sub->line;
struct skinny_device *d = l->device;
+ struct ast_var_t *current;
+ int doautoanswer = 0;
if (!d->registered) {
ast_log(LOG_ERROR, "Device not registered, cannot call %s\n", dest);
@@ -4075,8 +4090,40 @@ static int skinny_call(struct ast_channel *ast, char *dest, int timeout)
ast_queue_control(ast, AST_CONTROL_BUSY);
return -1;
}
-
+
+ AST_LIST_TRAVERSE(&ast->varshead, current, entries) {
+ if (!(strcasecmp(ast_var_name(current),"SKINNY_AUTOANSWER"))) {
+ if (d->hookstate == SKINNY_ONHOOK && !sub->aa_sched) {
+ char buf[24];
+ int aatime;
+ char *stringp = buf, *curstr;
+ ast_copy_string(buf, ast_var_value(current), sizeof(buf));
+ curstr = strsep(&stringp, ":");
+ ast_verb(3, "test %s\n", curstr);
+ aatime = atoi(curstr);
+ while ((curstr = strsep(&stringp, ":"))) {
+ if (!(strcasecmp(curstr,"BEEP"))) {
+ sub->aa_beep = 1;
+ } else if (!(strcasecmp(curstr,"MUTE"))) {
+ sub->aa_mute = 1;
+ }
+ }
+ if (skinnydebug)
+ ast_verb(3, "Sub %d - setting autoanswer time=%dms %s%s\n", sub->callid, aatime, sub->aa_beep?"BEEP ":"", sub->aa_mute?"MUTE":"");
+ if (aatime) {
+ //sub->aa_sched = ast_sched_add(sched, aatime, skinny_autoanswer_cb, sub);
+ sub->aa_sched = skinny_sched_add(aatime, skinny_autoanswer_cb, sub);
+ } else {
+ doautoanswer = 1;
+ }
+ }
+ }
+ }
+
setsubstate(sub, SUBSTATE_RINGIN);
+ if (doautoanswer) {
+ setsubstate(sub, SUBSTATE_CONNECTED);
+ }
return res;
}
@@ -4637,6 +4684,13 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
if (sub->substate == SUBSTATE_ONHOOK) {
return;
}
+
+ if (state != SUBSTATE_RINGIN && sub->aa_sched) {
+ skinny_sched_del(sub->aa_sched);
+ sub->aa_sched = 0;
+ sub->aa_beep = 0;
+ sub->aa_mute = 0;
+ }
if ((state == SUBSTATE_RINGIN) && ((d->hookstate == SKINNY_OFFHOOK) || (AST_LIST_NEXT(AST_LIST_FIRST(&l->sub), list)))) {
actualstate = SUBSTATE_CALLWAIT;
@@ -4789,6 +4843,7 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
ast_queue_control(sub->owner, AST_CONTROL_UNHOLD);
transmit_connect(d, sub);
}
+ transmit_ringer_mode(d, SKINNY_RING_OFF);
transmit_activatecallplane(d, l);
transmit_stop_tone(d, l->instance, sub->callid);
transmit_callinfo(sub);
@@ -4798,6 +4853,12 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
if (!sub->rtp) {
start_rtp(sub);
}
+ if (sub->aa_beep) {
+ transmit_start_tone(d, SKINNY_ZIP, l->instance, sub->callid);
+ }
+ if (sub->aa_mute) {
+ transmit_microphone_mode(d, SKINNY_MICOFF);
+ }
if (sub->substate == SUBSTATE_RINGIN || sub->substate == SUBSTATE_CALLWAIT) {
ast_queue_control(sub->owner, AST_CONTROL_ANSWER);
}
@@ -6499,59 +6560,6 @@ static void *accept_thread(void *ignore)
return 0;
}
-static void *do_monitor(void *data)
-{
- int res;
-
- /* This thread monitors all the interfaces which are not yet in use
- (and thus do not have a separate thread) indefinitely */
- /* From here on out, we die whenever asked */
- for(;;) {
- pthread_testcancel();
- /* Wait for sched or io */
- res = ast_sched_wait(sched);
- if ((res < 0) || (res > 1000)) {
- res = 1000;
- }
- res = ast_io_wait(io, res);
- ast_mutex_lock(&monlock);
- if (res >= 0) {
- ast_sched_runq(sched);
- }
- ast_mutex_unlock(&monlock);
- }
- /* Never reached */
- return NULL;
-
-}
-
-static int restart_monitor(void)
-{
- /* If we're supposed to be stopped -- stay stopped */
- if (monitor_thread == AST_PTHREADT_STOP)
- return 0;
-
- ast_mutex_lock(&monlock);
- if (monitor_thread == pthread_self()) {
- ast_mutex_unlock(&monlock);
- ast_log(LOG_WARNING, "Cannot kill myself\n");
- return -1;
- }
- if (monitor_thread != AST_PTHREADT_NULL) {
- /* Wake up the thread */
- pthread_kill(monitor_thread, SIGURG);
- } else {
- /* Start a new monitor */
- if (ast_pthread_create_background(&monitor_thread, NULL, do_monitor, NULL) < 0) {
- ast_mutex_unlock(&monlock);
- ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
- return -1;
- }
- }
- ast_mutex_unlock(&monlock);
- return 0;
-}
-
static int skinny_devicestate(void *data)
{
struct skinny_line *l;
@@ -6591,7 +6599,6 @@ static struct ast_channel *skinny_request(const char *type, struct ast_format_ca
if (!tmpc) {
ast_log(LOG_WARNING, "Unable to make channel for '%s'\n", tmp);
}
- restart_monitor();
return tmpc;
}
@@ -7425,13 +7432,13 @@ static int load_module(void)
sched = ast_sched_context_create();
if (!sched) {
ast_log(LOG_WARNING, "Unable to create schedule context\n");
+ return AST_MODULE_LOAD_FAILURE;
}
- io = io_context_create();
- if (!io) {
- ast_log(LOG_WARNING, "Unable to create I/O context\n");
+ if (ast_sched_start_thread(sched)) {
+ ast_sched_context_destroy(sched);
+ sched = NULL;
+ return AST_MODULE_LOAD_FAILURE;
}
- /* And start the monitor for the first time */
- restart_monitor();
return AST_MODULE_LOAD_SUCCESS;
}
@@ -7483,15 +7490,6 @@ static int unload_module(void)
delete_devices();
- ast_mutex_lock(&monlock);
- if ((monitor_thread != AST_PTHREADT_NULL) && (monitor_thread != AST_PTHREADT_STOP)) {
- pthread_cancel(monitor_thread);
- pthread_kill(monitor_thread, SIGURG);
- pthread_join(monitor_thread, NULL);
- }
- monitor_thread = AST_PTHREADT_STOP;
- ast_mutex_unlock(&monlock);
-
ast_mutex_lock(&netlock);
if (accept_t && (accept_t != AST_PTHREADT_STOP)) {
pthread_cancel(accept_t);
diff --git a/channels/sip/include/sip.h b/channels/sip/include/sip.h
index 0eb8be350..e8dba3067 100644
--- a/channels/sip/include/sip.h
+++ b/channels/sip/include/sip.h
@@ -691,6 +691,7 @@ struct sip_settings {
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 */
+ char messagecontext[AST_MAX_CONTEXT]; /*!< Default context for out of dialog msgs. */
unsigned int disallowed_methods; /*!< methods that we should never try to use */
int notifyringing; /*!< Send notifications on ringing */
int notifyhold; /*!< Send notifications on hold */
@@ -939,6 +940,7 @@ struct sip_pvt {
AST_STRING_FIELD(useragent); /*!< User agent in SIP request */
AST_STRING_FIELD(exten); /*!< Extension where to start */
AST_STRING_FIELD(context); /*!< Context for this call */
+ AST_STRING_FIELD(messagecontext); /*!< Default context for outofcall messages. */
AST_STRING_FIELD(subscribecontext); /*!< Subscribecontext */
AST_STRING_FIELD(subscribeuri); /*!< Subscribecontext */
AST_STRING_FIELD(fromdomain); /*!< Domain to show in the from field */
@@ -1172,6 +1174,7 @@ struct sip_peer {
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(messagecontext); /*!< Default context for outofcall messages. */
AST_STRING_FIELD(subscribecontext); /*!< Default context for subscriptions */
AST_STRING_FIELD(username); /*!< Temporary username until registration */
AST_STRING_FIELD(accountcode); /*!< Account code */