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:
parent
7d874c1af7
commit
da54605b8a
|
@ -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);
|
||||
|
||||
|
|
52
main/app.c
52
main/app.c
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue