Added more caller ID alerting signals

If supported by the AN, different alerting signals can be configured.
See command line help for details.
This commit is contained in:
Andreas Eversberg 2023-02-05 10:55:44 +01:00
parent 4027c98c53
commit 972c43d74e
5 changed files with 121 additions and 27 deletions

View File

@ -45,7 +45,8 @@
#define DBV_TO_DBM -0.086 /* impedance 1020 Ohms */ #define DBV_TO_DBM -0.086 /* impedance 1020 Ohms */
#define DTAS_TX_DBV -16.0 /* relative to 1 Volt RMS */ #define DTAS_TX_DBV -16.0 /* relative to 1 Volt RMS */
#define DTAS2_DURATION 0.080 /* 80 ms (DT-AS Off-Hook) */ #define DTAS_DURATION 0.100 /* 100 ms (DT-AS On-Hook) */
#define DTAS_CW_DURATION 0.080 /* 80 ms (DT-AS Off-Hook) */
#define FSK_TX_DBV -15.5 /* relative to 1 Volt RMS */ #define FSK_TX_DBV -15.5 /* relative to 1 Volt RMS */
#define FSK_BAUD_RATE 1200 #define FSK_BAUD_RATE 1200
#define FSK_BIT_ADJUST 0.5 /* must be 0.5 to completely sync each bit */ #define FSK_BIT_ADJUST 0.5 /* must be 0.5 to completely sync each bit */
@ -61,6 +62,7 @@
#define WAIT_RING_FSK 0.700 /* wait 500ms-2000ms after ring before sending FSK */ #define WAIT_RING_FSK 0.700 /* wait 500ms-2000ms after ring before sending FSK */
#define WAIT_CW_DTAS 0.050 /* wait 50ms after CW before sending DT_AS */ #define WAIT_CW_DTAS 0.050 /* wait 50ms after CW before sending DT_AS */
#define WAIT_DTAS_FSK 0.200 /* wait 200 for FSK after DT_AS */
#define WAIT_DTAS_TEACK 0.210 /* wait 160ms + 50ms(latency) for TE-ACK after DT_AS */ #define WAIT_DTAS_TEACK 0.210 /* wait 160ms + 50ms(latency) for TE-ACK after DT_AS */
#define WAIT_TEACK_FSK 0.055 /* wait 55ms after recognition of TE-ACK before sending FSK */ #define WAIT_TEACK_FSK 0.055 /* wait 55ms after recognition of TE-ACK before sending FSK */
#define WAIT_RING_DTMF 0.500 /* wait after 1st ring before sending DTMF */ #define WAIT_RING_DTMF 0.500 /* wait after 1st ring before sending DTMF */
@ -179,6 +181,8 @@ int callerid_set(callerid_t *cid, int cw, int dt_as, const char *callerid, uint8
return -EINVAL; return -EINVAL;
} }
cid->cw = cw;
if (!cid->use_dtmf) { if (!cid->use_dtmf) {
uint8_t *p; uint8_t *p;
uint8_t par = 0; uint8_t par = 0;
@ -319,7 +323,7 @@ again:
cid->dtas_phaseshift65536[1] = TONE_DTAS_2 / (double)cid->samplerate * 65536.0; cid->dtas_phaseshift65536[1] = TONE_DTAS_2 / (double)cid->samplerate * 65536.0;
cid->dtas_phase65536[0] = 0.0; cid->dtas_phase65536[0] = 0.0;
cid->dtas_phase65536[1] = 0.0; cid->dtas_phase65536[1] = 0.0;
cid->dt_as_count = (int)(DTAS2_DURATION * (double)cid->samplerate); cid->dt_as_count = (int)(((cid->cw) ? DTAS_CW_DURATION : DTAS_DURATION) * (double)cid->samplerate);
PDEBUG(DDSP, DEBUG_DEBUG, "Now start DT_AS transmission.\n"); PDEBUG(DDSP, DEBUG_DEBUG, "Now start DT_AS transmission.\n");
break; break;
case CID_STATE_WAIT_DTMF: case CID_STATE_WAIT_DTMF:
@ -361,9 +365,17 @@ again:
length -= i; length -= i;
count += i; count += i;
if (cid->dt_as_count == 0) { if (cid->dt_as_count == 0) {
/* wait for TE ACK */ if (cid->cw) {
cid->state = CID_STATE_WAIT_TE_ACK; /* wait for TE ACK */
cid->wait = (int)(WAIT_DTAS_TEACK * (double)cid->samplerate); PDEBUG(DDSP, DEBUG_DEBUG, "DT-AS transmission done, waiting for TE-ACK.\n");
cid->state = CID_STATE_WAIT_TE_ACK;
cid->wait = (int)(WAIT_DTAS_TEACK * (double)cid->samplerate);
} else {
/* wait for FSK */
PDEBUG(DDSP, DEBUG_DEBUG, "DT-AS transmission done, waiting for FSK.\n");
cid->state = CID_STATE_WAIT_FSK;
cid->wait = (int)(WAIT_DTAS_FSK * (double)cid->samplerate);
}
goto again; goto again;
} }
break; break;
@ -388,7 +400,10 @@ again:
samples += ret; samples += ret;
length -= ret; length -= ret;
if (length) { if (length) {
PDEBUG(DDSP, DEBUG_DEBUG, "FSK transmission done, waiting to re-establish audio.\n"); if (cid->cw)
PDEBUG(DDSP, DEBUG_DEBUG, "FSK transmission done, waiting to re-establish audio.\n");
else
PDEBUG(DDSP, DEBUG_DEBUG, "FSK transmission done, waiting to send ringing.\n");
cid->wait = (int)(WAIT_FSK_END * (double)cid->samplerate); cid->wait = (int)(WAIT_FSK_END * (double)cid->samplerate);
cid->state = CID_STATE_WAIT_END; cid->state = CID_STATE_WAIT_END;
break; break;

View File

@ -17,6 +17,7 @@ enum cid_state {
typedef struct callerid { typedef struct callerid {
/* settings */ /* settings */
int samplerate; /* sample rate to render output */ int samplerate; /* sample rate to render output */
char cw; /* use off-hook caller ID */
char use_dtmf; /* if set, use DTMF instead of FSK, start digit given */ char use_dtmf; /* if set, use DTMF instead of FSK, start digit given */
/* play states */ /* play states */

View File

@ -42,7 +42,7 @@ static const char *name = "pstn";
static const char *subscribers[SUBSCRIBER_MAX] = { "" }; static const char *subscribers[SUBSCRIBER_MAX] = { "" };
static int subscriber_num = 0; static int subscriber_num = 0;
static int tx_delay = 0; static int tx_delay = 0;
static int clip = 0; static enum pstn_cid_method clip = CID_METHOD_NONE;
static int cid_bell = 0; static int cid_bell = 0;
static int cid_dtmf = 0; static int cid_dtmf = 0;
static int clip_date = 0; static int clip_date = 0;
@ -50,7 +50,7 @@ static int enblock = 4;
static int recall = 0; static int recall = 0;
static int ringing_types_incoming[SUBSCRIBER_MAX] = { 0 }; static int ringing_types_incoming[SUBSCRIBER_MAX] = { 0 };
static int ringing_type_incoming_num = 0; static int ringing_type_incoming_num = 0;
static int ringing_type_hold = 1; static int ringing_type_hold = 0;
static enum tones_type tones_type = TONES_TYPE_GERMAN; static enum tones_type tones_type = TONES_TYPE_GERMAN;
static int rt_prio = 1; static int rt_prio = 1;
#define MAX_CC_ARGS 1024 #define MAX_CC_ARGS 1024
@ -85,8 +85,12 @@ static void print_help()
printf(" Give a delay in milliseconds. This is required for modem/fax. Audio\n"); printf(" Give a delay in milliseconds. This is required for modem/fax. Audio\n");
printf(" toward ISDN interface is buffered with the given delay.\n"); printf(" toward ISDN interface is buffered with the given delay.\n");
printf(" This feature alters dejittering strategy.\n"); printf(" This feature alters dejittering strategy.\n");
printf(" --clip [--clip-date]\n"); printf(" --clip pulse | stop | dtas | dtas-lr [--clip-date]\n");
printf(" Enable caller ID, optionally with date info. (disabled by default)\n"); printf(" Enable caller ID, optionally with date info. (disabled by default)\n");
printf(" Use 'pulse' to send first ringing via pulse signal and CLIP afterwards.\n");
printf(" Use 'stop' to stop after first ring, send CLIP and continue ringing.\n");
printf(" Use 'dtas' to send CLIP with DT-AS before first ring.\n");
printf(" Use 'dtas-lr' to send CLIP as above, but with reversed polarity.\n");
printf(" --clip-date\n"); printf(" --clip-date\n");
printf(" Send date+time with caller ID.\n"); printf(" Send date+time with caller ID.\n");
printf(" --cid-bell\n"); printf(" --cid-bell\n");
@ -157,7 +161,7 @@ static void add_options(void)
option_add('n', "name", 1); option_add('n', "name", 1);
option_add('I', "subscriber", 1); option_add('I', "subscriber", 1);
option_add(OPT_TX_DELAY, "tx-delay", 1); option_add(OPT_TX_DELAY, "tx-delay", 1);
option_add(OPT_TX_CLIP, "clip", 0); option_add(OPT_TX_CLIP, "clip", 1);
option_add(OPT_TX_CLIP_DATE, "clip-date", 0); option_add(OPT_TX_CLIP_DATE, "clip-date", 0);
option_add(OPT_TX_CID_BELL, "cid-bell", 0); option_add(OPT_TX_CID_BELL, "cid-bell", 0);
option_add(OPT_TX_CID_DTMF, "cid-dtmf", 1); option_add(OPT_TX_CID_DTMF, "cid-dtmf", 1);
@ -209,7 +213,18 @@ static int handle_options(int short_option, int argi, char **argv)
tx_delay = atoi(argv[argi]); tx_delay = atoi(argv[argi]);
break; break;
case OPT_TX_CLIP: case OPT_TX_CLIP:
clip = 1; if (!strcasecmp(argv[argi], "pulse"))
clip = CID_METHOD_PULSE;
else if (!strcasecmp(argv[argi], "stop"))
clip = CID_METHOD_STOP;
else if (!strcasecmp(argv[argi], "dtas"))
clip = CID_METHOD_DTAS;
else if (!strcasecmp(argv[argi], "dtas-lr"))
clip = CID_METHOD_DTAS_LR;
else {
fprintf(stderr, "Invalid clip method!\n");
return -EINVAL;
}
break; break;
case OPT_TX_CLIP_DATE: case OPT_TX_CLIP_DATE:
clip_date = 1; clip_date = 1;

View File

@ -311,7 +311,7 @@ static void pstn_new_state(pstn_t *pstn, enum pstn_state state)
} }
/* initialization and configuration of interface instance */ /* initialization and configuration of interface instance */
int pstn_init(pstn_t *pstn, const char *name, const char *socketname, const char **subscribers, int subscriber_num, uint8_t serving_location, int tx_delay, int clip, int cid_bell, int cid_dtmf, int clip_date, int enblock, int recall, int *ringing_types_incoming, int ringing_type_hold, enum tones_type tones_type, char law) int pstn_init(pstn_t *pstn, const char *name, const char *socketname, const char **subscribers, int subscriber_num, uint8_t serving_location, int tx_delay, enum pstn_cid_method clip, int cid_bell, int cid_dtmf, int clip_date, int enblock, int recall, int *ringing_types_incoming, int ringing_type_hold, enum tones_type tones_type, char law)
{ {
int i; int i;
int rc; int rc;
@ -436,6 +436,8 @@ static void timer_off(pstn_t *pstn)
static void callerid_on(pstn_t *pstn, int cw, const char *callerid, uint8_t caller_type) static void callerid_on(pstn_t *pstn, int cw, const char *callerid, uint8_t caller_type)
{ {
int dtas = 0;
/* DTMF on CW not supported */ /* DTMF on CW not supported */
if (cw && pstn->cid_dtmf) { if (cw && pstn->cid_dtmf) {
PDEBUG(DTEL, DEBUG_INFO, "DTMF CID is not allowed for waiting call, don't sending CID.\n"); PDEBUG(DTEL, DEBUG_INFO, "DTMF CID is not allowed for waiting call, don't sending CID.\n");
@ -444,21 +446,30 @@ static void callerid_on(pstn_t *pstn, int cw, const char *callerid, uint8_t call
PDEBUG(DTEL, DEBUG_DEBUG, "Schedule caller ID transmission. (cw=%d, callerid=%s)\n", cw, callerid); PDEBUG(DTEL, DEBUG_DEBUG, "Schedule caller ID transmission. (cw=%d, callerid=%s)\n", cw, callerid);
/* add DT_AS on waitng call */
callerid_set(&pstn->callerid, cw, (cw) ? 1 : 0, callerid, caller_type, pstn->clip_date);
if (cw) { if (cw) {
dtas = 1;
pstn->callerid_state = PSTN_CID_STATE_WAIT1; pstn->callerid_state = PSTN_CID_STATE_WAIT1;
/* add delay when cw */ /* add delay when cw */
pstn->callerid_wait1 = 8000; pstn->callerid_wait1 = 8000;
pstn->callerid_wait2 = 0; pstn->callerid_wait2 = 0;
} else { } else {
pstn->callerid_state = PSTN_CID_STATE_WAIT1; if (pstn->clip == CID_METHOD_DTAS || pstn->clip == CID_METHOD_DTAS_LR) {
/* add delay when ringing */ dtas = 1;
pstn->callerid_wait1 = 8000; pstn->callerid_state = PSTN_CID_STATE_WAIT1;
pstn->callerid_wait2 = 16000; /* wait for channel and do not wait to ring afterwards */
pstn->callerid_wait1 = 4000;
pstn->callerid_wait2 = 0;
} else {
pstn->callerid_state = PSTN_CID_STATE_WAIT1;
/* wait to stop ringing and wait to continue ringing */
pstn->callerid_wait1 = 8000;
pstn->callerid_wait2 = 16000;
}
} }
/* add DT_AS on waitng call */
callerid_set(&pstn->callerid, cw, dtas, callerid, caller_type, pstn->clip_date);
/* turn DTMF on, to detect TE-ACK */ /* turn DTMF on, to detect TE-ACK */
if (cw) { if (cw) {
/* start DTMF */ /* start DTMF */
@ -630,7 +641,7 @@ static void bchannel_rx_tx(pstn_t *pstn, uint8_t *data, int len)
/* wait before sending callerid */ /* wait before sending callerid */
pstn->callerid_wait1 -= len; pstn->callerid_wait1 -= len;
if (pstn->callerid_wait1 <= 0) { if (pstn->callerid_wait1 <= 0) {
if (pstn->call[PSTN_CALL_ACTIVE]->state == CALL_STATE_ALERTING_SUB) { if (pstn->clip == CID_METHOD_STOP && pstn->call[PSTN_CALL_ACTIVE]->state == CALL_STATE_ALERTING_SUB) {
PDEBUG(DTEL, DEBUG_DEBUG, "Stop ringing.\n"); PDEBUG(DTEL, DEBUG_DEBUG, "Stop ringing.\n");
uint8_t ie[3] = { PSTN_V5_IE_STEADY_SIGNAL, 1, 0x80 | 0x0e}; uint8_t ie[3] = { PSTN_V5_IE_STEADY_SIGNAL, 1, 0x80 | 0x0e};
v5_sig_req(pstn, ie, sizeof(ie)); v5_sig_req(pstn, ie, sizeof(ie));
@ -671,7 +682,13 @@ static void bchannel_rx_tx(pstn_t *pstn, uint8_t *data, int len)
if (pstn->callerid_wait2 <= 0) { if (pstn->callerid_wait2 <= 0) {
pstn->callerid_state = PSTN_CID_STATE_OFF; pstn->callerid_state = PSTN_CID_STATE_OFF;
if (pstn->call[PSTN_CALL_ACTIVE]->state == CALL_STATE_ALERTING_SUB) { if (pstn->call[PSTN_CALL_ACTIVE]->state == CALL_STATE_ALERTING_SUB) {
PDEBUG(DTEL, DEBUG_DEBUG, "Continue with ringing.\n"); if (pstn->clip == CID_METHOD_DTAS_LR) {
pstn->reversed = 0;
PDEBUG(DTEL, DEBUG_DEBUG, "Set normal polarity.\n");
uint8_t ie[3] = { PSTN_V5_IE_STEADY_SIGNAL, 1, 0x80 | PSTN_V5_STEADY_SIGNAL_NORMAL};
v5_sig_req(pstn, ie, sizeof(ie));
}
PDEBUG(DTEL, DEBUG_DEBUG, "Start ringing.\n");
uint8_t ie[3] = { PSTN_V5_IE_CADENCED_RINGING, 1, 0x80 | pstn->ringing_types_incoming[pstn->call[PSTN_CALL_ACTIVE]->subscriber_index] }; uint8_t ie[3] = { PSTN_V5_IE_CADENCED_RINGING, 1, 0x80 | pstn->ringing_types_incoming[pstn->call[PSTN_CALL_ACTIVE]->subscriber_index] };
v5_sig_req(pstn, ie, sizeof(ie)); v5_sig_req(pstn, ie, sizeof(ie));
} }
@ -892,8 +909,36 @@ void cc_message(osmo_cc_endpoint_t *ep, uint32_t callref, osmo_cc_msg_t *msg)
osmo_cc_ll_msg(&pstn->cc_ep, pstn_call->cc_callref, new_msg); osmo_cc_ll_msg(&pstn->cc_ep, pstn_call->cc_callref, new_msg);
if (pstn->state == PSTN_STATE_NULL) { if (pstn->state == PSTN_STATE_NULL) {
/* send message to V5 */ /* send message to V5 */
uint8_t ie[3] = { PSTN_V5_IE_CADENCED_RINGING, 1, 0x80 | pstn->ringing_types_incoming[pstn_call->subscriber_index] }; switch (pstn->clip) {
v5_est_req(pstn, ie, sizeof(ie)); case CID_METHOD_DTAS:
{
v5_est_req(pstn, NULL, 0);
break;
}
case CID_METHOD_DTAS_LR:
{
pstn->reversed = 1;
PDEBUG(DTEL, DEBUG_DEBUG, "Reversed polarity.\n");
uint8_t ie[3] = { PSTN_V5_IE_STEADY_SIGNAL, 1, 0x80 | PSTN_V5_STEADY_SIGNAL_REVERSED};
v5_est_req(pstn, ie, sizeof(ie));
break;
}
case CID_METHOD_PULSE:
{
PDEBUG(DTEL, DEBUG_DEBUG, "Start one ring pulse.\n");
uint8_t ie[5] = { PSTN_V5_IE_PULSED_SIGNAL, 3, 0x80 | PSTN_V5_PULSED_SIGNAL_INIT_RING, 0x60, 0x80 | 0x40 | 0x01};
v5_est_req(pstn, ie, sizeof(ie));
break;
}
case CID_METHOD_STOP:
case CID_METHOD_NONE:
{
PDEBUG(DTEL, DEBUG_DEBUG, "Start ringing.\n");
uint8_t ie[3] = { PSTN_V5_IE_CADENCED_RINGING, 1, 0x80 | pstn->ringing_types_incoming[pstn_call->subscriber_index] };
v5_est_req(pstn, ie, sizeof(ie));
break;
}
}
if (pstn->clip) { if (pstn->clip) {
/* send callerid */ /* send callerid */
callerid_on(pstn, 0, callerid, caller_type); callerid_on(pstn, 0, callerid, caller_type);
@ -1543,7 +1588,7 @@ static void v5_receive(pstn_t *pstn, uint8_t *data, int len)
case PSTN_EVENT_EST_IND: case PSTN_EVENT_EST_IND:
/* in case of collision, just treat as ACK and proceed outgoing call */ /* in case of collision, just treat as ACK and proceed outgoing call */
if (pstn->state == PSTN_STATE_EST_LE) { if (pstn->state == PSTN_STATE_EST_LE) {
PDEBUG(DTEL, DEBUG_INFO, " -> Handle establish collision, send ACK.\n"); PDEBUG(DTEL, DEBUG_NOTICE, "Handle establish collision, send ACK. A possible ACK from AN will be ignored.\n");
/* send ack message to V5 */ /* send ack message to V5 */
v5_est_ack_req(pstn); v5_est_ack_req(pstn);
/* treat as establish acknowledgement from PSTN interface */ /* treat as establish acknowledgement from PSTN interface */
@ -1668,7 +1713,13 @@ static void v5_disc_req_and_cleanup(pstn_t *pstn)
/* change state */ /* change state */
pstn_new_state(pstn, PSTN_STATE_NULL); pstn_new_state(pstn, PSTN_STATE_NULL);
v5_send(pstn, PSTN_EVENT_DISC_REQ, NULL, 0); if (pstn->reversed) {
pstn->reversed = 0;
PDEBUG(DTEL, DEBUG_DEBUG, "Normal polarity.\n");
uint8_t ie[3] = { PSTN_V5_IE_STEADY_SIGNAL, 1, 0x80 | PSTN_V5_STEADY_SIGNAL_NORMAL};
v5_send(pstn, PSTN_EVENT_DISC_REQ, ie, sizeof(ie));
} else
v5_send(pstn, PSTN_EVENT_DISC_REQ, NULL, 0);
} }

View File

@ -39,9 +39,12 @@ enum pstn_v5_ie {
}; };
enum pstn_v5_signal { enum pstn_v5_signal {
PSTN_V5_STEADY_SIGNAL_NORMAL = 0x00,
PSTN_V5_STEADY_SIGNAL_REVERSED = 0x01,
PSTN_V5_STEADY_SIGNAL_OFF_HOOK = 0x04, PSTN_V5_STEADY_SIGNAL_OFF_HOOK = 0x04,
PSTN_V5_STEADY_SIGNAL_ON_HOOK = 0x05, PSTN_V5_STEADY_SIGNAL_ON_HOOK = 0x05,
PSTN_V5_STEADY_SIGNAL_STOP_RING = 0x0e, PSTN_V5_STEADY_SIGNAL_STOP_RING = 0x0e,
PSTN_V5_PULSED_SIGNAL_INIT_RING = 0x79,
PSTN_V5_PULSED_SIGNAL_ON_HOOK = 0x7c, PSTN_V5_PULSED_SIGNAL_ON_HOOK = 0x7c,
}; };
@ -66,6 +69,14 @@ enum pstn_call_state {
CALL_STATE_DISCONNECT_NET, CALL_STATE_DISCONNECT_NET,
}; };
enum pstn_cid_method {
CID_METHOD_NONE = 0,
CID_METHOD_PULSE,
CID_METHOD_STOP,
CID_METHOD_DTAS,
CID_METHOD_DTAS_LR,
};
enum pstn_cid_state { enum pstn_cid_state {
PSTN_CID_STATE_OFF = 0, PSTN_CID_STATE_OFF = 0,
PSTN_CID_STATE_WAIT1, PSTN_CID_STATE_WAIT1,
@ -102,7 +113,7 @@ typedef struct pstn {
int subscriber_num; /* number of subscribers and tinging types (incoming) */ int subscriber_num; /* number of subscribers and tinging types (incoming) */
int serving_location; /* who we serve when sending causes towards interface */ int serving_location; /* who we serve when sending causes towards interface */
int tx_delay; /* delay to be used for fax/modem jitter buffering */ int tx_delay; /* delay to be used for fax/modem jitter buffering */
int clip; /* send caller ID */ enum pstn_cid_method clip; /* send caller ID */
int clip_date; /* send date with caller ID */ int clip_date; /* send date with caller ID */
int cid_bell; /* use V.23 or Bell 202 FSK tones */ int cid_bell; /* use V.23 or Bell 202 FSK tones */
int cid_dtmf; /* use DTMF instead of FSK caller ID */ int cid_dtmf; /* use DTMF instead of FSK caller ID */
@ -117,6 +128,7 @@ typedef struct pstn {
struct timer timer; /* timer for enblock dialing */ struct timer timer; /* timer for enblock dialing */
enum timer_ident timer_ident; /* why is the timer running */ enum timer_ident timer_ident; /* why is the timer running */
char dialing[33]; /* register for en-block dialing */ char dialing[33]; /* register for en-block dialing */
int reversed; /* if polarity is reversed */
int dtmf_on; /* we are listening to DTMF */ int dtmf_on; /* we are listening to DTMF */
int pulse_on; /* we take pulses */ int pulse_on; /* we take pulses */
enum pstn_cid_state callerid_state; /* transmitting callerid */ enum pstn_cid_state callerid_state; /* transmitting callerid */
@ -142,7 +154,7 @@ typedef struct pstn {
void pstn_destroy(pstn_t *pstn_ep); void pstn_destroy(pstn_t *pstn_ep);
pstn_t *pstn_create(void); pstn_t *pstn_create(void);
int pstn_init(pstn_t *pstn, const char *name, const char *socketname, const char **subscribers, int subscriber_num, uint8_t serving_location, int tx_delay, int clip, int cid_bell, int cid_dtmf, int clip_date, int enblock, int recall, int *ringing_types_incoming, int ringing_type_hold, enum tones_type tones_type, char law); int pstn_init(pstn_t *pstn, const char *name, const char *socketname, const char **subscribers, int subscriber_num, uint8_t serving_location, int tx_delay, enum pstn_cid_method clip, int cid_bell, int cid_dtmf, int clip_date, int enblock, int recall, int *ringing_types_incoming, int ringing_type_hold, enum tones_type tones_type, char law);
void cc_message(osmo_cc_endpoint_t *ep, uint32_t callref, osmo_cc_msg_t *msg); void cc_message(osmo_cc_endpoint_t *ep, uint32_t callref, osmo_cc_msg_t *msg);
void rtp_work(pstn_t *pstn_ep); void rtp_work(pstn_t *pstn_ep);
void pstn_work(pstn_t *pstn_ep); void pstn_work(pstn_t *pstn_ep);