ARI POST DTMF: Make not compete with channel's media thread.

There can be one and only one thread handling a channel's media at a time.
Otherwise, we don't know which thread is going to handle the media frames.

ASTERISK-27625

Change-Id: I4d6a2fe7386ea447ee199003bf8ad681cb30454e
This commit is contained in:
Richard Mudgett 2018-06-13 16:41:43 -05:00
parent 7d874c1af7
commit da54605b8a
3 changed files with 115 additions and 34 deletions

View File

@ -923,24 +923,51 @@ void ast_replace_sigchld(void);
void ast_unreplace_sigchld(void);
/*!
\brief Send DTMF to a channel
\param chan The channel that will receive the DTMF frames
\param peer (optional) Peer channel that will be autoserviced while the
primary channel is receiving DTMF
\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.
*/
* \brief Send a string of DTMF digits to a channel
*
* \param chan The channel that will receive the DTMF frames
* \param peer (optional) Peer channel that will be autoserviced while the
* primary channel is receiving DTMF
* \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 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);
/*!
* \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. */
int ast_linear_stream(struct ast_channel *chan, const char *filename, int fd, int allowoverride);

View File

@ -873,25 +873,37 @@ int ast_vm_test_destroy_user(const char *context, const char *mailbox)
}
#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;
int res;
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 (is_external) {
my_sleep = external_sleep;
my_senddigit = ast_senddigit_external;
} else {
my_sleep = ast_safe_sleep;
my_senddigit = ast_senddigit;
}
if (!between) {
between = 100;
}
if (peer && ast_autoservice_start(peer)) {
return -1;
}
/* Need a quiet time before sending digits. */
if (ast_opt_transmit_silence) {
silgen = ast_channel_start_silence_generator(chan);
}
res = ast_safe_sleep(chan, 100);
res = my_sleep(chan, 100);
if (res) {
goto dtmf_stream_cleanup;
}
@ -899,12 +911,14 @@ int ast_dtmf_stream(struct ast_channel *chan, struct ast_channel *peer, const ch
for (ptr = digits; *ptr; ptr++) {
if (*ptr == 'w') {
/* 'w' -- wait half a second */
if ((res = ast_safe_sleep(chan, 500))) {
res = my_sleep(chan, 500);
if (res) {
break;
}
} else if (*ptr == 'W') {
/* 'W' -- wait a second */
if ((res = ast_safe_sleep(chan, 1000))) {
res = my_sleep(chan, 1000);
if (res) {
break;
}
} else if (strchr("0123456789*#abcdfABCDF", *ptr)) {
@ -913,10 +927,11 @@ int ast_dtmf_stream(struct ast_channel *chan, struct ast_channel *peer, const ch
ast_indicate(chan, AST_CONTROL_FLASH);
} else {
/* Character represents valid DTMF */
ast_senddigit(chan, *ptr, duration);
my_senddigit(chan, *ptr, duration);
}
/* pause between digits */
if ((res = ast_safe_sleep(chan, between))) {
res = my_sleep(chan, between);
if (res) {
break;
}
} else {
@ -928,6 +943,18 @@ dtmf_stream_cleanup:
if (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)) {
res = -1;
}
@ -935,6 +962,11 @@ dtmf_stream_cleanup:
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 {
int fd;
int autoclose;

View File

@ -431,6 +431,32 @@ struct stasis_app_control_dtmf_data {
char dtmf[];
};
static void dtmf_in_bridge(struct ast_channel *chan, struct stasis_app_control_dtmf_data *dtmf_data)
{
if (dtmf_data->before) {
usleep(dtmf_data->before * 1000);
}
ast_dtmf_stream_external(chan, dtmf_data->dtmf, dtmf_data->between, dtmf_data->duration);
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) {
ast_safe_sleep(chan, dtmf_data->before);
}
ast_dtmf_stream(chan, NULL, dtmf_data->dtmf, dtmf_data->between, dtmf_data->duration);
if (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)
{
@ -440,14 +466,10 @@ static int app_control_dtmf(struct stasis_app_control *control,
ast_indicate(chan, AST_CONTROL_PROGRESS);
}
if (dtmf_data->before) {
ast_safe_sleep(chan, dtmf_data->before);
}
ast_dtmf_stream(chan, NULL, dtmf_data->dtmf, dtmf_data->between, dtmf_data->duration);
if (dtmf_data->after) {
ast_safe_sleep(chan, dtmf_data->after);
if (stasis_app_get_bridge(control)) {
dtmf_in_bridge(chan, dtmf_data);
} else {
dtmf_no_bridge(chan, dtmf_data);
}
return 0;