Merge branch 'master' of ssh://git.freeswitch.org:222/freeswitch
This commit is contained in:
commit
ecf53e662b
|
@ -1291,7 +1291,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
|
||||||
int span_id = -1, group_id = -1, chan_id = 0;
|
int span_id = -1, group_id = -1, chan_id = 0;
|
||||||
switch_call_cause_t cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
|
switch_call_cause_t cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
|
||||||
ftdm_status_t status;
|
ftdm_status_t status;
|
||||||
int direction = FTDM_TOP_DOWN;
|
ftdm_hunt_direction_t direction = FTDM_HUNT_BOTTOM_UP;
|
||||||
ftdm_caller_data_t caller_data = {{ 0 }};
|
ftdm_caller_data_t caller_data = {{ 0 }};
|
||||||
char *span_name = NULL;
|
char *span_name = NULL;
|
||||||
switch_event_header_t *h;
|
switch_event_header_t *h;
|
||||||
|
@ -1348,14 +1348,14 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
|
||||||
span_name = argv[0];
|
span_name = argv[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*argv[1] == 'A') {
|
if (*argv[1] == 'a') {
|
||||||
direction = FTDM_BOTTOM_UP;
|
direction = FTDM_HUNT_BOTTOM_UP;
|
||||||
} else if (*argv[1] == 'a') {
|
} else if (*argv[1] == 'A') {
|
||||||
direction = FTDM_TOP_DOWN;
|
direction = FTDM_HUNT_TOP_DOWN;
|
||||||
} else if (*argv[1] == 'r') {
|
|
||||||
direction = FTDM_RR_DOWN;
|
|
||||||
} else if (*argv[1] == 'R') {
|
} else if (*argv[1] == 'R') {
|
||||||
direction = FTDM_RR_UP;
|
direction = FTDM_HUNT_RR_DOWN;
|
||||||
|
} else if (*argv[1] == 'r') {
|
||||||
|
direction = FTDM_HUNT_RR_UP;
|
||||||
} else {
|
} else {
|
||||||
chan_id = atoi(argv[1]);
|
chan_id = atoi(argv[1]);
|
||||||
}
|
}
|
||||||
|
@ -1390,7 +1390,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
|
||||||
}
|
}
|
||||||
|
|
||||||
if (group_id < 0 && chan_id < 0) {
|
if (group_id < 0 && chan_id < 0) {
|
||||||
direction = FTDM_BOTTOM_UP;
|
direction = FTDM_HUNT_BOTTOM_UP;
|
||||||
chan_id = 0;
|
chan_id = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1502,7 +1502,7 @@ static __inline__ int chan_voice_is_avail(ftdm_channel_t *check)
|
||||||
}
|
}
|
||||||
|
|
||||||
static __inline__ int request_voice_channel(ftdm_channel_t *check, ftdm_channel_t **ftdmchan,
|
static __inline__ int request_voice_channel(ftdm_channel_t *check, ftdm_channel_t **ftdmchan,
|
||||||
ftdm_caller_data_t *caller_data, ftdm_direction_t direction)
|
ftdm_caller_data_t *caller_data, ftdm_hunt_direction_t direction)
|
||||||
{
|
{
|
||||||
ftdm_status_t status;
|
ftdm_status_t status;
|
||||||
if (chan_voice_is_avail(check)) {
|
if (chan_voice_is_avail(check)) {
|
||||||
|
@ -1589,13 +1589,13 @@ static ftdm_status_t __inline__ get_best_rated(ftdm_channel_t **fchan, ftdm_chan
|
||||||
return FTDM_SUCCESS;
|
return FTDM_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t __inline__ rr_next(uint32_t last, uint32_t min, uint32_t max, ftdm_direction_t direction)
|
static uint32_t __inline__ rr_next(uint32_t last, uint32_t min, uint32_t max, ftdm_hunt_direction_t direction)
|
||||||
{
|
{
|
||||||
uint32_t next = min;
|
uint32_t next = min;
|
||||||
|
|
||||||
ftdm_log(FTDM_LOG_DEBUG, "last = %d, min = %d, max = %d\n", last, min, max);
|
ftdm_log(FTDM_LOG_DEBUG, "last = %d, min = %d, max = %d\n", last, min, max);
|
||||||
|
|
||||||
if (direction == FTDM_RR_DOWN) {
|
if (direction == FTDM_HUNT_RR_UP) {
|
||||||
next = (last >= max) ? min : ++last;
|
next = (last >= max) ? min : ++last;
|
||||||
} else {
|
} else {
|
||||||
next = (last <= min) ? max : --last;
|
next = (last <= min) ? max : --last;
|
||||||
|
@ -1615,7 +1615,7 @@ FT_DECLARE(int) ftdm_channel_get_availability(ftdm_channel_t *ftdmchan)
|
||||||
return availability;
|
return availability;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ftdm_status_t _ftdm_channel_open_by_group(uint32_t group_id, ftdm_direction_t direction, ftdm_caller_data_t *caller_data, ftdm_channel_t **ftdmchan)
|
static ftdm_status_t _ftdm_channel_open_by_group(uint32_t group_id, ftdm_hunt_direction_t direction, ftdm_caller_data_t *caller_data, ftdm_channel_t **ftdmchan)
|
||||||
{
|
{
|
||||||
ftdm_status_t status = FTDM_FAIL;
|
ftdm_status_t status = FTDM_FAIL;
|
||||||
ftdm_channel_t *check = NULL;
|
ftdm_channel_t *check = NULL;
|
||||||
|
@ -1645,9 +1645,9 @@ static ftdm_status_t _ftdm_channel_open_by_group(uint32_t group_id, ftdm_directi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (direction == FTDM_TOP_DOWN) {
|
if (direction == FTDM_HUNT_BOTTOM_UP) {
|
||||||
i = 0;
|
i = 0;
|
||||||
} else if (direction == FTDM_RR_DOWN || direction == FTDM_RR_UP) {
|
} else if (direction == FTDM_HUNT_RR_DOWN || direction == FTDM_HUNT_RR_UP) {
|
||||||
i = rr_next(group->last_used_index, 0, group->chan_count - 1, direction);
|
i = rr_next(group->last_used_index, 0, group->chan_count - 1, direction);
|
||||||
first_channel = i;
|
first_channel = i;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1664,7 +1664,7 @@ static ftdm_status_t _ftdm_channel_open_by_group(uint32_t group_id, ftdm_directi
|
||||||
|
|
||||||
if (request_voice_channel(check, ftdmchan, caller_data, direction)) {
|
if (request_voice_channel(check, ftdmchan, caller_data, direction)) {
|
||||||
status = FTDM_SUCCESS;
|
status = FTDM_SUCCESS;
|
||||||
if (direction == FTDM_RR_UP || direction == FTDM_RR_DOWN) {
|
if (direction == FTDM_HUNT_RR_UP || direction == FTDM_HUNT_RR_DOWN) {
|
||||||
group->last_used_index = i;
|
group->last_used_index = i;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1672,12 +1672,12 @@ static ftdm_status_t _ftdm_channel_open_by_group(uint32_t group_id, ftdm_directi
|
||||||
|
|
||||||
calculate_best_rate(check, &best_rated, &best_rate);
|
calculate_best_rate(check, &best_rated, &best_rate);
|
||||||
|
|
||||||
if (direction == FTDM_TOP_DOWN) {
|
if (direction == FTDM_HUNT_BOTTOM_UP) {
|
||||||
if (i >= (group->chan_count - 1)) {
|
if (i >= (group->chan_count - 1)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
} else if (direction == FTDM_RR_DOWN || direction == FTDM_RR_UP) {
|
} else if (direction == FTDM_HUNT_RR_DOWN || direction == FTDM_HUNT_RR_UP) {
|
||||||
if (check == best_rated) {
|
if (check == best_rated) {
|
||||||
group->last_used_index = i;
|
group->last_used_index = i;
|
||||||
}
|
}
|
||||||
|
@ -1701,7 +1701,7 @@ static ftdm_status_t _ftdm_channel_open_by_group(uint32_t group_id, ftdm_directi
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_group(uint32_t group_id, ftdm_direction_t direction, ftdm_caller_data_t *caller_data, ftdm_channel_t **ftdmchan)
|
FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_group(uint32_t group_id, ftdm_hunt_direction_t direction, ftdm_caller_data_t *caller_data, ftdm_channel_t **ftdmchan)
|
||||||
{
|
{
|
||||||
ftdm_status_t status;
|
ftdm_status_t status;
|
||||||
status = _ftdm_channel_open_by_group(group_id, direction, caller_data, ftdmchan);
|
status = _ftdm_channel_open_by_group(group_id, direction, caller_data, ftdmchan);
|
||||||
|
@ -1734,7 +1734,7 @@ FT_DECLARE(ftdm_status_t) ftdm_span_channel_use_count(ftdm_span_t *span, uint32_
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Hunt a channel by span, if successful the channel is returned locked */
|
/* Hunt a channel by span, if successful the channel is returned locked */
|
||||||
static ftdm_status_t _ftdm_channel_open_by_span(uint32_t span_id, ftdm_direction_t direction, ftdm_caller_data_t *caller_data, ftdm_channel_t **ftdmchan)
|
static ftdm_status_t _ftdm_channel_open_by_span(uint32_t span_id, ftdm_hunt_direction_t direction, ftdm_caller_data_t *caller_data, ftdm_channel_t **ftdmchan)
|
||||||
{
|
{
|
||||||
ftdm_status_t status = FTDM_FAIL;
|
ftdm_status_t status = FTDM_FAIL;
|
||||||
ftdm_channel_t *check = NULL;
|
ftdm_channel_t *check = NULL;
|
||||||
|
@ -1773,9 +1773,9 @@ static ftdm_status_t _ftdm_channel_open_by_span(uint32_t span_id, ftdm_direction
|
||||||
|
|
||||||
ftdm_mutex_lock(span->mutex);
|
ftdm_mutex_lock(span->mutex);
|
||||||
|
|
||||||
if (direction == FTDM_TOP_DOWN) {
|
if (direction == FTDM_HUNT_BOTTOM_UP) {
|
||||||
i = 1;
|
i = 1;
|
||||||
} else if (direction == FTDM_RR_DOWN || direction == FTDM_RR_UP) {
|
} else if (direction == FTDM_HUNT_RR_DOWN || direction == FTDM_HUNT_RR_UP) {
|
||||||
i = rr_next(span->last_used_index, 1, span->chan_count, direction);
|
i = rr_next(span->last_used_index, 1, span->chan_count, direction);
|
||||||
first_channel = i;
|
first_channel = i;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1784,7 +1784,7 @@ static ftdm_status_t _ftdm_channel_open_by_span(uint32_t span_id, ftdm_direction
|
||||||
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
|
|
||||||
if (direction == FTDM_TOP_DOWN) {
|
if (direction == FTDM_HUNT_BOTTOM_UP) {
|
||||||
if (i > span->chan_count) {
|
if (i > span->chan_count) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1801,7 +1801,7 @@ static ftdm_status_t _ftdm_channel_open_by_span(uint32_t span_id, ftdm_direction
|
||||||
|
|
||||||
if (request_voice_channel(check, ftdmchan, caller_data, direction)) {
|
if (request_voice_channel(check, ftdmchan, caller_data, direction)) {
|
||||||
status = FTDM_SUCCESS;
|
status = FTDM_SUCCESS;
|
||||||
if (direction == FTDM_RR_UP || direction == FTDM_RR_DOWN) {
|
if (direction == FTDM_HUNT_RR_UP || direction == FTDM_HUNT_RR_DOWN) {
|
||||||
span->last_used_index = i;
|
span->last_used_index = i;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1809,9 +1809,9 @@ static ftdm_status_t _ftdm_channel_open_by_span(uint32_t span_id, ftdm_direction
|
||||||
|
|
||||||
calculate_best_rate(check, &best_rated, &best_rate);
|
calculate_best_rate(check, &best_rated, &best_rate);
|
||||||
|
|
||||||
if (direction == FTDM_TOP_DOWN) {
|
if (direction == FTDM_HUNT_BOTTOM_UP) {
|
||||||
i++;
|
i++;
|
||||||
} else if (direction == FTDM_RR_DOWN || direction == FTDM_RR_UP) {
|
} else if (direction == FTDM_HUNT_RR_DOWN || direction == FTDM_HUNT_RR_UP) {
|
||||||
if (check == best_rated) {
|
if (check == best_rated) {
|
||||||
span->last_used_index = i;
|
span->last_used_index = i;
|
||||||
}
|
}
|
||||||
|
@ -1833,7 +1833,7 @@ static ftdm_status_t _ftdm_channel_open_by_span(uint32_t span_id, ftdm_direction
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_span(uint32_t span_id, ftdm_direction_t direction, ftdm_caller_data_t *caller_data, ftdm_channel_t **ftdmchan)
|
FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_span(uint32_t span_id, ftdm_hunt_direction_t direction, ftdm_caller_data_t *caller_data, ftdm_channel_t **ftdmchan)
|
||||||
{
|
{
|
||||||
ftdm_status_t status;
|
ftdm_status_t status;
|
||||||
status = _ftdm_channel_open_by_span(span_id, direction, caller_data, ftdmchan);
|
status = _ftdm_channel_open_by_span(span_id, direction, caller_data, ftdmchan);
|
||||||
|
|
|
@ -166,10 +166,21 @@ typedef enum {
|
||||||
|
|
||||||
/*! \brief Hunting direction (when hunting for free channels) */
|
/*! \brief Hunting direction (when hunting for free channels) */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
FTDM_TOP_DOWN,
|
FTDM_HUNT_TOP_DOWN,
|
||||||
|
FTDM_HUNT_BOTTOM_UP,
|
||||||
|
FTDM_HUNT_RR_DOWN,
|
||||||
|
FTDM_HUNT_RR_UP,
|
||||||
|
} ftdm_hunt_direction_t;
|
||||||
|
|
||||||
|
/*! \brief Legacy Hunting direction (Top down and Bottom up were reversed), keep for source backwards compatibility of freetdm user applications
|
||||||
|
* \deprecated
|
||||||
|
* \see ftdm_hunt_direction_t
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
FTDM_BOTTOM_UP,
|
FTDM_BOTTOM_UP,
|
||||||
FTDM_RR_DOWN,
|
FTDM_TOP_DOWN,
|
||||||
FTDM_RR_UP,
|
FTDM_RR_UP,
|
||||||
|
FTDM_RR_DOWN,
|
||||||
} ftdm_direction_t;
|
} ftdm_direction_t;
|
||||||
|
|
||||||
/*! \brief I/O channel type */
|
/*! \brief I/O channel type */
|
||||||
|
@ -404,13 +415,13 @@ typedef enum {
|
||||||
/*! \brief Structure used for FTDM_HUNT_SPAN mode */
|
/*! \brief Structure used for FTDM_HUNT_SPAN mode */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t span_id;
|
uint32_t span_id;
|
||||||
ftdm_direction_t direction;
|
ftdm_hunt_direction_t direction;
|
||||||
} ftdm_span_hunt_t;
|
} ftdm_span_hunt_t;
|
||||||
|
|
||||||
/*! \brief Structure used for FTDM_HUNT_GROUP mode */
|
/*! \brief Structure used for FTDM_HUNT_GROUP mode */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t group_id;
|
uint32_t group_id;
|
||||||
ftdm_direction_t direction;
|
ftdm_hunt_direction_t direction;
|
||||||
} ftdm_group_hunt_t;
|
} ftdm_group_hunt_t;
|
||||||
|
|
||||||
/*! \brief Structure used for FTDM_HUNT_CHAN mode */
|
/*! \brief Structure used for FTDM_HUNT_CHAN mode */
|
||||||
|
@ -781,7 +792,7 @@ struct ftdm_memory_handler {
|
||||||
|
|
||||||
/*! \brief FreeTDM I/O layer interface argument macros
|
/*! \brief FreeTDM I/O layer interface argument macros
|
||||||
* You don't need these unless your implementing an I/O interface module (most users don't) */
|
* You don't need these unless your implementing an I/O interface module (most users don't) */
|
||||||
#define FIO_CHANNEL_REQUEST_ARGS (ftdm_span_t *span, uint32_t chan_id, ftdm_direction_t direction, ftdm_caller_data_t *caller_data, ftdm_channel_t **ftdmchan)
|
#define FIO_CHANNEL_REQUEST_ARGS (ftdm_span_t *span, uint32_t chan_id, ftdm_hunt_direction_t direction, ftdm_caller_data_t *caller_data, ftdm_channel_t **ftdmchan)
|
||||||
#define FIO_CHANNEL_OUTGOING_CALL_ARGS (ftdm_channel_t *ftdmchan)
|
#define FIO_CHANNEL_OUTGOING_CALL_ARGS (ftdm_channel_t *ftdmchan)
|
||||||
#define FIO_CHANNEL_INDICATE_ARGS (ftdm_channel_t *ftdmchan, ftdm_channel_indication_t indication)
|
#define FIO_CHANNEL_INDICATE_ARGS (ftdm_channel_t *ftdmchan, ftdm_channel_indication_t indication)
|
||||||
#define FIO_CHANNEL_SET_SIG_STATUS_ARGS (ftdm_channel_t *ftdmchan, ftdm_signaling_status_t status)
|
#define FIO_CHANNEL_SET_SIG_STATUS_ARGS (ftdm_channel_t *ftdmchan, ftdm_signaling_status_t status)
|
||||||
|
@ -1440,7 +1451,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_ph(uint32_t span_id, uint32_t chan_i
|
||||||
* \retval FTDM_SUCCESS success (a suitable channel was found available)
|
* \retval FTDM_SUCCESS success (a suitable channel was found available)
|
||||||
* \retval FTDM_FAIL failure (no suitable channel was found available)
|
* \retval FTDM_FAIL failure (no suitable channel was found available)
|
||||||
*/
|
*/
|
||||||
FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_span(uint32_t span_id, ftdm_direction_t direction, ftdm_caller_data_t *caller_data, ftdm_channel_t **ftdmchan);
|
FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_span(uint32_t span_id, ftdm_hunt_direction_t direction, ftdm_caller_data_t *caller_data, ftdm_channel_t **ftdmchan);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Hunts and opens a channel specifying group id
|
* \brief Hunts and opens a channel specifying group id
|
||||||
|
@ -1458,7 +1469,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_span(uint32_t span_id, ftdm_direc
|
||||||
* \retval FTDM_SUCCESS success (a suitable channel was found available)
|
* \retval FTDM_SUCCESS success (a suitable channel was found available)
|
||||||
* \retval FTDM_FAIL failure (no suitable channel was found available)
|
* \retval FTDM_FAIL failure (no suitable channel was found available)
|
||||||
*/
|
*/
|
||||||
FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_group(uint32_t group_id, ftdm_direction_t direction, ftdm_caller_data_t *caller_data, ftdm_channel_t **ftdmchan);
|
FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_group(uint32_t group_id, ftdm_hunt_direction_t direction, ftdm_caller_data_t *caller_data, ftdm_channel_t **ftdmchan);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Close a previously open channel
|
* \brief Close a previously open channel
|
||||||
|
|
|
@ -21,7 +21,7 @@ int main(int argc, char *argv[])
|
||||||
printf("FreeTDM loaded\n");
|
printf("FreeTDM loaded\n");
|
||||||
|
|
||||||
top:
|
top:
|
||||||
//if (ftdm_channel_open_any("wanpipe", 0, FTDM_TOP_DOWN, &chan) == FTDM_SUCCESS) {
|
//if (ftdm_channel_open_any("wanpipe", 0, FTDM_HUNT_BOTTOM_UP, &chan) == FTDM_SUCCESS) {
|
||||||
if (ftdm_channel_open(1, 1, &chan) == FTDM_SUCCESS) {
|
if (ftdm_channel_open(1, 1, &chan) == FTDM_SUCCESS) {
|
||||||
int x = 0;
|
int x = 0;
|
||||||
spanid = ftdm_channel_get_span_id(chan);
|
spanid = ftdm_channel_get_span_id(chan);
|
||||||
|
|
|
@ -2052,24 +2052,19 @@ crypto_policy_set_from_profile_for_rtp(crypto_policy_t *policy,
|
||||||
/* set SRTP policy from the SRTP profile in the key set */
|
/* set SRTP policy from the SRTP profile in the key set */
|
||||||
switch(profile) {
|
switch(profile) {
|
||||||
case srtp_profile_aes128_cm_sha1_80:
|
case srtp_profile_aes128_cm_sha1_80:
|
||||||
crypto_policy_set_aes_cm_128_hmac_sha1_80(policy);
|
|
||||||
crypto_policy_set_aes_cm_128_hmac_sha1_80(policy);
|
crypto_policy_set_aes_cm_128_hmac_sha1_80(policy);
|
||||||
break;
|
break;
|
||||||
case srtp_profile_aes128_cm_sha1_32:
|
case srtp_profile_aes128_cm_sha1_32:
|
||||||
crypto_policy_set_aes_cm_128_hmac_sha1_32(policy);
|
crypto_policy_set_aes_cm_128_hmac_sha1_32(policy);
|
||||||
crypto_policy_set_aes_cm_128_hmac_sha1_80(policy);
|
|
||||||
break;
|
break;
|
||||||
case srtp_profile_null_sha1_80:
|
case srtp_profile_null_sha1_80:
|
||||||
crypto_policy_set_null_cipher_hmac_sha1_80(policy);
|
|
||||||
crypto_policy_set_null_cipher_hmac_sha1_80(policy);
|
crypto_policy_set_null_cipher_hmac_sha1_80(policy);
|
||||||
break;
|
break;
|
||||||
case srtp_profile_aes256_cm_sha1_80:
|
case srtp_profile_aes256_cm_sha1_80:
|
||||||
crypto_policy_set_aes_cm_256_hmac_sha1_80(policy);
|
|
||||||
crypto_policy_set_aes_cm_256_hmac_sha1_80(policy);
|
crypto_policy_set_aes_cm_256_hmac_sha1_80(policy);
|
||||||
break;
|
break;
|
||||||
case srtp_profile_aes256_cm_sha1_32:
|
case srtp_profile_aes256_cm_sha1_32:
|
||||||
crypto_policy_set_aes_cm_256_hmac_sha1_32(policy);
|
crypto_policy_set_aes_cm_256_hmac_sha1_32(policy);
|
||||||
crypto_policy_set_aes_cm_256_hmac_sha1_80(policy);
|
|
||||||
break;
|
break;
|
||||||
/* the following profiles are not (yet) supported */
|
/* the following profiles are not (yet) supported */
|
||||||
case srtp_profile_null_sha1_32:
|
case srtp_profile_null_sha1_32:
|
||||||
|
@ -2090,7 +2085,7 @@ crypto_policy_set_from_profile_for_rtcp(crypto_policy_t *policy,
|
||||||
crypto_policy_set_aes_cm_128_hmac_sha1_80(policy);
|
crypto_policy_set_aes_cm_128_hmac_sha1_80(policy);
|
||||||
break;
|
break;
|
||||||
case srtp_profile_aes128_cm_sha1_32:
|
case srtp_profile_aes128_cm_sha1_32:
|
||||||
crypto_policy_set_aes_cm_128_hmac_sha1_80(policy);
|
crypto_policy_set_aes_cm_128_hmac_sha1_32(policy);
|
||||||
break;
|
break;
|
||||||
case srtp_profile_null_sha1_80:
|
case srtp_profile_null_sha1_80:
|
||||||
crypto_policy_set_null_cipher_hmac_sha1_80(policy);
|
crypto_policy_set_null_cipher_hmac_sha1_80(policy);
|
||||||
|
@ -2099,7 +2094,7 @@ crypto_policy_set_from_profile_for_rtcp(crypto_policy_t *policy,
|
||||||
crypto_policy_set_aes_cm_256_hmac_sha1_80(policy);
|
crypto_policy_set_aes_cm_256_hmac_sha1_80(policy);
|
||||||
break;
|
break;
|
||||||
case srtp_profile_aes256_cm_sha1_32:
|
case srtp_profile_aes256_cm_sha1_32:
|
||||||
crypto_policy_set_aes_cm_256_hmac_sha1_80(policy);
|
crypto_policy_set_aes_cm_256_hmac_sha1_32(policy);
|
||||||
break;
|
break;
|
||||||
/* the following profiles are not (yet) supported */
|
/* the following profiles are not (yet) supported */
|
||||||
case srtp_profile_null_sha1_32:
|
case srtp_profile_null_sha1_32:
|
||||||
|
|
|
@ -1307,6 +1307,7 @@ static void *SWITCH_THREAD_FUNC ringall_thread_run(switch_thread_t *thread, void
|
||||||
struct call_helper *rows[MAX_ROWS] = { 0 };
|
struct call_helper *rows[MAX_ROWS] = { 0 };
|
||||||
int rowcount = 0;
|
int rowcount = 0;
|
||||||
switch_memory_pool_t *pool;
|
switch_memory_pool_t *pool;
|
||||||
|
char *export = NULL;
|
||||||
|
|
||||||
switch_mutex_lock(globals.mutex);
|
switch_mutex_lock(globals.mutex);
|
||||||
globals.threads++;
|
globals.threads++;
|
||||||
|
@ -1473,6 +1474,28 @@ static void *SWITCH_THREAD_FUNC ringall_thread_run(switch_thread_t *thread, void
|
||||||
switch_event_add_header_string(ovars, SWITCH_STACK_BOTTOM, "fifo_originate_uuid", uuid_str);
|
switch_event_add_header_string(ovars, SWITCH_STACK_BOTTOM, "fifo_originate_uuid", uuid_str);
|
||||||
|
|
||||||
|
|
||||||
|
if ((export = switch_event_get_header(pop, "variable_fifo_export"))) {
|
||||||
|
int argc;
|
||||||
|
char *argv[100] = { 0 };
|
||||||
|
char *mydata = strdup(export);
|
||||||
|
char *tmp;
|
||||||
|
|
||||||
|
argc = switch_split(mydata, ',', argv);
|
||||||
|
|
||||||
|
for (x = 0; x < argc; x++) {
|
||||||
|
char *name = switch_mprintf("variable_%s", argv[x]);
|
||||||
|
|
||||||
|
if ((tmp = switch_event_get_header(pop, name))) {
|
||||||
|
switch_event_add_header_string(ovars, SWITCH_STACK_BOTTOM, argv[x], tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch_safe_free(mydata);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, FIFO_EVENT) == SWITCH_STATUS_SUCCESS) {
|
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, FIFO_EVENT) == SWITCH_STATUS_SUCCESS) {
|
||||||
switch_core_session_t *session;
|
switch_core_session_t *session;
|
||||||
if (id && (session = switch_core_session_locate(id))) {
|
if (id && (session = switch_core_session_locate(id))) {
|
||||||
|
|
|
@ -102,8 +102,8 @@ struct input_handler {
|
||||||
switch_media_bug_t *bug;
|
switch_media_bug_t *bug;
|
||||||
/** active voice input component */
|
/** active voice input component */
|
||||||
struct input_component *voice_component;
|
struct input_component *voice_component;
|
||||||
/** active dtmf input component */
|
/** active dtmf input components */
|
||||||
struct input_component *dtmf_component;
|
switch_hash_t *dtmf_components;
|
||||||
/** synchronizes media bug and dtmf callbacks */
|
/** synchronizes media bug and dtmf callbacks */
|
||||||
switch_mutex_t *mutex;
|
switch_mutex_t *mutex;
|
||||||
/** last recognizer used */
|
/** last recognizer used */
|
||||||
|
@ -147,84 +147,161 @@ static void send_barge_event(struct rayo_component *component)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process DTMF press
|
* Check if dtmf component has timed out
|
||||||
*/
|
*/
|
||||||
static switch_status_t input_component_on_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf, switch_dtmf_direction_t direction)
|
static switch_status_t dtmf_component_check_timeout(struct input_component *component, switch_core_session_t *session)
|
||||||
|
{
|
||||||
|
/* check for stopped component */
|
||||||
|
if (component->stop) {
|
||||||
|
rayo_component_send_complete(RAYO_COMPONENT(component), COMPONENT_COMPLETE_STOP);
|
||||||
|
|
||||||
|
/* let handler know component is done */
|
||||||
|
return SWITCH_STATUS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check for timeout */
|
||||||
|
if (component->start_timers) {
|
||||||
|
int elapsed_ms = (switch_micro_time_now() - component->last_digit_time) / 1000;
|
||||||
|
if (component->num_digits && component->inter_digit_timeout > 0 && elapsed_ms > component->inter_digit_timeout) {
|
||||||
|
enum srgs_match_type match;
|
||||||
|
const char *interpretation = NULL;
|
||||||
|
|
||||||
|
/* we got some input, check for match */
|
||||||
|
match = srgs_grammar_match(component->grammar, component->digits, &interpretation);
|
||||||
|
if (match == SMT_MATCH || match == SMT_MATCH_END) {
|
||||||
|
iks *result = nlsml_create_dtmf_match(component->digits, interpretation);
|
||||||
|
/* notify of match */
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "MATCH = %s\n", component->digits);
|
||||||
|
send_match_event(RAYO_COMPONENT(component), result);
|
||||||
|
iks_delete(result);
|
||||||
|
} else {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "inter-digit-timeout\n");
|
||||||
|
rayo_component_send_complete(RAYO_COMPONENT(component), INPUT_NOMATCH);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* let handler know component is done */
|
||||||
|
return SWITCH_STATUS_FALSE;
|
||||||
|
} else if (!component->num_digits && component->initial_timeout > 0 && elapsed_ms > component->initial_timeout) {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "initial-timeout\n");
|
||||||
|
rayo_component_send_complete(RAYO_COMPONENT(component), INPUT_NOINPUT);
|
||||||
|
|
||||||
|
/* let handler know component is done */
|
||||||
|
return SWITCH_STATUS_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SWITCH_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process DTMF press for a specific component
|
||||||
|
* @param component to receive DTMF
|
||||||
|
* @param session
|
||||||
|
* @param dtmf
|
||||||
|
* @param direction
|
||||||
|
* @return SWITCH_STATUS_FALSE if component is done
|
||||||
|
*/
|
||||||
|
static switch_status_t dtmf_component_on_dtmf(struct input_component *component, switch_core_session_t *session, const switch_dtmf_t *dtmf, switch_dtmf_direction_t direction)
|
||||||
|
{
|
||||||
|
int is_term_digit = 0;
|
||||||
|
enum srgs_match_type match;
|
||||||
|
const char *interpretation = NULL;
|
||||||
|
|
||||||
|
is_term_digit = digit_test(component->term_digit, dtmf->digit);
|
||||||
|
|
||||||
|
if (!is_term_digit) {
|
||||||
|
component->digits[component->num_digits] = dtmf->digit;
|
||||||
|
component->num_digits++;
|
||||||
|
component->digits[component->num_digits] = '\0';
|
||||||
|
component->last_digit_time = switch_micro_time_now();
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Collected digits = \"%s\"\n", component->digits);
|
||||||
|
} else {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Collected term digit = \"%c\"\n", dtmf->digit);
|
||||||
|
}
|
||||||
|
|
||||||
|
match = srgs_grammar_match(component->grammar, component->digits, &interpretation);
|
||||||
|
|
||||||
|
if (is_term_digit) {
|
||||||
|
/* finalize result if terminating digit was pressed */
|
||||||
|
if (match == SMT_MATCH_PARTIAL) {
|
||||||
|
match = SMT_NO_MATCH;
|
||||||
|
} else if (match == SMT_MATCH) {
|
||||||
|
match = SMT_MATCH_END;
|
||||||
|
}
|
||||||
|
} else if (component->num_digits >= MAX_DTMF) {
|
||||||
|
/* maximum digits collected and still not a definitive match */
|
||||||
|
if (match != SMT_MATCH_END) {
|
||||||
|
match = SMT_NO_MATCH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (match) {
|
||||||
|
case SMT_MATCH:
|
||||||
|
case SMT_MATCH_PARTIAL: {
|
||||||
|
/* need more digits */
|
||||||
|
if (component->num_digits == 1) {
|
||||||
|
send_barge_event(RAYO_COMPONENT(component));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SMT_NO_MATCH: {
|
||||||
|
/* notify of no-match and remove input component */
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "NO MATCH = %s\n", component->digits);
|
||||||
|
rayo_component_send_complete(RAYO_COMPONENT(component), INPUT_NOMATCH);
|
||||||
|
|
||||||
|
/* let handler know component is done */
|
||||||
|
return SWITCH_STATUS_FALSE;
|
||||||
|
}
|
||||||
|
case SMT_MATCH_END: {
|
||||||
|
iks *result = nlsml_create_dtmf_match(component->digits, interpretation);
|
||||||
|
/* notify of match and remove input component */
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "MATCH = %s\n", component->digits);
|
||||||
|
send_match_event(RAYO_COMPONENT(component), result);
|
||||||
|
iks_delete(result);
|
||||||
|
|
||||||
|
/* let handler know component is done */
|
||||||
|
return SWITCH_STATUS_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* still need more input */
|
||||||
|
return SWITCH_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process DTMF press on call
|
||||||
|
*/
|
||||||
|
static switch_status_t input_handler_on_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf, switch_dtmf_direction_t direction)
|
||||||
{
|
{
|
||||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||||
struct input_handler *handler = (struct input_handler *)switch_channel_get_private(channel, RAYO_INPUT_COMPONENT_PRIVATE_VAR);
|
struct input_handler *handler = (struct input_handler *)switch_channel_get_private(channel, RAYO_INPUT_COMPONENT_PRIVATE_VAR);
|
||||||
|
|
||||||
if (handler) {
|
if (handler) {
|
||||||
int is_term_digit = 0;
|
switch_event_t *components_to_remove = NULL;
|
||||||
struct input_component *component;
|
switch_hash_index_t *hi;
|
||||||
enum srgs_match_type match;
|
|
||||||
const char *interpretation = NULL;
|
|
||||||
|
|
||||||
switch_mutex_lock(handler->mutex);
|
switch_mutex_lock(handler->mutex);
|
||||||
|
|
||||||
component = handler->dtmf_component;
|
/* check input on each component */
|
||||||
/* additional paranoia check */
|
for (hi = switch_core_hash_first(handler->dtmf_components); hi; hi = switch_core_hash_next(hi)) {
|
||||||
if (!component) {
|
const void *jid;
|
||||||
switch_mutex_unlock(handler->mutex);
|
void *component;
|
||||||
return SWITCH_STATUS_SUCCESS;
|
switch_core_hash_this(hi, &jid, NULL, &component);
|
||||||
}
|
if (dtmf_component_on_dtmf(INPUT_COMPONENT(component), session, dtmf, direction) != SWITCH_STATUS_SUCCESS) {
|
||||||
|
if (!components_to_remove) {
|
||||||
is_term_digit = digit_test(component->term_digit, dtmf->digit);
|
switch_event_create_subclass(&components_to_remove, SWITCH_EVENT_CLONE, NULL);
|
||||||
|
|
||||||
if (!is_term_digit) {
|
|
||||||
component->digits[component->num_digits] = dtmf->digit;
|
|
||||||
component->num_digits++;
|
|
||||||
component->digits[component->num_digits] = '\0';
|
|
||||||
component->last_digit_time = switch_micro_time_now();
|
|
||||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Collected digits = \"%s\"\n", component->digits);
|
|
||||||
} else {
|
|
||||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Collected term digit = \"%c\"\n", dtmf->digit);
|
|
||||||
}
|
|
||||||
|
|
||||||
match = srgs_grammar_match(component->grammar, component->digits, &interpretation);
|
|
||||||
|
|
||||||
if (is_term_digit) {
|
|
||||||
/* finalize result if terminating digit was pressed */
|
|
||||||
if (match == SMT_MATCH_PARTIAL) {
|
|
||||||
match = SMT_NO_MATCH;
|
|
||||||
} else if (match == SMT_MATCH) {
|
|
||||||
match = SMT_MATCH_END;
|
|
||||||
}
|
|
||||||
} else if (component->num_digits >= MAX_DTMF) {
|
|
||||||
/* maximum digits collected and still not a definitive match */
|
|
||||||
if (match != SMT_MATCH_END) {
|
|
||||||
match = SMT_NO_MATCH;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (match) {
|
|
||||||
case SMT_MATCH:
|
|
||||||
case SMT_MATCH_PARTIAL: {
|
|
||||||
/* need more digits */
|
|
||||||
if (component->num_digits == 1) {
|
|
||||||
send_barge_event(RAYO_COMPONENT(component));
|
|
||||||
}
|
}
|
||||||
break;
|
switch_event_add_header_string(components_to_remove, SWITCH_STACK_BOTTOM, "done", RAYO_JID(component));
|
||||||
}
|
|
||||||
case SMT_NO_MATCH: {
|
|
||||||
/* notify of no-match and remove input component */
|
|
||||||
handler->dtmf_component = NULL;
|
|
||||||
switch_core_media_bug_remove(session, &handler->bug);
|
|
||||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "NO MATCH = %s\n", component->digits);
|
|
||||||
rayo_component_send_complete(RAYO_COMPONENT(component), INPUT_NOMATCH);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SMT_MATCH_END: {
|
|
||||||
iks *result = nlsml_create_dtmf_match(component->digits, interpretation);
|
|
||||||
/* notify of match and remove input component */
|
|
||||||
handler->dtmf_component = NULL;
|
|
||||||
switch_core_media_bug_remove(session, &handler->bug);
|
|
||||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "MATCH = %s\n", component->digits);
|
|
||||||
send_match_event(RAYO_COMPONENT(component), result);
|
|
||||||
iks_delete(result);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* remove any finished components */
|
||||||
|
if (components_to_remove) {
|
||||||
|
switch_event_header_t *component_to_remove = NULL;
|
||||||
|
for (component_to_remove = components_to_remove->headers; component_to_remove; component_to_remove = component_to_remove->next) {
|
||||||
|
switch_core_hash_delete(handler->dtmf_components, component_to_remove->value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch_mutex_unlock(handler->mutex);
|
switch_mutex_unlock(handler->mutex);
|
||||||
}
|
}
|
||||||
return SWITCH_STATUS_SUCCESS;
|
return SWITCH_STATUS_SUCCESS;
|
||||||
|
@ -233,67 +310,59 @@ static switch_status_t input_component_on_dtmf(switch_core_session_t *session, c
|
||||||
/**
|
/**
|
||||||
* Monitor for input
|
* Monitor for input
|
||||||
*/
|
*/
|
||||||
static switch_bool_t input_component_bug_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
|
static switch_bool_t input_handler_bug_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
|
||||||
{
|
{
|
||||||
switch_core_session_t *session = switch_core_media_bug_get_session(bug);
|
switch_core_session_t *session = switch_core_media_bug_get_session(bug);
|
||||||
struct input_handler *handler = (struct input_handler *)user_data;
|
struct input_handler *handler = (struct input_handler *)user_data;
|
||||||
struct input_component *component;
|
switch_hash_index_t *hi;
|
||||||
|
|
||||||
switch_mutex_lock(handler->mutex);
|
switch_mutex_lock(handler->mutex);
|
||||||
component = handler->dtmf_component;
|
|
||||||
|
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case SWITCH_ABC_TYPE_INIT: {
|
case SWITCH_ABC_TYPE_INIT: {
|
||||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Adding DTMF callback\n");
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Adding DTMF callback\n");
|
||||||
switch_core_event_hook_add_recv_dtmf(session, input_component_on_dtmf);
|
switch_core_event_hook_add_recv_dtmf(session, input_handler_on_dtmf);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SWITCH_ABC_TYPE_READ_REPLACE: {
|
case SWITCH_ABC_TYPE_READ_REPLACE: {
|
||||||
switch_frame_t *rframe = switch_core_media_bug_get_read_replace_frame(bug);
|
switch_frame_t *rframe = switch_core_media_bug_get_read_replace_frame(bug);
|
||||||
/* check for timeout */
|
switch_event_t *components_to_remove = NULL;
|
||||||
if (component && component->start_timers) {
|
|
||||||
int elapsed_ms = (switch_micro_time_now() - component->last_digit_time) / 1000;
|
|
||||||
if (component->num_digits && component->inter_digit_timeout > 0 && elapsed_ms > component->inter_digit_timeout) {
|
|
||||||
enum srgs_match_type match;
|
|
||||||
const char *interpretation = NULL;
|
|
||||||
handler->dtmf_component = NULL;
|
|
||||||
switch_core_media_bug_set_flag(bug, SMBF_PRUNE);
|
|
||||||
|
|
||||||
/* we got some input, check for match */
|
/* check timeout/stop on each component */
|
||||||
match = srgs_grammar_match(component->grammar, component->digits, &interpretation);
|
for (hi = switch_core_hash_first(handler->dtmf_components); hi; hi = switch_core_hash_next(hi)) {
|
||||||
if (match == SMT_MATCH || match == SMT_MATCH_END) {
|
const void *jid;
|
||||||
iks *result = nlsml_create_dtmf_match(component->digits, interpretation);
|
void *component;
|
||||||
/* notify of match */
|
switch_core_hash_this(hi, &jid, NULL, &component);
|
||||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "MATCH = %s\n", component->digits);
|
if (dtmf_component_check_timeout(INPUT_COMPONENT(component), session) != SWITCH_STATUS_SUCCESS) {
|
||||||
send_match_event(RAYO_COMPONENT(component), result);
|
if (!components_to_remove) {
|
||||||
iks_delete(result);
|
switch_event_create_subclass(&components_to_remove, SWITCH_EVENT_CLONE, NULL);
|
||||||
} else {
|
|
||||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "inter-digit-timeout\n");
|
|
||||||
rayo_component_send_complete(RAYO_COMPONENT(component), INPUT_NOMATCH);
|
|
||||||
}
|
}
|
||||||
} else if (!component->num_digits && component->initial_timeout > 0 && elapsed_ms > component->initial_timeout) {
|
switch_event_add_header_string(components_to_remove, SWITCH_STACK_BOTTOM, "done", RAYO_JID(component));
|
||||||
handler->dtmf_component = NULL;
|
|
||||||
switch_core_media_bug_set_flag(bug, SMBF_PRUNE);
|
|
||||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "initial-timeout\n");
|
|
||||||
rayo_component_send_complete(RAYO_COMPONENT(component), INPUT_NOINPUT);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* remove any finished components */
|
||||||
|
if (components_to_remove) {
|
||||||
|
switch_event_header_t *component_to_remove = NULL;
|
||||||
|
for (component_to_remove = components_to_remove->headers; component_to_remove; component_to_remove = component_to_remove->next) {
|
||||||
|
switch_core_hash_delete(handler->dtmf_components, component_to_remove->value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch_core_media_bug_set_read_replace_frame(bug, rframe);
|
switch_core_media_bug_set_read_replace_frame(bug, rframe);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SWITCH_ABC_TYPE_CLOSE:
|
case SWITCH_ABC_TYPE_CLOSE:
|
||||||
/* check for hangup */
|
/* complete all components */
|
||||||
if (component) {
|
for (hi = switch_core_hash_first(handler->dtmf_components); hi; hi = switch_core_hash_next(hi)) {
|
||||||
if (component->stop) {
|
const void *jid;
|
||||||
handler->dtmf_component = NULL;
|
void *component;
|
||||||
rayo_component_send_complete(RAYO_COMPONENT(component), COMPONENT_COMPLETE_STOP);
|
switch_core_hash_this(hi, &jid, NULL, &component);
|
||||||
} else {
|
rayo_component_send_complete(RAYO_COMPONENT(component), COMPONENT_COMPLETE_STOP);
|
||||||
handler->dtmf_component = NULL;
|
|
||||||
rayo_component_send_complete(RAYO_COMPONENT(component), COMPONENT_COMPLETE_HANGUP);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Removing DTMF callback\n");
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Removing DTMF callback\n");
|
||||||
switch_core_event_hook_remove_recv_dtmf(session, input_component_on_dtmf);
|
switch_core_event_hook_remove_recv_dtmf(session, input_handler_on_dtmf);
|
||||||
|
switch_core_hash_destroy(&handler->dtmf_components);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -342,6 +411,140 @@ static int validate_call_input(iks *input, const char **error)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start call input on voice resource
|
||||||
|
*/
|
||||||
|
static iks *start_call_voice_input(struct input_component *component, switch_core_session_t *session, iks *input, iks *iq, const char *output_file, int barge_in)
|
||||||
|
{
|
||||||
|
struct input_handler *handler = component->handler;
|
||||||
|
switch_stream_handle_t grammar = { 0 };
|
||||||
|
SWITCH_STANDARD_STREAM(grammar);
|
||||||
|
|
||||||
|
if (component->speech_mode && handler->voice_component) {
|
||||||
|
/* don't allow multi voice input */
|
||||||
|
RAYO_UNLOCK(component);
|
||||||
|
RAYO_DESTROY(component);
|
||||||
|
return iks_new_error_detailed(iq, STANZA_ERROR_CONFLICT, "Multiple voice input is not allowed");
|
||||||
|
}
|
||||||
|
|
||||||
|
handler->voice_component = component;
|
||||||
|
|
||||||
|
if (zstr(component->recognizer)) {
|
||||||
|
component->recognizer = globals.default_recognizer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if recognition engine is different, we can't handle this request */
|
||||||
|
if (!zstr(handler->last_recognizer) && strcmp(component->recognizer, handler->last_recognizer)) {
|
||||||
|
handler->voice_component = NULL;
|
||||||
|
RAYO_UNLOCK(component);
|
||||||
|
RAYO_DESTROY(component);
|
||||||
|
return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "Must use the same recognizer for the entire call");
|
||||||
|
}
|
||||||
|
handler->last_recognizer = switch_core_session_strdup(session, component->recognizer);
|
||||||
|
|
||||||
|
if (!strcmp(component->recognizer, "pocketsphinx")) {
|
||||||
|
const char *jsgf_path;
|
||||||
|
|
||||||
|
/* transform SRGS grammar to JSGF */
|
||||||
|
if (!(component->grammar = srgs_parse(globals.parser, iks_find_cdata(input, "grammar")))) {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Failed to parse grammar body\n");
|
||||||
|
handler->voice_component = NULL;
|
||||||
|
RAYO_UNLOCK(component);
|
||||||
|
RAYO_DESTROY(component);
|
||||||
|
return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "Failed to parse grammar body");
|
||||||
|
}
|
||||||
|
jsgf_path = srgs_grammar_to_jsgf_file(component->grammar, SWITCH_GLOBAL_dirs.grammar_dir, "gram");
|
||||||
|
if (!jsgf_path) {
|
||||||
|
handler->voice_component = NULL;
|
||||||
|
RAYO_UNLOCK(component);
|
||||||
|
RAYO_DESTROY(component);
|
||||||
|
return iks_new_error_detailed(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, "Grammar conversion to JSGF error");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* build pocketsphinx grammar string */
|
||||||
|
grammar.write_function(&grammar,
|
||||||
|
"{start-input-timers=%s,no-input-timeout=%d,speech-timeout=%d,confidence-threshold=%d}%s",
|
||||||
|
component->start_timers ? "true" : "false",
|
||||||
|
component->initial_timeout,
|
||||||
|
component->max_silence,
|
||||||
|
(int)ceil(component->min_confidence * 100.0),
|
||||||
|
jsgf_path);
|
||||||
|
} else if (!strncmp(component->recognizer, "unimrcp", strlen("unimrcp"))) {
|
||||||
|
/* send inline grammar to unimrcp */
|
||||||
|
grammar.write_function(&grammar, "{start-input-timers=%s,confidence-threshold=%f,sensitivity-level=%f",
|
||||||
|
component->start_timers ? "true" : "false",
|
||||||
|
component->min_confidence,
|
||||||
|
component->sensitivity);
|
||||||
|
|
||||||
|
if (component->initial_timeout > 0) {
|
||||||
|
grammar.write_function(&grammar, ",no-input-timeout=%d",
|
||||||
|
component->initial_timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (component->max_silence > 0) {
|
||||||
|
grammar.write_function(&grammar, ",speech-complete-timeout=%d,speech-incomplete-timeout=%d",
|
||||||
|
component->max_silence,
|
||||||
|
component->max_silence);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!zstr(component->language)) {
|
||||||
|
grammar.write_function(&grammar, ",speech-language=%s", component->language);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(iks_find_attrib_soft(input, "mode"), "any")) {
|
||||||
|
/* set dtmf params */
|
||||||
|
if (component->inter_digit_timeout > 0) {
|
||||||
|
grammar.write_function(&grammar, ",dtmf-interdigit-timeout=%d", component->inter_digit_timeout);
|
||||||
|
}
|
||||||
|
if (component->term_digit) {
|
||||||
|
grammar.write_function(&grammar, ",dtmf-term-char=%c", component->term_digit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
grammar.write_function(&grammar, "}inline:%s", iks_find_cdata(input, "grammar"));
|
||||||
|
} else {
|
||||||
|
/* passthrough to unknown ASR module */
|
||||||
|
grammar.write_function(&grammar, "%s", iks_find_cdata(input, "grammar"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* acknowledge command */
|
||||||
|
rayo_component_send_start(RAYO_COMPONENT(component), iq);
|
||||||
|
|
||||||
|
/* start speech detection */
|
||||||
|
switch_channel_set_variable(switch_core_session_get_channel(session), "fire_asr_events", "true");
|
||||||
|
if (switch_ivr_detect_speech(session, component->recognizer, grammar.data, "mod_rayo_grammar", "", NULL) != SWITCH_STATUS_SUCCESS) {
|
||||||
|
handler->voice_component = NULL;
|
||||||
|
rayo_component_send_complete(RAYO_COMPONENT(component), COMPONENT_COMPLETE_ERROR);
|
||||||
|
}
|
||||||
|
switch_safe_free(grammar.data);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start call input on DTMF resource
|
||||||
|
*/
|
||||||
|
static iks *start_call_dtmf_input(struct input_component *component, switch_core_session_t *session, iks *input, iks *iq, const char *output_file, int barge_in)
|
||||||
|
{
|
||||||
|
/* parse the grammar */
|
||||||
|
if (!(component->grammar = srgs_parse(globals.parser, iks_find_cdata(input, "grammar")))) {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Failed to parse grammar body\n");
|
||||||
|
RAYO_UNLOCK(component);
|
||||||
|
RAYO_DESTROY(component);
|
||||||
|
return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "Failed to parse grammar body");
|
||||||
|
}
|
||||||
|
|
||||||
|
component->last_digit_time = switch_micro_time_now();
|
||||||
|
|
||||||
|
/* acknowledge command */
|
||||||
|
rayo_component_send_start(RAYO_COMPONENT(component), iq);
|
||||||
|
|
||||||
|
/* start dtmf input detection */
|
||||||
|
switch_core_hash_insert(component->handler->dtmf_components, RAYO_JID(component), component);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start call input for the given component
|
* Start call input for the given component
|
||||||
* @param component the input or prompt component
|
* @param component the input or prompt component
|
||||||
|
@ -351,35 +554,36 @@ static int validate_call_input(iks *input, const char **error)
|
||||||
*/
|
*/
|
||||||
static iks *start_call_input(struct input_component *component, switch_core_session_t *session, iks *input, iks *iq, const char *output_file, int barge_in)
|
static iks *start_call_input(struct input_component *component, switch_core_session_t *session, iks *input, iks *iq, const char *output_file, int barge_in)
|
||||||
{
|
{
|
||||||
|
iks *result = NULL;
|
||||||
|
|
||||||
/* set up input component for new detection */
|
/* set up input component for new detection */
|
||||||
struct input_handler *handler = (struct input_handler *)switch_channel_get_private(switch_core_session_get_channel(session), RAYO_INPUT_COMPONENT_PRIVATE_VAR);
|
struct input_handler *handler = (struct input_handler *)switch_channel_get_private(switch_core_session_get_channel(session), RAYO_INPUT_COMPONENT_PRIVATE_VAR);
|
||||||
if (!handler) {
|
if (!handler) {
|
||||||
/* create input component */
|
/* create input component */
|
||||||
handler = switch_core_session_alloc(session, sizeof(*handler));
|
handler = switch_core_session_alloc(session, sizeof(*handler));
|
||||||
switch_mutex_init(&handler->mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
|
switch_mutex_init(&handler->mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
|
||||||
|
switch_core_hash_init(&handler->dtmf_components, NULL);
|
||||||
switch_channel_set_private(switch_core_session_get_channel(session), RAYO_INPUT_COMPONENT_PRIVATE_VAR, handler);
|
switch_channel_set_private(switch_core_session_get_channel(session), RAYO_INPUT_COMPONENT_PRIVATE_VAR, handler);
|
||||||
handler->last_recognizer = "";
|
handler->last_recognizer = "";
|
||||||
|
|
||||||
|
/* fire up media bug to monitor lifecycle */
|
||||||
|
if (switch_core_media_bug_add(session, "rayo_input_component", NULL, input_handler_bug_callback, handler, 0, SMBF_READ_REPLACE, &handler->bug) != SWITCH_STATUS_SUCCESS) {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Failed to create input handler media bug\n");
|
||||||
|
RAYO_UNLOCK(component);
|
||||||
|
RAYO_DESTROY(component);
|
||||||
|
return iks_new_error_detailed(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, "Failed to create input handler media bug");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO break up this function by mode... dtmf/voice/fax/etc */
|
switch_mutex_lock(handler->mutex);
|
||||||
component->speech_mode = strcmp(iks_find_attrib_soft(input, "mode"), "dtmf");
|
|
||||||
if (component->speech_mode && handler->voice_component) {
|
|
||||||
/* don't allow multi voice input */
|
|
||||||
RAYO_UNLOCK(component);
|
|
||||||
RAYO_DESTROY(component);
|
|
||||||
return iks_new_error_detailed(iq, STANZA_ERROR_CONFLICT, "Multiple voice input is not allowed");
|
|
||||||
}
|
|
||||||
if (!component->speech_mode && handler->dtmf_component) {
|
|
||||||
/* don't allow multi dtmf input */
|
|
||||||
RAYO_UNLOCK(component);
|
|
||||||
RAYO_DESTROY(component);
|
|
||||||
return iks_new_error_detailed(iq, STANZA_ERROR_CONFLICT, "Multiple dtmf input is not allowed");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (component->speech_mode) {
|
if (!handler->dtmf_components) {
|
||||||
handler->voice_component = component;
|
/* handler bug was destroyed */
|
||||||
} else {
|
switch_mutex_unlock(handler->mutex);
|
||||||
handler->dtmf_component = component;
|
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Input handler media bug is closed\n");
|
||||||
|
RAYO_UNLOCK(component);
|
||||||
|
RAYO_DESTROY(component);
|
||||||
|
return iks_new_error_detailed(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, "Input handler media bug is closed\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
component->grammar = NULL;
|
component->grammar = NULL;
|
||||||
|
@ -397,123 +601,17 @@ static iks *start_call_input(struct input_component *component, switch_core_sess
|
||||||
component->recognizer = iks_find_attrib(input, "recognizer");
|
component->recognizer = iks_find_attrib(input, "recognizer");
|
||||||
component->language = iks_find_attrib(input, "language");
|
component->language = iks_find_attrib(input, "language");
|
||||||
component->handler = handler;
|
component->handler = handler;
|
||||||
|
component->speech_mode = strcmp(iks_find_attrib_soft(input, "mode"), "dtmf");
|
||||||
|
|
||||||
/* is this voice or dtmf srgs grammar? */
|
if (component->speech_mode) {
|
||||||
if (!component->speech_mode) {
|
result = start_call_voice_input(component, session, input, iq, output_file, barge_in);
|
||||||
|
|
||||||
/* parse the grammar */
|
|
||||||
if (!(component->grammar = srgs_parse(globals.parser, iks_find_cdata(input, "grammar")))) {
|
|
||||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Failed to parse grammar body\n");
|
|
||||||
RAYO_UNLOCK(component);
|
|
||||||
RAYO_DESTROY(component);
|
|
||||||
return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "Failed to parse grammar body");
|
|
||||||
}
|
|
||||||
|
|
||||||
component->last_digit_time = switch_micro_time_now();
|
|
||||||
|
|
||||||
/* acknowledge command */
|
|
||||||
rayo_component_send_start(RAYO_COMPONENT(component), iq);
|
|
||||||
|
|
||||||
/* start dtmf input detection */
|
|
||||||
if (switch_core_media_bug_add(session, "rayo_input_component", NULL, input_component_bug_callback, handler, 0, SMBF_READ_REPLACE, &handler->bug) != SWITCH_STATUS_SUCCESS) {
|
|
||||||
handler->dtmf_component = NULL;
|
|
||||||
rayo_component_send_complete(RAYO_COMPONENT(component), COMPONENT_COMPLETE_ERROR);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
switch_stream_handle_t grammar = { 0 };
|
result = start_call_dtmf_input(component, session, input, iq, output_file, barge_in);
|
||||||
SWITCH_STANDARD_STREAM(grammar);
|
|
||||||
|
|
||||||
if (zstr(component->recognizer)) {
|
|
||||||
component->recognizer = globals.default_recognizer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if recognition engine is different, we can't handle this request */
|
|
||||||
if (!zstr(handler->last_recognizer) && strcmp(component->recognizer, handler->last_recognizer)) {
|
|
||||||
handler->voice_component = NULL;
|
|
||||||
RAYO_UNLOCK(component);
|
|
||||||
RAYO_DESTROY(component);
|
|
||||||
return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "Must use the same recognizer for the entire call");
|
|
||||||
}
|
|
||||||
handler->last_recognizer = switch_core_session_strdup(session, component->recognizer);
|
|
||||||
|
|
||||||
if (!strcmp(component->recognizer, "pocketsphinx")) {
|
|
||||||
const char *jsgf_path;
|
|
||||||
|
|
||||||
/* transform SRGS grammar to JSGF */
|
|
||||||
if (!(component->grammar = srgs_parse(globals.parser, iks_find_cdata(input, "grammar")))) {
|
|
||||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Failed to parse grammar body\n");
|
|
||||||
handler->voice_component = NULL;
|
|
||||||
RAYO_UNLOCK(component);
|
|
||||||
RAYO_DESTROY(component);
|
|
||||||
return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "Failed to parse grammar body");
|
|
||||||
}
|
|
||||||
jsgf_path = srgs_grammar_to_jsgf_file(component->grammar, SWITCH_GLOBAL_dirs.grammar_dir, "gram");
|
|
||||||
if (!jsgf_path) {
|
|
||||||
handler->voice_component = NULL;
|
|
||||||
RAYO_UNLOCK(component);
|
|
||||||
RAYO_DESTROY(component);
|
|
||||||
return iks_new_error_detailed(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, "Grammar conversion to JSGF error");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* build pocketsphinx grammar string */
|
|
||||||
grammar.write_function(&grammar,
|
|
||||||
"{start-input-timers=%s,no-input-timeout=%d,speech-timeout=%d,confidence-threshold=%d}%s",
|
|
||||||
component->start_timers ? "true" : "false",
|
|
||||||
component->initial_timeout,
|
|
||||||
component->max_silence,
|
|
||||||
(int)ceil(component->min_confidence * 100.0),
|
|
||||||
jsgf_path);
|
|
||||||
} else if (!strncmp(component->recognizer, "unimrcp", strlen("unimrcp"))) {
|
|
||||||
/* send inline grammar to unimrcp */
|
|
||||||
grammar.write_function(&grammar, "{start-input-timers=%s,confidence-threshold=%f,sensitivity-level=%f",
|
|
||||||
component->start_timers ? "true" : "false",
|
|
||||||
component->min_confidence,
|
|
||||||
component->sensitivity);
|
|
||||||
|
|
||||||
if (component->initial_timeout > 0) {
|
|
||||||
grammar.write_function(&grammar, ",no-input-timeout=%d",
|
|
||||||
component->initial_timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (component->max_silence > 0) {
|
|
||||||
grammar.write_function(&grammar, ",speech-complete-timeout=%d,speech-incomplete-timeout=%d",
|
|
||||||
component->max_silence,
|
|
||||||
component->max_silence);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!zstr(component->language)) {
|
|
||||||
grammar.write_function(&grammar, ",speech-language=%s", component->language);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!strcmp(iks_find_attrib_soft(input, "mode"), "any")) {
|
|
||||||
/* set dtmf params */
|
|
||||||
if (component->inter_digit_timeout > 0) {
|
|
||||||
grammar.write_function(&grammar, ",dtmf-interdigit-timeout=%d", component->inter_digit_timeout);
|
|
||||||
}
|
|
||||||
if (component->term_digit) {
|
|
||||||
grammar.write_function(&grammar, ",dtmf-term-char=%c", component->term_digit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
grammar.write_function(&grammar, "}inline:%s", iks_find_cdata(input, "grammar"));
|
|
||||||
} else {
|
|
||||||
/* passthrough to unknown ASR module */
|
|
||||||
grammar.write_function(&grammar, "%s", iks_find_cdata(input, "grammar"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* acknowledge command */
|
|
||||||
rayo_component_send_start(RAYO_COMPONENT(component), iq);
|
|
||||||
|
|
||||||
/* start speech detection */
|
|
||||||
switch_channel_set_variable(switch_core_session_get_channel(session), "fire_asr_events", "true");
|
|
||||||
if (switch_ivr_detect_speech(session, component->recognizer, grammar.data, "mod_rayo_grammar", "", NULL) != SWITCH_STATUS_SUCCESS) {
|
|
||||||
handler->voice_component = NULL;
|
|
||||||
rayo_component_send_complete(RAYO_COMPONENT(component), COMPONENT_COMPLETE_ERROR);
|
|
||||||
}
|
|
||||||
switch_safe_free(grammar.data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
switch_mutex_unlock(handler->mutex);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -527,6 +625,9 @@ static char *create_input_component_id(switch_core_session_t *session, iks *inpu
|
||||||
const char *mode = "unk";
|
const char *mode = "unk";
|
||||||
if (input) {
|
if (input) {
|
||||||
mode = iks_find_attrib_soft(input, "mode");
|
mode = iks_find_attrib_soft(input, "mode");
|
||||||
|
if (!strcmp(mode, "dtmf")) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
if (!strcmp(mode, "any")) {
|
if (!strcmp(mode, "any")) {
|
||||||
mode = "voice";
|
mode = "voice";
|
||||||
}
|
}
|
||||||
|
@ -575,13 +676,10 @@ static iks *stop_call_input_component(struct rayo_actor *component, struct rayo_
|
||||||
switch_core_session_t *session = switch_core_session_locate(RAYO_COMPONENT(component)->parent->id);
|
switch_core_session_t *session = switch_core_session_locate(RAYO_COMPONENT(component)->parent->id);
|
||||||
if (session) {
|
if (session) {
|
||||||
switch_mutex_lock(input_component->handler->mutex);
|
switch_mutex_lock(input_component->handler->mutex);
|
||||||
|
input_component->stop = 1;
|
||||||
if (input_component->speech_mode) {
|
if (input_component->speech_mode) {
|
||||||
input_component->stop = 1;
|
|
||||||
switch_ivr_stop_detect_speech(session);
|
switch_ivr_stop_detect_speech(session);
|
||||||
rayo_component_send_complete(RAYO_COMPONENT(component), COMPONENT_COMPLETE_STOP);
|
rayo_component_send_complete(RAYO_COMPONENT(component), COMPONENT_COMPLETE_STOP);
|
||||||
} else if (input_component->handler->bug) {
|
|
||||||
input_component->stop = 1;
|
|
||||||
switch_core_media_bug_remove(session, &input_component->handler->bug);
|
|
||||||
}
|
}
|
||||||
switch_mutex_unlock(input_component->handler->mutex);
|
switch_mutex_unlock(input_component->handler->mutex);
|
||||||
switch_core_session_rwunlock(session);
|
switch_core_session_rwunlock(session);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* mod_rayo for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
* mod_rayo for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||||
* Copyright (C) 2013, Grasshopper
|
* Copyright (C) 2013-2014, Grasshopper
|
||||||
*
|
*
|
||||||
* Version: MPL 1.1
|
* Version: MPL 1.1
|
||||||
*
|
*
|
||||||
|
@ -186,6 +186,9 @@ static iks *start_mixer_output_component(struct rayo_actor *mixer, struct rayo_m
|
||||||
}
|
}
|
||||||
stream.write_function(&stream, "}fileman://rayo://%s", RAYO_JID(component));
|
stream.write_function(&stream, "}fileman://rayo://%s", RAYO_JID(component));
|
||||||
|
|
||||||
|
/* acknowledge command */
|
||||||
|
rayo_component_send_start(component, iq);
|
||||||
|
|
||||||
rayo_component_api_execute_async(component, "conference", stream.data);
|
rayo_component_api_execute_async(component, "conference", stream.data);
|
||||||
|
|
||||||
switch_safe_free(stream.data);
|
switch_safe_free(stream.data);
|
||||||
|
|
Loading…
Reference in New Issue