mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-04 11:58:52 +00:00
app_sf: Add full tech-agnostic SF support
Adds tech-agnostic support for SF signaling by adding SF sender and receiver applications as well as Dial integration. ASTERISK-29802 #close Change-Id: I7ec50752e9a661af639425e5d1e339f17411bcad
This commit is contained in:
committed by
Friendly Automation
parent
076d502694
commit
2ed004846a
173
main/app.c
173
main/app.c
@@ -830,6 +830,157 @@ static int external_sleep(struct ast_channel *chan, int ms)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sf_stream(struct ast_channel *chan, struct ast_channel *chan2, const char *digits, int frequency, int is_external)
|
||||
{
|
||||
/* Bell System Technical Journal 39 (Nov. 1960) */
|
||||
#define SF_ON 67
|
||||
#define SF_OFF 33
|
||||
#define SF_BETWEEN 600
|
||||
|
||||
const char *ptr;
|
||||
int res;
|
||||
struct ast_silence_generator *silgen = NULL, *silgen2 = NULL;
|
||||
char *freq;
|
||||
int (*my_sleep)(struct ast_channel *chan, int ms);
|
||||
|
||||
if (frequency >= 100000) {
|
||||
ast_log(LOG_WARNING, "Frequency too large: %d\n", frequency);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (is_external) {
|
||||
my_sleep = external_sleep;
|
||||
} else {
|
||||
my_sleep = ast_safe_sleep;
|
||||
}
|
||||
|
||||
/* Need a quiet time before sending digits. */
|
||||
if (ast_opt_transmit_silence) {
|
||||
silgen = ast_channel_start_silence_generator(chan);
|
||||
if (chan2) {
|
||||
silgen2 = ast_channel_start_silence_generator(chan2);
|
||||
}
|
||||
}
|
||||
if (chan2) {
|
||||
ast_autoservice_start(chan2);
|
||||
}
|
||||
res = my_sleep(chan, 100);
|
||||
if (chan2) {
|
||||
ast_autoservice_stop(chan2);
|
||||
}
|
||||
if (res) {
|
||||
goto sf_stream_cleanup;
|
||||
}
|
||||
|
||||
/* len(SF_ON) + len(SF_OFF) + len(0) + maxlen(frequency) + /,/ + null terminator = 2 + 2 + 1 + 5 at most + 3 + 1 = 14 */
|
||||
#define SF_BUF_LEN 20
|
||||
freq = ast_alloca(SF_BUF_LEN); /* min 20 to avoid compiler warning about insufficient buffer */
|
||||
/* pauses need to send audio, so send 0 Hz */
|
||||
snprintf(freq, SF_BUF_LEN, "%d/%d,%d/%d", frequency, SF_ON, 0, SF_OFF);
|
||||
|
||||
for (ptr = digits; *ptr; ptr++) {
|
||||
if (*ptr == 'w') {
|
||||
/* 'w' -- wait half a second */
|
||||
if (chan2) {
|
||||
ast_autoservice_start(chan2);
|
||||
}
|
||||
res = my_sleep(chan, 500);
|
||||
if (chan2) {
|
||||
ast_autoservice_stop(chan2);
|
||||
}
|
||||
if (res) {
|
||||
break;
|
||||
}
|
||||
} else if (*ptr == 'h' || *ptr == 'H') {
|
||||
/* 'h' -- 2600 Hz for half a second, but
|
||||
only to far end of trunk, not near end */
|
||||
ast_playtones_start(chan, 0, "2600", 0);
|
||||
if (chan2) {
|
||||
ast_playtones_start(chan2, 0, "0", 0);
|
||||
ast_autoservice_start(chan2);
|
||||
}
|
||||
res = my_sleep(chan, 250);
|
||||
ast_senddigit_mf_end(chan);
|
||||
if (chan2) {
|
||||
ast_autoservice_stop(chan2);
|
||||
ast_senddigit_mf_end(chan2);
|
||||
}
|
||||
if (res) {
|
||||
break;
|
||||
}
|
||||
} else if (strchr("0123456789*#ABCDabcdwWfF", *ptr)) {
|
||||
if (*ptr == 'f' || *ptr == 'F') {
|
||||
/* ignore return values if not supported by channel */
|
||||
ast_indicate(chan, AST_CONTROL_FLASH);
|
||||
} else if (*ptr == 'W') {
|
||||
/* ignore return values if not supported by channel */
|
||||
ast_indicate(chan, AST_CONTROL_WINK);
|
||||
} else {
|
||||
/* Character represents valid SF */
|
||||
int beeps;
|
||||
if (*ptr == '*') {
|
||||
beeps = 11;
|
||||
} else if (*ptr == '#') {
|
||||
beeps = 12;
|
||||
} else if (*ptr == 'D') {
|
||||
beeps = 13;
|
||||
} else if (*ptr == 'C') {
|
||||
beeps = 14;
|
||||
} else if (*ptr == 'B') {
|
||||
beeps = 15;
|
||||
} else if (*ptr == 'A') {
|
||||
beeps = 16;
|
||||
} else {
|
||||
beeps = (*ptr == '0') ? 10 : *ptr - '0';
|
||||
}
|
||||
while (beeps-- > 0) {
|
||||
ast_playtones_start(chan, 0, freq, 0);
|
||||
if (chan2) {
|
||||
ast_playtones_start(chan2, 0, freq, 0);
|
||||
ast_autoservice_start(chan2);
|
||||
}
|
||||
res = my_sleep(chan, SF_ON + SF_OFF);
|
||||
ast_senddigit_mf_end(chan);
|
||||
if (chan2) {
|
||||
ast_autoservice_stop(chan2);
|
||||
ast_senddigit_mf_end(chan2);
|
||||
}
|
||||
if (res) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* pause between digits */
|
||||
ast_playtones_start(chan, 0, "0", 0);
|
||||
if (chan2) {
|
||||
ast_playtones_start(chan2, 0, "0", 0);
|
||||
ast_autoservice_start(chan2);
|
||||
}
|
||||
res = my_sleep(chan, SF_BETWEEN);
|
||||
if (chan2) {
|
||||
ast_autoservice_stop(chan2);
|
||||
ast_senddigit_mf_end(chan2);
|
||||
}
|
||||
ast_senddigit_mf_end(chan);
|
||||
if (res) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
ast_log(LOG_WARNING, "Illegal SF character '%c' in string. (0-9A-DwWfFhH allowed)\n", *ptr);
|
||||
}
|
||||
}
|
||||
|
||||
sf_stream_cleanup:
|
||||
if (silgen) {
|
||||
ast_channel_stop_silence_generator(chan, silgen);
|
||||
}
|
||||
if (silgen2) {
|
||||
ast_channel_stop_silence_generator(chan2, silgen2);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int mf_stream(struct ast_channel *chan, struct ast_channel *chan2, const char *digits, int between, unsigned int duration,
|
||||
unsigned int durationkp, unsigned int durationst, int is_external)
|
||||
{
|
||||
@@ -869,7 +1020,13 @@ static int mf_stream(struct ast_channel *chan, struct ast_channel *chan2, const
|
||||
for (ptr = digits; *ptr; ptr++) {
|
||||
if (*ptr == 'w') {
|
||||
/* 'w' -- wait half a second */
|
||||
if (chan2) {
|
||||
ast_autoservice_start(chan2);
|
||||
}
|
||||
res = my_sleep(chan, 500);
|
||||
if (chan2) {
|
||||
ast_autoservice_stop(chan2);
|
||||
}
|
||||
if (res) {
|
||||
break;
|
||||
}
|
||||
@@ -1007,6 +1164,22 @@ dtmf_stream_cleanup:
|
||||
return res;
|
||||
}
|
||||
|
||||
int ast_sf_stream(struct ast_channel *chan, struct ast_channel *peer, struct ast_channel *chan2, const char *digits, int frequency, int is_external)
|
||||
{
|
||||
int res;
|
||||
if (frequency <= 0) {
|
||||
frequency = 2600;
|
||||
}
|
||||
if (!is_external && !chan2 && peer && ast_autoservice_start(peer)) {
|
||||
return -1;
|
||||
}
|
||||
res = sf_stream(chan, chan2, digits, frequency, is_external);
|
||||
if (!is_external && !chan2 && peer && ast_autoservice_stop(peer)) {
|
||||
res = -1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int ast_mf_stream(struct ast_channel *chan, struct ast_channel *peer, struct ast_channel *chan2, const char *digits,
|
||||
int between, unsigned int duration, unsigned int durationkp, unsigned int durationst, int is_external)
|
||||
{
|
||||
|
Reference in New Issue
Block a user