Merge "ARI POST DTMF: Make not compete with channel's media thread." into 13

13.23
George Joseph 7 years ago committed by Gerrit Code Review
commit aedbf5ba58

@ -923,24 +923,51 @@ void ast_replace_sigchld(void);
void ast_unreplace_sigchld(void); void ast_unreplace_sigchld(void);
/*! /*!
\brief Send DTMF to a channel * \brief Send a string of DTMF digits to a channel
*
\param chan The channel that will receive the DTMF frames * \param chan The channel that will receive the DTMF frames
\param peer (optional) Peer channel that will be autoserviced while the * \param peer (optional) Peer channel that will be autoserviced while the
primary channel is receiving DTMF * primary channel is receiving DTMF
\param digits This is a string of characters representing the DTMF digits * \param digits This is a string of characters representing the DTMF digits
to be sent to the channel. Valid characters are * to be sent to the channel. Valid characters are
"0123456789*#abcdABCD". Note: You can pass arguments 'f' or * "0123456789*#abcdABCD". Note: You can pass arguments 'f' or
'F', if you want to Flash the channel (if supported by the * 'F', if you want to Flash the channel (if supported by the
channel), or 'w' to add a 500 millisecond pause to the DTMF * channel), or 'w' to add a 500 millisecond pause to the DTMF
sequence. * sequence.
\param between This is the number of milliseconds to wait in between each * \param between This is the number of milliseconds to wait in between each
DTMF digit. If zero milliseconds is specified, then the * DTMF digit. If zero milliseconds is specified, then the
default value of 100 will be used. * default value of 100 will be used.
\param duration This is the duration that each DTMF digit should have. * \param duration This is the duration that each DTMF digit should have.
*/ *
* \pre This must only be called by the channel's media handler thread.
*
* \retval 0 on success.
* \retval -1 on failure or a channel hung up.
*/
int ast_dtmf_stream(struct ast_channel *chan, struct ast_channel *peer, const char *digits, int between, unsigned int duration); int ast_dtmf_stream(struct ast_channel *chan, struct ast_channel *peer, const char *digits, int between, unsigned int duration);
/*!
* \brief Send a string of DTMF digits to a channel from an external thread.
*
* \param chan The channel that will receive the DTMF frames
* \param digits This is a string of characters representing the DTMF digits
* to be sent to the channel. Valid characters are
* "0123456789*#abcdABCD". Note: You can pass arguments 'f' or
* 'F', if you want to Flash the channel (if supported by the
* channel), or 'w' to add a 500 millisecond pause to the DTMF
* sequence.
* \param between This is the number of milliseconds to wait in between each
* DTMF digit. If zero milliseconds is specified, then the
* default value of 100 will be used.
* \param duration This is the duration that each DTMF digit should have.
*
* \pre This must only be called by threads that are not the channel's
* media handler thread.
*
* \return Nothing
*/
void ast_dtmf_stream_external(struct ast_channel *chan, const char *digits, int between, unsigned int duration);
/*! \brief Stream a filename (or file descriptor) as a generator. */ /*! \brief Stream a filename (or file descriptor) as a generator. */
int ast_linear_stream(struct ast_channel *chan, const char *filename, int fd, int allowoverride); int ast_linear_stream(struct ast_channel *chan, const char *filename, int fd, int allowoverride);

@ -875,25 +875,37 @@ int ast_vm_test_destroy_user(const char *context, const char *mailbox)
} }
#endif #endif
int ast_dtmf_stream(struct ast_channel *chan, struct ast_channel *peer, const char *digits, int between, unsigned int duration) static int external_sleep(struct ast_channel *chan, int ms)
{
usleep(ms * 1000);
return 0;
}
static int dtmf_stream(struct ast_channel *chan, const char *digits, int between, unsigned int duration, int is_external)
{ {
const char *ptr; const char *ptr;
int res; int res;
struct ast_silence_generator *silgen = NULL; struct ast_silence_generator *silgen = NULL;
int (*my_sleep)(struct ast_channel *chan, int ms);
int (*my_senddigit)(struct ast_channel *chan, char digit, unsigned int duration);
if (!between) { if (is_external) {
between = 100; my_sleep = external_sleep;
my_senddigit = ast_senddigit_external;
} else {
my_sleep = ast_safe_sleep;
my_senddigit = ast_senddigit;
} }
if (peer && ast_autoservice_start(peer)) { if (!between) {
return -1; between = 100;
} }
/* Need a quiet time before sending digits. */ /* Need a quiet time before sending digits. */
if (ast_opt_transmit_silence) { if (ast_opt_transmit_silence) {
silgen = ast_channel_start_silence_generator(chan); silgen = ast_channel_start_silence_generator(chan);
} }
res = ast_safe_sleep(chan, 100); res = my_sleep(chan, 100);
if (res) { if (res) {
goto dtmf_stream_cleanup; goto dtmf_stream_cleanup;
} }
@ -901,12 +913,14 @@ int ast_dtmf_stream(struct ast_channel *chan, struct ast_channel *peer, const ch
for (ptr = digits; *ptr; ptr++) { for (ptr = digits; *ptr; ptr++) {
if (*ptr == 'w') { if (*ptr == 'w') {
/* 'w' -- wait half a second */ /* 'w' -- wait half a second */
if ((res = ast_safe_sleep(chan, 500))) { res = my_sleep(chan, 500);
if (res) {
break; break;
} }
} else if (*ptr == 'W') { } else if (*ptr == 'W') {
/* 'W' -- wait a second */ /* 'W' -- wait a second */
if ((res = ast_safe_sleep(chan, 1000))) { res = my_sleep(chan, 1000);
if (res) {
break; break;
} }
} else if (strchr("0123456789*#abcdfABCDF", *ptr)) { } else if (strchr("0123456789*#abcdfABCDF", *ptr)) {
@ -915,10 +929,11 @@ int ast_dtmf_stream(struct ast_channel *chan, struct ast_channel *peer, const ch
ast_indicate(chan, AST_CONTROL_FLASH); ast_indicate(chan, AST_CONTROL_FLASH);
} else { } else {
/* Character represents valid DTMF */ /* Character represents valid DTMF */
ast_senddigit(chan, *ptr, duration); my_senddigit(chan, *ptr, duration);
} }
/* pause between digits */ /* pause between digits */
if ((res = ast_safe_sleep(chan, between))) { res = my_sleep(chan, between);
if (res) {
break; break;
} }
} else { } else {
@ -930,6 +945,18 @@ dtmf_stream_cleanup:
if (silgen) { if (silgen) {
ast_channel_stop_silence_generator(chan, silgen); ast_channel_stop_silence_generator(chan, silgen);
} }
return res;
}
int ast_dtmf_stream(struct ast_channel *chan, struct ast_channel *peer, const char *digits, int between, unsigned int duration)
{
int res;
if (peer && ast_autoservice_start(peer)) {
return -1;
}
res = dtmf_stream(chan, digits, between, duration, 0);
if (peer && ast_autoservice_stop(peer)) { if (peer && ast_autoservice_stop(peer)) {
res = -1; res = -1;
} }
@ -937,6 +964,11 @@ dtmf_stream_cleanup:
return res; return res;
} }
void ast_dtmf_stream_external(struct ast_channel *chan, const char *digits, int between, unsigned int duration)
{
dtmf_stream(chan, digits, between, duration, 1);
}
struct linear_state { struct linear_state {
int fd; int fd;
int autoclose; int autoclose;

@ -503,15 +503,21 @@ struct stasis_app_control_dtmf_data {
char dtmf[]; char dtmf[];
}; };
static int app_control_dtmf(struct stasis_app_control *control, static void dtmf_in_bridge(struct ast_channel *chan, struct stasis_app_control_dtmf_data *dtmf_data)
struct ast_channel *chan, void *data)
{ {
struct stasis_app_control_dtmf_data *dtmf_data = data; if (dtmf_data->before) {
usleep(dtmf_data->before * 1000);
}
if (ast_channel_state(chan) != AST_STATE_UP) { ast_dtmf_stream_external(chan, dtmf_data->dtmf, dtmf_data->between, dtmf_data->duration);
ast_indicate(chan, AST_CONTROL_PROGRESS);
if (dtmf_data->after) {
usleep(dtmf_data->after * 1000);
} }
}
static void dtmf_no_bridge(struct ast_channel *chan, struct stasis_app_control_dtmf_data *dtmf_data)
{
if (dtmf_data->before) { if (dtmf_data->before) {
ast_safe_sleep(chan, dtmf_data->before); ast_safe_sleep(chan, dtmf_data->before);
} }
@ -521,6 +527,22 @@ static int app_control_dtmf(struct stasis_app_control *control,
if (dtmf_data->after) { if (dtmf_data->after) {
ast_safe_sleep(chan, dtmf_data->after); ast_safe_sleep(chan, dtmf_data->after);
} }
}
static int app_control_dtmf(struct stasis_app_control *control,
struct ast_channel *chan, void *data)
{
struct stasis_app_control_dtmf_data *dtmf_data = data;
if (ast_channel_state(chan) != AST_STATE_UP) {
ast_indicate(chan, AST_CONTROL_PROGRESS);
}
if (stasis_app_get_bridge(control)) {
dtmf_in_bridge(chan, dtmf_data);
} else {
dtmf_no_bridge(chan, dtmf_data);
}
return 0; return 0;
} }

Loading…
Cancel
Save