sig_analog: Add Called Subscriber Held capability.

This adds support for Called Subscriber Held for FXS
lines, which allows users to go on hook when receiving
a call and resume the call later from another phone on
the same line, without disconnecting the call. This is
a convenience mechanism that most real PSTN telephone
switches support.

ASTERISK-30372 #close

Resolves: #240

UserNote: Called Subscriber Held is now supported for analog
FXS channels, using the calledsubscriberheld option. This allows
a station  user to go on hook when receiving an incoming call
and resume from another phone on the same line by going on hook,
without disconnecting the call.
pull/542/head
Naveen Albert 2 years ago
parent 9a28531362
commit 52283301e8

@ -12949,6 +12949,7 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
tmp->callwaitingcallerid = conf->chan.callwaitingcallerid;
tmp->threewaycalling = conf->chan.threewaycalling;
tmp->threewaysilenthold = conf->chan.threewaysilenthold;
tmp->calledsubscriberheld = conf->chan.calledsubscriberheld; /* Not used in chan_dahdi.c, just analog pvt, but must exist on the DAHDI pvt anyways */
tmp->adsi = conf->chan.adsi;
tmp->use_smdi = conf->chan.use_smdi;
tmp->permhidecallerid = conf->chan.hidecallerid;
@ -13247,6 +13248,7 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
analog_p->ani_wink_time = conf->chan.ani_wink_time;
analog_p->hanguponpolarityswitch = conf->chan.hanguponpolarityswitch;
analog_p->permcallwaiting = conf->chan.callwaiting; /* permcallwaiting possibly modified in analog_config_complete */
analog_p->calledsubscriberheld = conf->chan.calledsubscriberheld; /* Only actually used in analog pvt, not DAHDI pvt */
analog_p->callreturn = conf->chan.callreturn;
analog_p->cancallforward = conf->chan.cancallforward;
analog_p->canpark = conf->chan.canpark;
@ -18341,6 +18343,8 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
confp->chan.busycount = atoi(v->value);
} else if (!strcasecmp(v->name, "busypattern")) {
parse_busy_pattern(v, &confp->chan.busy_cadence);
} else if (!strcasecmp(v->name, "calledsubscriberheld")) {
confp->chan.calledsubscriberheld = ast_true(v->value);
} else if (!strcasecmp(v->name, "callprogress")) {
confp->chan.callprogress &= ~CALLPROGRESS_PROGRESS;
if (ast_true(v->value))

@ -204,6 +204,13 @@ struct dahdi_pvt {
* \note Set from the "busydetect" value read in from chan_dahdi.conf
*/
unsigned int busydetect:1;
/*!
* \brief TRUE if Called Subscriber held is enabled.
* This allows a single incoming call to hold a DAHDI channel up,
* allowing a recipient to hang up an extension and pick up another
* phone on the same line without disconnecting the call.
*/
unsigned int calledsubscriberheld:1;
/*!
* \brief TRUE if call return is enabled.
* (*69, if your dialplan doesn't catch this first)

@ -805,6 +805,11 @@ int analog_available(struct analog_pvt *p)
return 0;
}
/* If line is being held, definitely not (don't allow call waitings to an on-hook phone) */
if (p->cshactive) {
return 0;
}
/* If no owner definitely available */
if (!p->owner) {
offhook = analog_is_off_hook(p);
@ -1300,6 +1305,7 @@ int analog_hangup(struct analog_pvt *p, struct ast_channel *ast)
p->channel, idx, p->subs[ANALOG_SUB_REAL].allocd, p->subs[ANALOG_SUB_CALLWAIT].allocd, p->subs[ANALOG_SUB_THREEWAY].allocd);
if (idx > -1) {
/* Real channel, do some fixup */
p->cshactive = 0;
p->subs[idx].owner = NULL;
p->polarity = POLARITY_IDLE;
analog_set_linear_mode(p, idx, 0);
@ -2933,6 +2939,34 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
analog_get_and_handle_alarms(p);
cause_code->ast_cause = AST_CAUSE_NETWORK_OUT_OF_ORDER;
case ANALOG_EVENT_ONHOOK:
if (p->calledsubscriberheld && (p->sig == ANALOG_SIG_FXOLS || p->sig == ANALOG_SIG_FXOGS || p->sig == ANALOG_SIG_FXOKS) && idx == ANALOG_SUB_REAL) {
ast_debug(4, "Channel state on %s is %d\n", ast_channel_name(ast), ast_channel_state(ast));
/* Called Subscriber Held: don't let the called party hang up on an incoming call immediately (if it's the only call). */
if (p->subs[ANALOG_SUB_CALLWAIT].owner || p->subs[ANALOG_SUB_THREEWAY].owner) {
ast_debug(2, "Letting this call hang up normally, since it's not the only call\n");
} else if (!p->owner || !p->subs[ANALOG_SUB_REAL].owner || ast_channel_state(ast) != AST_STATE_UP) {
ast_debug(2, "Called Subscriber Held does not apply: channel state is %d\n", ast_channel_state(ast));
} else if (!p->owner || !p->subs[ANALOG_SUB_REAL].owner || strcmp(ast_channel_appl(p->subs[ANALOG_SUB_REAL].owner), "AppDial")) {
/* Called Subscriber held only applies to incoming calls, not outgoing calls.
* We can't use p->outgoing because that is always true, for both incoming and outgoing calls, so it's not accurate.
* We can check the channel application/data instead.
* For incoming calls to the channel, it will look like: AppDial / (Outgoing Line)
* We only want this behavior for regular calls anyways (and not, say, Queue),
* so this would actually work great. But accessing ast_channel_appl can cause a crash if there are no calls left,
* so this check must occur AFTER we confirm the channel state *is* still UP.
*/
ast_debug(2, "Called Subscriber Held does not apply: not an incoming call\n");
} else if (analog_is_off_hook(p)) {
ast_log(LOG_WARNING, "Got ONHOOK but channel %d is off hook?\n", p->channel); /* Shouldn't happen */
} else {
ast_verb(3, "Holding incoming call %s for channel %d\n", ast_channel_name(ast), p->channel);
/* Inhibit dahdi_hangup from getting called, and do nothing else now.
* When the DAHDI channel goes off hook again, it'll just get reconnected with the incoming call,
* to which, as far as its concerned, nothing has happened. */
p->cshactive = 1; /* Keep track that this DAHDI channel is currently being held by an incoming call. */
break;
}
}
ast_queue_control_data(ast, AST_CONTROL_PVT_CAUSE_CODE, cause_code, data_size);
ast_channel_hangupcause_hash_set(ast, cause_code, data_size);
switch (p->sig) {
@ -3809,6 +3843,7 @@ void *analog_handle_init_event(struct analog_pvt *i, int event)
case ANALOG_SIG_FXOKS:
res = analog_off_hook(i);
i->fxsoffhookstate = 1;
i->cshactive = 0;
if (res && (errno == EBUSY)) {
break;
}

@ -289,6 +289,7 @@ struct analog_pvt {
unsigned int ani_wink_time:16; /* Safe wait time before we wink to start ANI spill */
unsigned int answeronpolarityswitch:1;
unsigned int calledsubscriberheld:1; /*!< TRUE if a single incoming call can hold an FXS channel */
unsigned int callreturn:1;
unsigned int cancallforward:1;
unsigned int canpark:1;
@ -330,6 +331,7 @@ struct analog_pvt {
/* XXX: All variables after this are internal */
unsigned int callwaiting:1; /*!< TRUE if call waiting is enabled. (Active option) */
unsigned int cshactive:1; /*!< TRUE if FXS channel is currently held by an incoming call */
unsigned int dialednone:1;
unsigned int dialing:1; /*!< TRUE if in the process of dialing digits or sending something */
unsigned int dnd:1; /*!< TRUE if Do-Not-Disturb is enabled. */

@ -755,6 +755,18 @@ usecallingpres=yes
;
callwaitingcallerid=yes
;
; Whether or not to allow users to go on-hook when receiving an incoming call
; without disconnecting it. Users can later resume the call from any phone
; on the same physical phone line (the same DAHDI channel).
; This setting only has an effect on FXS (FXO-signalled) channels where there
; is only a single incoming call to the DAHDI channel, using the Dial application.
; (This is a convenience mechanism to avoid users wishing to resume a conversation
; at a different phone from leaving a phone off the hook, resuming elsewhere,
; and forgetting to restore the original phone on hook afterwards.)
; Default is no.
;
;calledsubscriberheld=yes
;
; Support three-way calling
;
threewaycalling=yes

Loading…
Cancel
Save