mirror of
https://github.com/signalwire/freeswitch.git
synced 2025-04-15 16:39:14 +00:00
gather 2833 into RTP core and a few tweaks
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@1351 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
parent
81c4e9f959
commit
23d6224dab
@ -228,6 +228,38 @@ SWITCH_DECLARE(void) switch_rtp_set_invald_handler(switch_rtp_t *rtp_session, sw
|
|||||||
*/
|
*/
|
||||||
SWITCH_DECLARE(switch_status_t) switch_rtp_read(switch_rtp_t *rtp_session, void *data, uint32_t *datalen, switch_payload_t *payload_type, switch_frame_flag_t *flags);
|
SWITCH_DECLARE(switch_status_t) switch_rtp_read(switch_rtp_t *rtp_session, void *data, uint32_t *datalen, switch_payload_t *payload_type, switch_frame_flag_t *flags);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Queue RFC2833 DTMF data into an RTP Session
|
||||||
|
\param rtp_session the rtp session to use
|
||||||
|
\param digits the digit string to queue
|
||||||
|
\param duration the duration of the dtmf
|
||||||
|
*/
|
||||||
|
SWITCH_DECLARE(switch_status_t) switch_rtp_queue_rfc2833(switch_rtp_t *rtp_session, char *digits, uint32_t duration);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Test for presence of DTMF on a given RTP session
|
||||||
|
\param rtp_session session to test
|
||||||
|
\return number of digits in the queue
|
||||||
|
*/
|
||||||
|
SWITCH_DECLARE(switch_size_t) switch_rtp_has_dtmf(switch_rtp_t *rtp_session);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Queue DTMF on a given RTP session
|
||||||
|
\param rtp_session RTP session to queue DTMF to
|
||||||
|
\param dtmf string of digits to queue
|
||||||
|
\return SWITCH_STATUS_SUCCESS if successful
|
||||||
|
*/
|
||||||
|
SWITCH_DECLARE(switch_status_t) switch_rtp_queue_dtmf(switch_rtp_t *rtp_session, char *dtmf);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Retrieve DTMF digits from a given RTP session
|
||||||
|
\param rtp_session RTP session to retrieve digits from
|
||||||
|
\param dtmf buffer to write dtmf to
|
||||||
|
\param len max size in bytes of the buffer
|
||||||
|
\return number of bytes read into the buffer
|
||||||
|
*/
|
||||||
|
SWITCH_DECLARE(switch_size_t) switch_rtp_dequeue_dtmf(switch_rtp_t *rtp_session, char *dtmf, switch_size_t len);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief Read data from a given RTP session without copying
|
\brief Read data from a given RTP session without copying
|
||||||
\param rtp_session the RTP session to read from
|
\param rtp_session the RTP session to read from
|
||||||
@ -237,7 +269,11 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_read(switch_rtp_t *rtp_session, void
|
|||||||
\param flags flags
|
\param flags flags
|
||||||
\return the number of bytes read
|
\return the number of bytes read
|
||||||
*/
|
*/
|
||||||
SWITCH_DECLARE(switch_status_t) switch_rtp_zerocopy_read(switch_rtp_t *rtp_session, void **data, uint32_t *datalen, switch_payload_t *payload_type, switch_frame_flag_t *flags);
|
SWITCH_DECLARE(switch_status_t) switch_rtp_zerocopy_read(switch_rtp_t *rtp_session,
|
||||||
|
void **data,
|
||||||
|
uint32_t *datalen,
|
||||||
|
switch_payload_t *payload_type,
|
||||||
|
switch_frame_flag_t *flags);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief Read data from a given RTP session without copying
|
\brief Read data from a given RTP session without copying
|
||||||
|
@ -517,6 +517,8 @@ typedef enum {
|
|||||||
SWITCH_EVENT_TALK - Talking Detected
|
SWITCH_EVENT_TALK - Talking Detected
|
||||||
SWITCH_EVENT_NOTALK - Not Talking Detected
|
SWITCH_EVENT_NOTALK - Not Talking Detected
|
||||||
SWITCH_EVENT_SESSION_CRASH - Session Crashed
|
SWITCH_EVENT_SESSION_CRASH - Session Crashed
|
||||||
|
SWITCH_EVENT_MODULE_LOAD - Module was loaded
|
||||||
|
SWITCH_EVENT_DTMF - DTMF was sent
|
||||||
SWITCH_EVENT_ALL - All events at once
|
SWITCH_EVENT_ALL - All events at once
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
@ -543,6 +545,7 @@ typedef enum {
|
|||||||
SWITCH_EVENT_NOTALK,
|
SWITCH_EVENT_NOTALK,
|
||||||
SWITCH_EVENT_SESSION_CRASH,
|
SWITCH_EVENT_SESSION_CRASH,
|
||||||
SWITCH_EVENT_MODULE_LOAD,
|
SWITCH_EVENT_MODULE_LOAD,
|
||||||
|
SWITCH_EVENT_DTMF,
|
||||||
SWITCH_EVENT_ALL
|
SWITCH_EVENT_ALL
|
||||||
} switch_event_types_t;
|
} switch_event_types_t;
|
||||||
|
|
||||||
|
@ -85,6 +85,13 @@ SWITCH_DECLARE(char) switch_rfc2833_to_char(int event);
|
|||||||
*/
|
*/
|
||||||
SWITCH_DECLARE(unsigned char) switch_char_to_rfc2833(char key);
|
SWITCH_DECLARE(unsigned char) switch_char_to_rfc2833(char key);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief determine if a character is a valid DTMF key
|
||||||
|
\param key the key to test
|
||||||
|
\return TRUE or FALSE
|
||||||
|
*/
|
||||||
|
#define is_dtmf(key) ((key > 47 && key < 58) || (key > 64 && key < 69) || (key > 96 && key < 101) || key == 35 || key == 42)
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief Duplicate a string
|
\brief Duplicate a string
|
||||||
*/
|
*/
|
||||||
|
@ -124,18 +124,9 @@ struct private_object {
|
|||||||
char *remote_user;
|
char *remote_user;
|
||||||
unsigned int cand_id;
|
unsigned int cand_id;
|
||||||
unsigned int desc_id;
|
unsigned int desc_id;
|
||||||
char last_digit;
|
|
||||||
unsigned int dc;
|
unsigned int dc;
|
||||||
time_t last_digit_time;
|
|
||||||
switch_queue_t *dtmf_queue;
|
|
||||||
char out_digit;
|
|
||||||
unsigned char out_digit_packet[4];
|
|
||||||
unsigned int out_digit_sofar;
|
|
||||||
unsigned int out_digit_dur;
|
|
||||||
uint16_t out_digit_seq;
|
|
||||||
int32_t timestamp_send;
|
int32_t timestamp_send;
|
||||||
int32_t timestamp_recv;
|
int32_t timestamp_recv;
|
||||||
int32_t timestamp_dtmf;
|
|
||||||
uint32_t last_read;
|
uint32_t last_read;
|
||||||
char *codec_name;
|
char *codec_name;
|
||||||
switch_payload_t codec_num;
|
switch_payload_t codec_num;
|
||||||
@ -718,11 +709,14 @@ static switch_status_t channel_send_dtmf(switch_core_session_t *session, char *d
|
|||||||
assert(tech_pvt != NULL);
|
assert(tech_pvt != NULL);
|
||||||
|
|
||||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "DTMF [%s]\n", dtmf);
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "DTMF [%s]\n", dtmf);
|
||||||
snprintf(digits, sizeof(digits), "+%s\n", dtmf);
|
//snprintf(digits, sizeof(digits), "+%s\n", dtmf);
|
||||||
ldl_handle_send_msg(tech_pvt->profile->handle, tech_pvt->recip, NULL, digits);
|
//ldl_handle_send_msg(tech_pvt->profile->handle, tech_pvt->recip, NULL, digits);
|
||||||
|
|
||||||
|
return switch_rtp_queue_rfc2833(tech_pvt->rtp_session,
|
||||||
|
digits,
|
||||||
|
100 * (tech_pvt->read_codec.implementation->samples_per_second / 1000));
|
||||||
|
|
||||||
return SWITCH_STATUS_SUCCESS;
|
//return SWITCH_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, int timeout,
|
static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, int timeout,
|
||||||
@ -769,41 +763,16 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch
|
|||||||
return SWITCH_STATUS_BREAK;
|
return SWITCH_STATUS_BREAK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* RFC2833 ... TBD try harder to honor the duration etc.*/
|
|
||||||
if (payload == 101) {
|
|
||||||
unsigned char *packet = tech_pvt->read_frame.data;
|
|
||||||
int end = packet[1]&0x80;
|
|
||||||
int duration = (packet[2]<<8) + packet[3];
|
|
||||||
char key = switch_rfc2833_to_char(packet[0]);
|
|
||||||
|
|
||||||
/* SHEESH.... Curse you RFC2833 inventors!!!!*/
|
|
||||||
if ((time(NULL) - tech_pvt->last_digit_time) > 2) {
|
|
||||||
tech_pvt->last_digit = 0;
|
|
||||||
tech_pvt->dc = 0;
|
|
||||||
}
|
|
||||||
if (duration && end) {
|
|
||||||
if (key != tech_pvt->last_digit) {
|
|
||||||
char digit_str[] = {key, 0};
|
|
||||||
time(&tech_pvt->last_digit_time);
|
|
||||||
switch_channel_queue_dtmf(channel, digit_str);
|
|
||||||
switch_set_flag(tech_pvt, TFLAG_DTMF);
|
|
||||||
}
|
|
||||||
if (++tech_pvt->dc >= 3) {
|
|
||||||
tech_pvt->last_digit = 0;
|
|
||||||
tech_pvt->dc = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
tech_pvt->last_digit = key;
|
|
||||||
} else {
|
|
||||||
tech_pvt->last_digit = 0;
|
|
||||||
tech_pvt->dc = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (switch_test_flag(&tech_pvt->read_frame, SFF_CNG)) {
|
if (switch_test_flag(&tech_pvt->read_frame, SFF_CNG)) {
|
||||||
tech_pvt->read_frame.datalen = tech_pvt->last_read ? tech_pvt->last_read : tech_pvt->read_codec.implementation->encoded_bytes_per_frame;
|
tech_pvt->read_frame.datalen = tech_pvt->last_read ? tech_pvt->last_read : tech_pvt->read_codec.implementation->encoded_bytes_per_frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (switch_rtp_has_dtmf(tech_pvt->rtp_session)) {
|
||||||
|
char dtmf[128];
|
||||||
|
switch_rtp_dequeue_dtmf(tech_pvt->rtp_session, dtmf, sizeof(dtmf));
|
||||||
|
switch_channel_queue_dtmf(channel, dtmf);
|
||||||
|
}
|
||||||
|
|
||||||
if (tech_pvt->read_frame.datalen > 0) {
|
if (tech_pvt->read_frame.datalen > 0) {
|
||||||
bytes = tech_pvt->read_codec.implementation->encoded_bytes_per_frame;
|
bytes = tech_pvt->read_codec.implementation->encoded_bytes_per_frame;
|
||||||
frames = (tech_pvt->read_frame.datalen / bytes);
|
frames = (tech_pvt->read_frame.datalen / bytes);
|
||||||
@ -867,66 +836,6 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc
|
|||||||
frames = ((int) frame->datalen / bytes);
|
frames = ((int) frame->datalen / bytes);
|
||||||
samples = frames * tech_pvt->read_codec.implementation->samples_per_frame;
|
samples = frames * tech_pvt->read_codec.implementation->samples_per_frame;
|
||||||
|
|
||||||
if (tech_pvt->out_digit_dur > 0) {
|
|
||||||
int x, ts, loops = 1, duration;
|
|
||||||
|
|
||||||
tech_pvt->out_digit_sofar += samples;
|
|
||||||
|
|
||||||
if (tech_pvt->out_digit_sofar >= tech_pvt->out_digit_dur) {
|
|
||||||
duration = tech_pvt->out_digit_dur;
|
|
||||||
tech_pvt->out_digit_packet[1] |= 0x80;
|
|
||||||
tech_pvt->out_digit_dur = 0;
|
|
||||||
loops = 3;
|
|
||||||
} else {
|
|
||||||
duration = tech_pvt->out_digit_sofar;
|
|
||||||
}
|
|
||||||
|
|
||||||
ts = tech_pvt->timestamp_dtmf += samples;
|
|
||||||
tech_pvt->out_digit_packet[2] = (unsigned char) (duration >> 8);
|
|
||||||
tech_pvt->out_digit_packet[3] = (unsigned char) duration;
|
|
||||||
|
|
||||||
|
|
||||||
for (x = 0; x < loops; x++) {
|
|
||||||
switch_rtp_write_manual(tech_pvt->rtp_session, tech_pvt->out_digit_packet, 4, 0, 101, ts, tech_pvt->out_digit_seq, &frame->flags);
|
|
||||||
/*
|
|
||||||
printf("Send %s packet for [%c] ts=%d sofar=%u dur=%d\n", loops == 1 ? "middle" : "end", tech_pvt->out_digit, ts,
|
|
||||||
tech_pvt->out_digit_sofar, duration);
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tech_pvt->out_digit_dur && tech_pvt->dtmf_queue && switch_queue_size(tech_pvt->dtmf_queue)) {
|
|
||||||
void *pop;
|
|
||||||
|
|
||||||
if (switch_queue_trypop(tech_pvt->dtmf_queue, &pop) == SWITCH_STATUS_SUCCESS) {
|
|
||||||
int x, ts;
|
|
||||||
struct rfc2833_digit *rdigit = pop;
|
|
||||||
|
|
||||||
memset(tech_pvt->out_digit_packet, 0, 4);
|
|
||||||
tech_pvt->out_digit_sofar = 0;
|
|
||||||
tech_pvt->out_digit_dur = rdigit->duration;
|
|
||||||
tech_pvt->out_digit = rdigit->digit;
|
|
||||||
tech_pvt->out_digit_packet[0] = (unsigned char)switch_char_to_rfc2833(rdigit->digit);
|
|
||||||
tech_pvt->out_digit_packet[1] = 7;
|
|
||||||
|
|
||||||
ts = tech_pvt->timestamp_dtmf += samples;
|
|
||||||
tech_pvt->out_digit_seq++;
|
|
||||||
for (x = 0; x < 3; x++) {
|
|
||||||
switch_rtp_write_manual(tech_pvt->rtp_session, tech_pvt->out_digit_packet, 4, 1, 101, ts, tech_pvt->out_digit_seq, &frame->flags);
|
|
||||||
/*
|
|
||||||
printf("Send start packet for [%c] ts=%d sofar=%u dur=%d\n", tech_pvt->out_digit, ts,
|
|
||||||
tech_pvt->out_digit_sofar, 0);
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
free(rdigit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//printf("%s send %d bytes %d samples in %d frames ts=%d\n", switch_channel_get_name(channel), frame->datalen, samples, frames, tech_pvt->timestamp_send);
|
//printf("%s send %d bytes %d samples in %d frames ts=%d\n", switch_channel_get_name(channel), frame->datalen, samples, frames, tech_pvt->timestamp_send);
|
||||||
|
|
||||||
if (switch_rtp_write_frame(tech_pvt->rtp_session, frame, samples) < 0) {
|
if (switch_rtp_write_frame(tech_pvt->rtp_session, frame, samples) < 0) {
|
||||||
|
@ -108,7 +108,6 @@ struct private_object {
|
|||||||
int tid;
|
int tid;
|
||||||
int32_t timestamp_send;
|
int32_t timestamp_send;
|
||||||
int32_t timestamp_recv;
|
int32_t timestamp_recv;
|
||||||
int32_t timestamp_dtmf;
|
|
||||||
int payload_num;
|
int payload_num;
|
||||||
switch_rtp_t *rtp_session;
|
switch_rtp_t *rtp_session;
|
||||||
struct osip_rfc3264 *sdp_config;
|
struct osip_rfc3264 *sdp_config;
|
||||||
@ -120,24 +119,12 @@ struct private_object {
|
|||||||
switch_port_t local_sdp_audio_port;
|
switch_port_t local_sdp_audio_port;
|
||||||
char call_id[50];
|
char call_id[50];
|
||||||
int ssrc;
|
int ssrc;
|
||||||
char last_digit;
|
|
||||||
unsigned int dc;
|
|
||||||
time_t last_digit_time;
|
|
||||||
switch_queue_t *dtmf_queue;
|
|
||||||
char out_digit;
|
|
||||||
switch_time_t last_read;
|
switch_time_t last_read;
|
||||||
unsigned char out_digit_packet[4];
|
|
||||||
unsigned int out_digit_sofar;
|
|
||||||
unsigned int out_digit_dur;
|
|
||||||
uint16_t out_digit_seq;
|
|
||||||
char *realm;
|
char *realm;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct rfc2833_digit {
|
|
||||||
char digit;
|
|
||||||
int duration;
|
|
||||||
};
|
|
||||||
|
|
||||||
SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_dialplan, globals.dialplan)
|
SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_dialplan, globals.dialplan)
|
||||||
SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_extrtpip, globals.extrtpip)
|
SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_extrtpip, globals.extrtpip)
|
||||||
@ -642,34 +629,10 @@ static switch_status_t exosip_read_frame(switch_core_session_t *session, switch_
|
|||||||
return SWITCH_STATUS_BREAK;
|
return SWITCH_STATUS_BREAK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* RFC2833 ... TBD try harder to honor the duration etc.*/
|
if (switch_rtp_has_dtmf(tech_pvt->rtp_session)) {
|
||||||
if (payload == 101) {
|
char dtmf[128];
|
||||||
unsigned char *packet = tech_pvt->read_frame.data;
|
switch_rtp_dequeue_dtmf(tech_pvt->rtp_session, dtmf, sizeof(dtmf));
|
||||||
int end = packet[1]&0x80;
|
switch_channel_queue_dtmf(channel, dtmf);
|
||||||
int duration = (packet[2]<<8) + packet[3];
|
|
||||||
char key = switch_rfc2833_to_char(packet[0]);
|
|
||||||
|
|
||||||
/* SHEESH.... Curse you RFC2833 inventors!!!!*/
|
|
||||||
if ((time(NULL) - tech_pvt->last_digit_time) > 2) {
|
|
||||||
tech_pvt->last_digit = 0;
|
|
||||||
tech_pvt->dc = 0;
|
|
||||||
}
|
|
||||||
if (duration && end) {
|
|
||||||
if (key != tech_pvt->last_digit) {
|
|
||||||
char digit_str[] = {key, 0};
|
|
||||||
time(&tech_pvt->last_digit_time);
|
|
||||||
switch_channel_queue_dtmf(channel, digit_str);
|
|
||||||
}
|
|
||||||
if (++tech_pvt->dc >= 3) {
|
|
||||||
tech_pvt->last_digit = 0;
|
|
||||||
tech_pvt->dc = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
tech_pvt->last_digit = key;
|
|
||||||
} else {
|
|
||||||
tech_pvt->last_digit = 0;
|
|
||||||
tech_pvt->dc = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -740,67 +703,6 @@ static switch_status_t exosip_write_frame(switch_core_session_t *session, switch
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (tech_pvt->out_digit_dur > 0) {
|
|
||||||
int x, ts, loops = 1, duration;
|
|
||||||
|
|
||||||
tech_pvt->out_digit_sofar += samples;
|
|
||||||
|
|
||||||
if (tech_pvt->out_digit_sofar >= tech_pvt->out_digit_dur) {
|
|
||||||
duration = tech_pvt->out_digit_dur;
|
|
||||||
tech_pvt->out_digit_packet[1] |= 0x80;
|
|
||||||
tech_pvt->out_digit_dur = 0;
|
|
||||||
loops = 3;
|
|
||||||
} else {
|
|
||||||
duration = tech_pvt->out_digit_sofar;
|
|
||||||
}
|
|
||||||
|
|
||||||
ts = tech_pvt->timestamp_dtmf += samples;
|
|
||||||
tech_pvt->out_digit_packet[2] = (unsigned char) (duration >> 8);
|
|
||||||
tech_pvt->out_digit_packet[3] = (unsigned char) duration;
|
|
||||||
|
|
||||||
|
|
||||||
for (x = 0; x < loops; x++) {
|
|
||||||
frame->flags = 0;
|
|
||||||
switch_rtp_write_manual(tech_pvt->rtp_session,
|
|
||||||
tech_pvt->out_digit_packet, 4, 0, 101, ts,
|
|
||||||
loops == 1 ? tech_pvt->out_digit_seq++ : tech_pvt->out_digit_seq, &frame->flags);
|
|
||||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Send %s packet for [%c] ts=%d sofar=%u dur=%d\n",
|
|
||||||
loops == 1 ? "middle" : "end",
|
|
||||||
tech_pvt->out_digit,
|
|
||||||
ts,
|
|
||||||
tech_pvt->out_digit_sofar,
|
|
||||||
duration);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tech_pvt->out_digit_dur && tech_pvt->dtmf_queue && switch_queue_size(tech_pvt->dtmf_queue)) {
|
|
||||||
void *pop;
|
|
||||||
|
|
||||||
if (switch_queue_trypop(tech_pvt->dtmf_queue, &pop) == SWITCH_STATUS_SUCCESS) {
|
|
||||||
int x, ts;
|
|
||||||
struct rfc2833_digit *rdigit = pop;
|
|
||||||
|
|
||||||
memset(tech_pvt->out_digit_packet, 0, 4);
|
|
||||||
tech_pvt->out_digit_sofar = 0;
|
|
||||||
tech_pvt->out_digit_dur = rdigit->duration;
|
|
||||||
tech_pvt->out_digit = rdigit->digit;
|
|
||||||
tech_pvt->out_digit_packet[0] = (unsigned char)switch_char_to_rfc2833(rdigit->digit);
|
|
||||||
tech_pvt->out_digit_packet[1] = 7;
|
|
||||||
|
|
||||||
ts = tech_pvt->timestamp_dtmf += samples;
|
|
||||||
tech_pvt->out_digit_seq++;
|
|
||||||
for (x = 0; x < 3; x++) {
|
|
||||||
frame->flags = 0;
|
|
||||||
switch_rtp_write_manual(tech_pvt->rtp_session, tech_pvt->out_digit_packet, 4, 1, 101, ts, tech_pvt->out_digit_seq, &frame->flags);
|
|
||||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Send start packet for [%c] ts=%d sofar=%u dur=%d\n", tech_pvt->out_digit, ts,
|
|
||||||
tech_pvt->out_digit_sofar, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(rdigit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//printf("%s %s->%s send %d bytes %d samples in %d frames ts=%d\n", switch_channel_get_name(channel), tech_pvt->local_sdp_audio_ip, tech_pvt->remote_sdp_audio_ip, frame->datalen, samples, frames, tech_pvt->timestamp_send);
|
//printf("%s %s->%s send %d bytes %d samples in %d frames ts=%d\n", switch_channel_get_name(channel), tech_pvt->local_sdp_audio_ip, tech_pvt->remote_sdp_audio_ip, frame->datalen, samples, frames, tech_pvt->timestamp_send);
|
||||||
|
|
||||||
@ -869,29 +771,14 @@ static switch_status_t exosip_waitfor_write(switch_core_session_t *session, int
|
|||||||
static switch_status_t exosip_send_dtmf(switch_core_session_t *session, char *digits)
|
static switch_status_t exosip_send_dtmf(switch_core_session_t *session, char *digits)
|
||||||
{
|
{
|
||||||
struct private_object *tech_pvt;
|
struct private_object *tech_pvt;
|
||||||
char *c;
|
|
||||||
|
|
||||||
tech_pvt = switch_core_session_get_private(session);
|
tech_pvt = switch_core_session_get_private(session);
|
||||||
assert(tech_pvt != NULL);
|
assert(tech_pvt != NULL);
|
||||||
|
|
||||||
if (!tech_pvt->dtmf_queue) {
|
return switch_rtp_queue_rfc2833(tech_pvt->rtp_session,
|
||||||
switch_queue_create(&tech_pvt->dtmf_queue, 100, switch_core_session_get_pool(session));
|
digits,
|
||||||
}
|
globals.dtmf_duration * (tech_pvt->read_codec.implementation->samples_per_second / 1000));
|
||||||
|
|
||||||
for(c = digits; *c; c++) {
|
|
||||||
struct rfc2833_digit *rdigit;
|
|
||||||
|
|
||||||
if ((rdigit = malloc(sizeof(*rdigit))) != 0) {
|
|
||||||
memset(rdigit, 0, sizeof(*rdigit));
|
|
||||||
rdigit->digit = *c;
|
|
||||||
rdigit->duration = globals.dtmf_duration * (tech_pvt->read_codec.implementation->samples_per_second / 1000);
|
|
||||||
switch_queue_push(tech_pvt->dtmf_queue, rdigit);
|
|
||||||
} else {
|
|
||||||
return SWITCH_STATUS_MEMERR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return SWITCH_STATUS_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static switch_status_t exosip_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg)
|
static switch_status_t exosip_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg)
|
||||||
|
@ -238,7 +238,7 @@ SWITCH_DECLARE(switch_status_t) switch_channel_queue_dtmf(switch_channel_t *chan
|
|||||||
|
|
||||||
p = dtmf;
|
p = dtmf;
|
||||||
while(wr < len && p) {
|
while(wr < len && p) {
|
||||||
if (*p > 47 && *p < 58) {
|
if (is_dtmf(*p)) {
|
||||||
wr++;
|
wr++;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
@ -265,7 +265,7 @@ SWITCH_DECLARE(switch_size_t) switch_channel_dequeue_dtmf(switch_channel_t *chan
|
|||||||
}
|
}
|
||||||
switch_mutex_unlock(channel->dtmf_mutex);
|
switch_mutex_unlock(channel->dtmf_mutex);
|
||||||
|
|
||||||
if (bytes && switch_event_create(&event, SWITCH_EVENT_CHANNEL_ANSWER) == SWITCH_STATUS_SUCCESS) {
|
if (bytes && switch_event_create(&event, SWITCH_EVENT_DTMF) == SWITCH_STATUS_SUCCESS) {
|
||||||
switch_channel_event_set_data(channel, event);
|
switch_channel_event_set_data(channel, event);
|
||||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "DTMF-String", dtmf);
|
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "DTMF-String", dtmf);
|
||||||
switch_event_fire(&event);
|
switch_event_fire(&event);
|
||||||
|
@ -111,6 +111,7 @@ static char *EVENT_NAMES[] = {
|
|||||||
"NOTALK",
|
"NOTALK",
|
||||||
"SESSION_CRASH",
|
"SESSION_CRASH",
|
||||||
"MODULE_LOAD",
|
"MODULE_LOAD",
|
||||||
|
"DTMF",
|
||||||
"ALL"
|
"ALL"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
233
src/switch_rtp.c
233
src/switch_rtp.c
@ -58,6 +58,11 @@ typedef struct {
|
|||||||
} rtp_msg_t;
|
} rtp_msg_t;
|
||||||
|
|
||||||
|
|
||||||
|
struct rfc2833_digit {
|
||||||
|
char digit;
|
||||||
|
int duration;
|
||||||
|
};
|
||||||
|
|
||||||
struct switch_rtp_vad_data {
|
struct switch_rtp_vad_data {
|
||||||
switch_core_session_t *session;
|
switch_core_session_t *session;
|
||||||
switch_codec_t vad_codec;
|
switch_codec_t vad_codec;
|
||||||
@ -80,6 +85,22 @@ struct switch_rtp_vad_data {
|
|||||||
time_t next_scan;
|
time_t next_scan;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct switch_rtp_rfc2833_data {
|
||||||
|
switch_queue_t *dtmf_queue;
|
||||||
|
char out_digit;
|
||||||
|
unsigned char out_digit_packet[4];
|
||||||
|
unsigned int out_digit_sofar;
|
||||||
|
unsigned int out_digit_dur;
|
||||||
|
uint16_t out_digit_seq;
|
||||||
|
int32_t timestamp_dtmf;
|
||||||
|
char last_digit;
|
||||||
|
unsigned int dc;
|
||||||
|
time_t last_digit_time;
|
||||||
|
switch_buffer_t *dtmf_buffer;
|
||||||
|
switch_mutex_t *dtmf_mutex;
|
||||||
|
};
|
||||||
|
|
||||||
struct switch_rtp {
|
struct switch_rtp {
|
||||||
switch_socket_t *sock;
|
switch_socket_t *sock;
|
||||||
|
|
||||||
@ -113,6 +134,7 @@ struct switch_rtp {
|
|||||||
uint8_t stuncount;
|
uint8_t stuncount;
|
||||||
switch_buffer_t *packet_buffer;
|
switch_buffer_t *packet_buffer;
|
||||||
struct switch_rtp_vad_data vad_data;
|
struct switch_rtp_vad_data vad_data;
|
||||||
|
struct switch_rtp_rfc2833_data dtmf_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int global_init = 0;
|
static int global_init = 0;
|
||||||
@ -298,7 +320,8 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_create(switch_rtp_t **new_rtp_session
|
|||||||
|
|
||||||
rtp_session->pool = pool;
|
rtp_session->pool = pool;
|
||||||
rtp_session->flags = flags;
|
rtp_session->flags = flags;
|
||||||
|
switch_mutex_init(&rtp_session->dtmf_data.dtmf_mutex, SWITCH_MUTEX_NESTED, rtp_session->pool);
|
||||||
|
switch_buffer_create(rtp_session->pool, &rtp_session->dtmf_data.dtmf_buffer, 128);
|
||||||
/* for from address on recvfrom calls */
|
/* for from address on recvfrom calls */
|
||||||
switch_sockaddr_info_get(&rtp_session->from_addr, NULL, SWITCH_UNSPEC, 0, 0, rtp_session->pool);
|
switch_sockaddr_info_get(&rtp_session->from_addr, NULL, SWITCH_UNSPEC, 0, 0, rtp_session->pool);
|
||||||
|
|
||||||
@ -514,6 +537,82 @@ SWITCH_DECLARE(void) switch_rtp_clear_flag(switch_rtp_t *rtp_session, switch_rtp
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void do_2833(switch_rtp_t *rtp_session)
|
||||||
|
{
|
||||||
|
switch_frame_flag_t flags = 0;
|
||||||
|
uint32_t samples = rtp_session->packet_size;
|
||||||
|
|
||||||
|
if (rtp_session->dtmf_data.out_digit_dur > 0) {
|
||||||
|
int x, ts, loops = 1, duration;
|
||||||
|
rtp_session->dtmf_data.out_digit_sofar += samples;
|
||||||
|
|
||||||
|
if (rtp_session->dtmf_data.out_digit_sofar >= rtp_session->dtmf_data.out_digit_dur) {
|
||||||
|
duration = rtp_session->dtmf_data.out_digit_dur;
|
||||||
|
rtp_session->dtmf_data.out_digit_packet[1] |= 0x80;
|
||||||
|
rtp_session->dtmf_data.out_digit_dur = 0;
|
||||||
|
loops = 3;
|
||||||
|
} else {
|
||||||
|
duration = rtp_session->dtmf_data.out_digit_sofar;
|
||||||
|
}
|
||||||
|
|
||||||
|
ts = rtp_session->dtmf_data.timestamp_dtmf += samples;
|
||||||
|
rtp_session->dtmf_data.out_digit_packet[2] = (unsigned char) (duration >> 8);
|
||||||
|
rtp_session->dtmf_data.out_digit_packet[3] = (unsigned char) duration;
|
||||||
|
|
||||||
|
|
||||||
|
for (x = 0; x < loops; x++) {
|
||||||
|
switch_rtp_write_manual(rtp_session,
|
||||||
|
rtp_session->dtmf_data.out_digit_packet, 4, 0, 101, ts,
|
||||||
|
loops == 1 ? rtp_session->dtmf_data.out_digit_seq++ : rtp_session->dtmf_data.out_digit_seq, &flags);
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Send %s packet for [%c] ts=%d sofar=%u dur=%d\n",
|
||||||
|
loops == 1 ? "middle" : "end",
|
||||||
|
rtp_session->dtmf_data.out_digit,
|
||||||
|
ts,
|
||||||
|
rtp_session->dtmf_data.out_digit_sofar,
|
||||||
|
duration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rtp_session->dtmf_data.out_digit_dur && rtp_session->dtmf_data.dtmf_queue && switch_queue_size(rtp_session->dtmf_data.dtmf_queue)) {
|
||||||
|
void *pop;
|
||||||
|
|
||||||
|
if (switch_queue_trypop(rtp_session->dtmf_data.dtmf_queue, &pop) == SWITCH_STATUS_SUCCESS) {
|
||||||
|
int x, ts;
|
||||||
|
struct rfc2833_digit *rdigit = pop;
|
||||||
|
|
||||||
|
memset(rtp_session->dtmf_data.out_digit_packet, 0, 4);
|
||||||
|
rtp_session->dtmf_data.out_digit_sofar = 0;
|
||||||
|
rtp_session->dtmf_data.out_digit_dur = rdigit->duration;
|
||||||
|
rtp_session->dtmf_data.out_digit = rdigit->digit;
|
||||||
|
rtp_session->dtmf_data.out_digit_packet[0] = (unsigned char)switch_char_to_rfc2833(rdigit->digit);
|
||||||
|
rtp_session->dtmf_data.out_digit_packet[1] = 7;
|
||||||
|
|
||||||
|
ts = rtp_session->dtmf_data.timestamp_dtmf += samples;
|
||||||
|
rtp_session->dtmf_data.out_digit_seq++;
|
||||||
|
for (x = 0; x < 3; x++) {
|
||||||
|
switch_rtp_write_manual(rtp_session,
|
||||||
|
rtp_session->dtmf_data.out_digit_packet,
|
||||||
|
4,
|
||||||
|
1,
|
||||||
|
101,
|
||||||
|
ts,
|
||||||
|
rtp_session->dtmf_data.out_digit_seq,
|
||||||
|
&flags);
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG,
|
||||||
|
SWITCH_LOG_DEBUG,
|
||||||
|
"Send start packet for [%c] ts=%d sofar=%u dur=%d\n",
|
||||||
|
rtp_session->dtmf_data.out_digit,
|
||||||
|
ts,
|
||||||
|
rtp_session->dtmf_data.out_digit_sofar,
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(rdigit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_type, switch_frame_flag_t *flags)
|
static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_type, switch_frame_flag_t *flags)
|
||||||
{
|
{
|
||||||
switch_size_t bytes;
|
switch_size_t bytes;
|
||||||
@ -562,6 +661,7 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
|
|||||||
rtp_session->next_read += rtp_session->ms_per_packet;
|
rtp_session->next_read += rtp_session->ms_per_packet;
|
||||||
}
|
}
|
||||||
*payload_type = SWITCH_RTP_CNG_PAYLOAD;
|
*payload_type = SWITCH_RTP_CNG_PAYLOAD;
|
||||||
|
do_2833(rtp_session);
|
||||||
return SWITCH_RTP_CNG_PAYLOAD;
|
return SWITCH_RTP_CNG_PAYLOAD;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -610,13 +710,138 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
|
|||||||
rtp_session->next_read += rtp_session->ms_per_packet;
|
rtp_session->next_read += rtp_session->ms_per_packet;
|
||||||
*payload_type = rtp_session->recv_msg.header.pt;
|
*payload_type = rtp_session->recv_msg.header.pt;
|
||||||
|
|
||||||
|
|
||||||
|
/* RFC2833 ... TBD try harder to honor the duration etc.*/
|
||||||
|
if (*payload_type == 101) {
|
||||||
|
unsigned char *packet = rtp_session->recv_msg.body;
|
||||||
|
int end = packet[1]&0x80;
|
||||||
|
int duration = (packet[2]<<8) + packet[3];
|
||||||
|
char key = switch_rfc2833_to_char(packet[0]);
|
||||||
|
|
||||||
|
/* SHEESH.... Curse you RFC2833 inventors!!!!*/
|
||||||
|
if ((time(NULL) - rtp_session->dtmf_data.last_digit_time) > 2) {
|
||||||
|
rtp_session->dtmf_data.last_digit = 0;
|
||||||
|
rtp_session->dtmf_data.dc = 0;
|
||||||
|
}
|
||||||
|
if (duration && end) {
|
||||||
|
if (key != rtp_session->dtmf_data.last_digit) {
|
||||||
|
char digit_str[] = {key, 0};
|
||||||
|
time(&rtp_session->dtmf_data.last_digit_time);
|
||||||
|
switch_rtp_queue_dtmf(rtp_session, digit_str);
|
||||||
|
}
|
||||||
|
if (++rtp_session->dtmf_data.dc >= 3) {
|
||||||
|
rtp_session->dtmf_data.last_digit = 0;
|
||||||
|
rtp_session->dtmf_data.dc = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
rtp_session->dtmf_data.last_digit = key;
|
||||||
|
} else {
|
||||||
|
rtp_session->dtmf_data.last_digit = 0;
|
||||||
|
rtp_session->dtmf_data.dc = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (*payload_type == SWITCH_RTP_CNG_PAYLOAD) {
|
if (*payload_type == SWITCH_RTP_CNG_PAYLOAD) {
|
||||||
*flags |= SFF_CNG;
|
*flags |= SFF_CNG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bytes > 0) {
|
||||||
|
do_2833(rtp_session);
|
||||||
|
}
|
||||||
return (int) bytes;
|
return (int) bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
SWITCH_DECLARE(switch_size_t) switch_rtp_has_dtmf(switch_rtp_t *rtp_session)
|
||||||
|
{
|
||||||
|
switch_size_t has;
|
||||||
|
|
||||||
|
assert(rtp_session != NULL);
|
||||||
|
switch_mutex_lock(rtp_session->dtmf_data.dtmf_mutex);
|
||||||
|
has = switch_buffer_inuse(rtp_session->dtmf_data.dtmf_buffer);
|
||||||
|
switch_mutex_unlock(rtp_session->dtmf_data.dtmf_mutex);
|
||||||
|
|
||||||
|
return has;
|
||||||
|
}
|
||||||
|
|
||||||
|
SWITCH_DECLARE(switch_status_t) switch_rtp_queue_dtmf(switch_rtp_t *rtp_session, char *dtmf)
|
||||||
|
{
|
||||||
|
switch_status_t status;
|
||||||
|
register switch_size_t len, inuse;
|
||||||
|
switch_size_t wr = 0;
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
assert(rtp_session != NULL);
|
||||||
|
|
||||||
|
switch_mutex_lock(rtp_session->dtmf_data.dtmf_mutex);
|
||||||
|
|
||||||
|
inuse = switch_buffer_inuse(rtp_session->dtmf_data.dtmf_buffer);
|
||||||
|
len = strlen(dtmf);
|
||||||
|
|
||||||
|
if (len + inuse > switch_buffer_len(rtp_session->dtmf_data.dtmf_buffer)) {
|
||||||
|
switch_buffer_toss(rtp_session->dtmf_data.dtmf_buffer, strlen(dtmf));
|
||||||
|
}
|
||||||
|
|
||||||
|
p = dtmf;
|
||||||
|
while(wr < len && p) {
|
||||||
|
if (is_dtmf(*p)) {
|
||||||
|
wr++;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
status = switch_buffer_write(rtp_session->dtmf_data.dtmf_buffer, dtmf, wr) ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_MEMERR;
|
||||||
|
switch_mutex_unlock(rtp_session->dtmf_data.dtmf_mutex);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SWITCH_DECLARE(switch_size_t) switch_rtp_dequeue_dtmf(switch_rtp_t *rtp_session, char *dtmf, switch_size_t len)
|
||||||
|
{
|
||||||
|
switch_size_t bytes;
|
||||||
|
|
||||||
|
assert(rtp_session != NULL);
|
||||||
|
|
||||||
|
switch_mutex_lock(rtp_session->dtmf_data.dtmf_mutex);
|
||||||
|
if ((bytes = switch_buffer_read(rtp_session->dtmf_data.dtmf_buffer, dtmf, len)) > 0) {
|
||||||
|
*(dtmf + bytes) = '\0';
|
||||||
|
}
|
||||||
|
switch_mutex_unlock(rtp_session->dtmf_data.dtmf_mutex);
|
||||||
|
|
||||||
|
return bytes;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SWITCH_DECLARE(switch_status_t) switch_rtp_queue_rfc2833(switch_rtp_t *rtp_session, char *digits, uint32_t duration)
|
||||||
|
{
|
||||||
|
char *c;
|
||||||
|
|
||||||
|
if (!rtp_session->dtmf_data.dtmf_queue) {
|
||||||
|
switch_queue_create(&rtp_session->dtmf_data.dtmf_queue, 100, rtp_session->pool);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(c = digits; *c; c++) {
|
||||||
|
struct rfc2833_digit *rdigit;
|
||||||
|
|
||||||
|
if ((rdigit = malloc(sizeof(*rdigit))) != 0) {
|
||||||
|
memset(rdigit, 0, sizeof(*rdigit));
|
||||||
|
rdigit->digit = *c;
|
||||||
|
rdigit->duration = duration;
|
||||||
|
switch_queue_push(rtp_session->dtmf_data.dtmf_queue, rdigit);
|
||||||
|
} else {
|
||||||
|
return SWITCH_STATUS_MEMERR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SWITCH_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
SWITCH_DECLARE(switch_status_t) switch_rtp_read(switch_rtp_t *rtp_session, void *data, uint32_t *datalen, switch_payload_t *payload_type, switch_frame_flag_t *flags)
|
SWITCH_DECLARE(switch_status_t) switch_rtp_read(switch_rtp_t *rtp_session, void *data, uint32_t *datalen, switch_payload_t *payload_type, switch_frame_flag_t *flags)
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -664,7 +889,11 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_zerocopy_read_frame(switch_rtp_t *rtp
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SWITCH_DECLARE(switch_status_t) switch_rtp_zerocopy_read(switch_rtp_t *rtp_session, void **data, uint32_t *datalen, switch_payload_t *payload_type, switch_frame_flag_t *flags)
|
SWITCH_DECLARE(switch_status_t) switch_rtp_zerocopy_read(switch_rtp_t *rtp_session,
|
||||||
|
void **data,
|
||||||
|
uint32_t *datalen,
|
||||||
|
switch_payload_t *payload_type,
|
||||||
|
switch_frame_flag_t *flags)
|
||||||
{
|
{
|
||||||
|
|
||||||
int bytes = rtp_common_read(rtp_session, payload_type, flags);
|
int bytes = rtp_common_read(rtp_session, payload_type, flags);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user