Skip to content

Commit 301b025

Browse files
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.
1 parent 27c5d27 commit 301b025

File tree

5 files changed

+60
-0
lines changed

5 files changed

+60
-0
lines changed

channels/chan_dahdi.c

+4
Original file line numberDiff line numberDiff line change
@@ -12949,6 +12949,7 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
1294912949
tmp->callwaitingcallerid = conf->chan.callwaitingcallerid;
1295012950
tmp->threewaycalling = conf->chan.threewaycalling;
1295112951
tmp->threewaysilenthold = conf->chan.threewaysilenthold;
12952+
tmp->calledsubscriberheld = conf->chan.calledsubscriberheld; /* Not used in chan_dahdi.c, just analog pvt, but must exist on the DAHDI pvt anyways */
1295212953
tmp->adsi = conf->chan.adsi;
1295312954
tmp->use_smdi = conf->chan.use_smdi;
1295412955
tmp->permhidecallerid = conf->chan.hidecallerid;
@@ -13247,6 +13248,7 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
1324713248
analog_p->ani_wink_time = conf->chan.ani_wink_time;
1324813249
analog_p->hanguponpolarityswitch = conf->chan.hanguponpolarityswitch;
1324913250
analog_p->permcallwaiting = conf->chan.callwaiting; /* permcallwaiting possibly modified in analog_config_complete */
13251+
analog_p->calledsubscriberheld = conf->chan.calledsubscriberheld; /* Only actually used in analog pvt, not DAHDI pvt */
1325013252
analog_p->callreturn = conf->chan.callreturn;
1325113253
analog_p->cancallforward = conf->chan.cancallforward;
1325213254
analog_p->canpark = conf->chan.canpark;
@@ -18341,6 +18343,8 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct
1834118343
confp->chan.busycount = atoi(v->value);
1834218344
} else if (!strcasecmp(v->name, "busypattern")) {
1834318345
parse_busy_pattern(v, &confp->chan.busy_cadence);
18346+
} else if (!strcasecmp(v->name, "calledsubscriberheld")) {
18347+
confp->chan.calledsubscriberheld = ast_true(v->value);
1834418348
} else if (!strcasecmp(v->name, "callprogress")) {
1834518349
confp->chan.callprogress &= ~CALLPROGRESS_PROGRESS;
1834618350
if (ast_true(v->value))

channels/chan_dahdi.h

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

channels/sig_analog.c

+35
Original file line numberDiff line numberDiff line change
@@ -805,6 +805,11 @@ int analog_available(struct analog_pvt *p)
805805
return 0;
806806
}
807807

808+
/* If line is being held, definitely not (don't allow call waitings to an on-hook phone) */
809+
if (p->cshactive) {
810+
return 0;
811+
}
812+
808813
/* If no owner definitely available */
809814
if (!p->owner) {
810815
offhook = analog_is_off_hook(p);
@@ -1300,6 +1305,7 @@ int analog_hangup(struct analog_pvt *p, struct ast_channel *ast)
13001305
p->channel, idx, p->subs[ANALOG_SUB_REAL].allocd, p->subs[ANALOG_SUB_CALLWAIT].allocd, p->subs[ANALOG_SUB_THREEWAY].allocd);
13011306
if (idx > -1) {
13021307
/* Real channel, do some fixup */
1308+
p->cshactive = 0;
13031309
p->subs[idx].owner = NULL;
13041310
p->polarity = POLARITY_IDLE;
13051311
analog_set_linear_mode(p, idx, 0);
@@ -2933,6 +2939,34 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
29332939
analog_get_and_handle_alarms(p);
29342940
cause_code->ast_cause = AST_CAUSE_NETWORK_OUT_OF_ORDER;
29352941
case ANALOG_EVENT_ONHOOK:
2942+
if (p->calledsubscriberheld && (p->sig == ANALOG_SIG_FXOLS || p->sig == ANALOG_SIG_FXOGS || p->sig == ANALOG_SIG_FXOKS) && idx == ANALOG_SUB_REAL) {
2943+
ast_debug(4, "Channel state on %s is %d\n", ast_channel_name(ast), ast_channel_state(ast));
2944+
/* Called Subscriber Held: don't let the called party hang up on an incoming call immediately (if it's the only call). */
2945+
if (p->subs[ANALOG_SUB_CALLWAIT].owner || p->subs[ANALOG_SUB_THREEWAY].owner) {
2946+
ast_debug(2, "Letting this call hang up normally, since it's not the only call\n");
2947+
} else if (!p->owner || !p->subs[ANALOG_SUB_REAL].owner || ast_channel_state(ast) != AST_STATE_UP) {
2948+
ast_debug(2, "Called Subscriber Held does not apply: channel state is %d\n", ast_channel_state(ast));
2949+
} else if (!p->owner || !p->subs[ANALOG_SUB_REAL].owner || strcmp(ast_channel_appl(p->subs[ANALOG_SUB_REAL].owner), "AppDial")) {
2950+
/* Called Subscriber held only applies to incoming calls, not outgoing calls.
2951+
* We can't use p->outgoing because that is always true, for both incoming and outgoing calls, so it's not accurate.
2952+
* We can check the channel application/data instead.
2953+
* For incoming calls to the channel, it will look like: AppDial / (Outgoing Line)
2954+
* We only want this behavior for regular calls anyways (and not, say, Queue),
2955+
* so this would actually work great. But accessing ast_channel_appl can cause a crash if there are no calls left,
2956+
* so this check must occur AFTER we confirm the channel state *is* still UP.
2957+
*/
2958+
ast_debug(2, "Called Subscriber Held does not apply: not an incoming call\n");
2959+
} else if (analog_is_off_hook(p)) {
2960+
ast_log(LOG_WARNING, "Got ONHOOK but channel %d is off hook?\n", p->channel); /* Shouldn't happen */
2961+
} else {
2962+
ast_verb(3, "Holding incoming call %s for channel %d\n", ast_channel_name(ast), p->channel);
2963+
/* Inhibit dahdi_hangup from getting called, and do nothing else now.
2964+
* When the DAHDI channel goes off hook again, it'll just get reconnected with the incoming call,
2965+
* to which, as far as its concerned, nothing has happened. */
2966+
p->cshactive = 1; /* Keep track that this DAHDI channel is currently being held by an incoming call. */
2967+
break;
2968+
}
2969+
}
29362970
ast_queue_control_data(ast, AST_CONTROL_PVT_CAUSE_CODE, cause_code, data_size);
29372971
ast_channel_hangupcause_hash_set(ast, cause_code, data_size);
29382972
switch (p->sig) {
@@ -3809,6 +3843,7 @@ void *analog_handle_init_event(struct analog_pvt *i, int event)
38093843
case ANALOG_SIG_FXOKS:
38103844
res = analog_off_hook(i);
38113845
i->fxsoffhookstate = 1;
3846+
i->cshactive = 0;
38123847
if (res && (errno == EBUSY)) {
38133848
break;
38143849
}

channels/sig_analog.h

+2
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@ struct analog_pvt {
289289
unsigned int ani_wink_time:16; /* Safe wait time before we wink to start ANI spill */
290290

291291
unsigned int answeronpolarityswitch:1;
292+
unsigned int calledsubscriberheld:1; /*!< TRUE if a single incoming call can hold an FXS channel */
292293
unsigned int callreturn:1;
293294
unsigned int cancallforward:1;
294295
unsigned int canpark:1;
@@ -330,6 +331,7 @@ struct analog_pvt {
330331

331332
/* XXX: All variables after this are internal */
332333
unsigned int callwaiting:1; /*!< TRUE if call waiting is enabled. (Active option) */
334+
unsigned int cshactive:1; /*!< TRUE if FXS channel is currently held by an incoming call */
333335
unsigned int dialednone:1;
334336
unsigned int dialing:1; /*!< TRUE if in the process of dialing digits or sending something */
335337
unsigned int dnd:1; /*!< TRUE if Do-Not-Disturb is enabled. */

configs/samples/chan_dahdi.conf.sample

+12
Original file line numberDiff line numberDiff line change
@@ -755,6 +755,18 @@ usecallingpres=yes
755755
;
756756
callwaitingcallerid=yes
757757
;
758+
; Whether or not to allow users to go on-hook when receiving an incoming call
759+
; without disconnecting it. Users can later resume the call from any phone
760+
; on the same physical phone line (the same DAHDI channel).
761+
; This setting only has an effect on FXS (FXO-signalled) channels where there
762+
; is only a single incoming call to the DAHDI channel, using the Dial application.
763+
; (This is a convenience mechanism to avoid users wishing to resume a conversation
764+
; at a different phone from leaving a phone off the hook, resuming elsewhere,
765+
; and forgetting to restore the original phone on hook afterwards.)
766+
; Default is no.
767+
;
768+
;calledsubscriberheld=yes
769+
;
758770
; Support three-way calling
759771
;
760772
threewaycalling=yes

0 commit comments

Comments
 (0)