password => mypass
dialplan => demo
message => Jingle all the way
- generate_silence => yes
ip => 0.0.0.0
; or ;
;ip => my_lan_ip
switch_size_t samples;
/*! the rate of the frame */
int rate;
- /*! the timestamp of the frame */
- int32_t timestamp;
+ /*! frame flags */
+ switch_frame_flag flags;
};
#ifdef __cplusplus
#endif
#endif
+#define SWITCH_RTP_MAX_BUF_LEN 16384
///\defgroup rtp RTP (RealTime Transport Protocol)
///\ingroup core1
\param data the data to read
\param datalen the length of the data
\param payload_type the IANA payload of the packet
+ \param flags flags
\return the number of bytes read
*/
-SWITCH_DECLARE(int) switch_rtp_read(switch_rtp *rtp_session, void *data, uint32_t datalen, int *payload_type);
+SWITCH_DECLARE(int) switch_rtp_read(switch_rtp *rtp_session, void *data, uint32_t datalen, int *payload_type, switch_frame_flag *flags);
/*!
\brief Read data from a given RTP session without copying
\param payload_type the IANA payload of the packet
\return the number of bytes read
*/
-SWITCH_DECLARE(int) switch_rtp_zerocopy_read(switch_rtp *rtp_session, void **data, int *payload_type);
+SWITCH_DECLARE(int) switch_rtp_zerocopy_read(switch_rtp *rtp_session, void **data, int *payload_type, switch_frame_flag *flags);
/*!
\brief Write data to a given RTP session
\param data data to write
\param datalen the size of the data
\param ts then number of bytes to increment the timestamp by
+ \param flags flags
\return the number of bytes written
*/
SWITCH_DECLARE(int) switch_rtp_write(switch_rtp *rtp_session, void *data, int datalen, uint32_t ts);
\brief Channel Flags
<pre>
-CF_SEND_AUDIO = (1 << 0) - Channel will send audio
-CF_RECV_AUDIO = (1 << 1) - Channel will receive audio
-CF_ANSWERED = (1 << 2) - Channel is answered
-CF_OUTBOUND = (1 << 3) - Channel is an outbound channel
-CF_EARLY_MEDIA = (1 << 4) - Channel is ready for audio before answer
-CF_ORIGINATOR = (1 << 5) - Channel is an originator
-CF_TRANSFER = (1 << 6) - Channel is being transfered
+CF_ANSWERED = (1 << 0) - Channel is answered
+CF_OUTBOUND = (1 << 1) - Channel is an outbound channel
+CF_EARLY_MEDIA = (1 << 2) - Channel is ready for audio before answer
+CF_ORIGINATOR = (1 << 3) - Channel is an originator
+CF_TRANSFER = (1 << 4) - Channel is being transfered
+CF_ACCEPT_CNG = (1 << 5) - Channel will accept CNG frames
</pre>
*/
typedef enum {
- CF_SEND_AUDIO = (1 << 0),
- CF_RECV_AUDIO = (1 << 1),
- CF_ANSWERED = (1 << 2),
- CF_OUTBOUND = (1 << 3),
- CF_EARLY_MEDIA = (1 << 4),
- CF_ORIGINATOR = (1 << 5),
- CF_TRANSFER = (1 << 6)
+ CF_ANSWERED = (1 << 0),
+ CF_OUTBOUND = (1 << 1),
+ CF_EARLY_MEDIA = (1 << 2),
+ CF_ORIGINATOR = (1 << 3),
+ CF_TRANSFER = (1 << 4),
+ CF_ACCEPT_CNG = (1 << 5)
} switch_channel_flag;
+/*!
+ \enum switch_frame_flag
+ \brief Frame Flags
+
+<pre>
+CF_CNG = (1 << 0) - Frame represents comfort noise
+</pre>
+ */
+typedef enum {
+ SFF_CNG = (1 << 0)
+} switch_frame_flag;
+
+
/*!
\enum switch_signal
\brief Signals to send to channels
TFLAG_VOICE = (1 << 6),
TFLAG_RTP_READY = (1 << 7),
TFLAG_CODEC_READY = (1 << 8),
- TFLAG_SILENCE = (1 << 9)
} TFLAGS;
-typedef enum {
- PFLAG_GENSILENCE = (1 << 0)
-} PFLAGS;
-
typedef enum {
GFLAG_MY_CODEC_PREFS = (1 << 0)
} GFLAGS;
switch_codec read_codec;
switch_codec write_codec;
struct switch_frame read_frame;
- struct switch_frame cng_frame;
struct mdl_profile *profile;
- unsigned char read_buf[SWITCH_RECCOMMENDED_BUFFER_SIZE];
- unsigned char cng_buf[SWITCH_RECCOMMENDED_BUFFER_SIZE];
switch_core_session *session;
switch_caller_profile *caller_profile;
unsigned short samprate;
int32_t timestamp_dtmf;
char *codec_name;
int codec_num;
- switch_time_t cng_next;
};
struct rfc2833_digit {
}
- tech_pvt->read_frame.data = tech_pvt->read_buf;
- tech_pvt->read_frame.buflen = sizeof(tech_pvt->read_buf);
-
- tech_pvt->cng_frame.data = tech_pvt->cng_buf;
- tech_pvt->cng_frame.buflen = sizeof(tech_pvt->cng_buf);
-
if (switch_core_codec_init(&tech_pvt->read_codec,
tech_pvt->codec_name,
8000,
}
tech_pvt->read_frame.rate = tech_pvt->read_codec.implementation->samples_per_second;
tech_pvt->read_frame.codec = &tech_pvt->read_codec;
- tech_pvt->cng_frame.rate = tech_pvt->read_codec.implementation->samples_per_second;
- tech_pvt->cng_frame.codec = &tech_pvt->read_codec;
- memset(tech_pvt->cng_buf,255, sizeof(tech_pvt->cng_buf));
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Set Read Codec to %s\n", tech_pvt->codec_name);
switch_core_session_set_read_codec(session, &tech_pvt->read_codec);
switch_core_session_set_write_codec(session, &tech_pvt->write_codec);
- //switch_set_flag(tech_pvt, TFLAG_SILENCE);
//printf("WAIT %s %d\n", switch_channel_get_name(channel), switch_test_flag(tech_pvt, TFLAG_OUTBOUND));
channel = switch_core_session_get_channel(session);
assert(channel != NULL);
+ tech_pvt->read_frame.buflen = SWITCH_RTP_MAX_BUF_LEN;
+
/* Move Channel's State Machine to RING */
switch_channel_set_state(channel, CS_RING);
size_t bytes = 0, samples = 0, frames = 0, ms = 0;
switch_channel *channel = NULL;
int payload = 0;
- switch_time_t now;
channel = switch_core_session_get_channel(session);
assert(channel != NULL);
assert(tech_pvt->rtp_session != NULL);
tech_pvt->read_frame.datalen = 0;
+
while (!switch_test_flag(tech_pvt, TFLAG_BYE) && switch_test_flag(tech_pvt, TFLAG_IO) && tech_pvt->read_frame.datalen == 0) {
payload = -1;
- tech_pvt->read_frame.datalen = switch_rtp_read(tech_pvt->rtp_session, tech_pvt->read_frame.data, sizeof(tech_pvt->read_buf), &payload);
- if (switch_test_flag(tech_pvt, TFLAG_SILENCE)) {
- if (tech_pvt->read_frame.datalen) {
- switch_clear_flag(tech_pvt, TFLAG_SILENCE);
- } else {
- now = switch_time_now();
- if (now >= tech_pvt->cng_next) {
- tech_pvt->cng_next += ms;
- if (!tech_pvt->cng_frame.datalen) {
- tech_pvt->cng_frame.datalen = bytes;
- }
- memset(tech_pvt->cng_frame.data, 255, tech_pvt->cng_frame.datalen);
- //printf("GENERATE X bytes=%d payload=%d frames=%d samples=%d ms=%d ts=%d sampcount=%d\n", tech_pvt->cng_frame.datalen, payload, frames, samples, ms, tech_pvt->timestamp_recv, tech_pvt->read_frame.samples);
- *frame = &tech_pvt->cng_frame;
- return SWITCH_STATUS_SUCCESS;
- }
- switch_yield(1000);
- continue;
- }
- }
+ tech_pvt->read_frame.flags = 0;
+ tech_pvt->read_frame.datalen = switch_rtp_zerocopy_read(tech_pvt->rtp_session, &tech_pvt->read_frame.data, &payload, &tech_pvt->read_frame.flags);
+
/* RFC2833 ... TBD try harder to honor the duration etc.*/
if (payload == 101) {
}
- if (switch_test_flag(tech_pvt->profile, PFLAG_GENSILENCE)) {
- if ((switch_test_flag(tech_pvt, TFLAG_SILENCE) || payload == 13) && tech_pvt->cng_frame.datalen) {
- memset(tech_pvt->cng_frame.data, 255, tech_pvt->cng_frame.datalen);
- *frame = &tech_pvt->cng_frame;
- //printf("GENERATE bytes=%d payload=%d frames=%d samples=%d ms=%d ts=%d sampcount=%d\n", tech_pvt->cng_frame.datalen, payload, frames, samples, ms, tech_pvt->timestamp_recv, tech_pvt->read_frame.samples);
- switch_set_flag(tech_pvt, TFLAG_SILENCE);
- tech_pvt->cng_next = switch_time_now() + ms;
- return SWITCH_STATUS_SUCCESS;
- }
- }
-
-
- if (payload != tech_pvt->codec_num) {
- switch_yield(1000);
- continue;
- }
-
if (tech_pvt->read_frame.datalen > 0) {
bytes = tech_pvt->read_codec.implementation->encoded_bytes_per_frame;
frames = (tech_pvt->read_frame.datalen / bytes);
ms = frames * tech_pvt->read_codec.implementation->microseconds_per_frame;
tech_pvt->timestamp_recv += (int32_t) samples;
tech_pvt->read_frame.samples = (int) samples;
- if (switch_test_flag(tech_pvt->profile, PFLAG_GENSILENCE)) {
- //memcpy(tech_pvt->cng_buf, tech_pvt->read_buf, tech_pvt->read_frame.datalen);
- tech_pvt->cng_frame.datalen = tech_pvt->read_frame.datalen;
- tech_pvt->cng_frame.samples = tech_pvt->read_frame.samples;
- switch_clear_flag(tech_pvt, TFLAG_SILENCE);
- }
- //printf("READ bytes=%d payload=%d frames=%d samples=%d ms=%d ts=%d sampcount=%d\n", tech_pvt->read_frame.datalen, payload, frames, samples, ms, tech_pvt->timestamp_recv, tech_pvt->read_frame.samples);
+ //printf("READ bytes=%d payload=%d frames=%d samples=%d ms=%d ts=%d sampcount=%d\n", (int)tech_pvt->read_frame.datalen, (int)payload, (int)frames, (int)samples, (int)ms, (int)tech_pvt->timestamp_recv, (int)tech_pvt->read_frame.samples);
break;
}
profile->name = switch_core_strdup(module_pool, val);
} else if (!strcmp(var, "message")) {
profile->message = switch_core_strdup(module_pool, val);
- } else if (!strcmp(var, "generate_silence")) {
- if (switch_true(val)) {
- switch_set_flag(profile, PFLAG_GENSILENCE);
- }
} else if (!strcmp(var, "ip")) {
profile->ip = switch_core_strdup(module_pool, val);
} else if (!strcmp(var, "extip")) {
tech_pvt->remote_ip,
tech_pvt->remote_port,
tech_pvt->codec_num,
- switch_test_flag(tech_pvt->profile, PFLAG_GENSILENCE) ? SWITCH_RTP_NOBLOCK : 0,
+ 0,
&err, switch_core_session_get_pool(tech_pvt->session)))) {
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "RTP ERROR %s\n", err);
switch_channel_hangup(channel);
TFLAG_RTP = (1 << 7),
TFLAG_BYE = (1 << 8),
TFLAG_ANS = (1 << 9),
- TFLAG_EARLY_MEDIA = (1 << 10),
- TFLAG_SILENCE = (1 << 11)
+ TFLAG_EARLY_MEDIA = (1 << 10)
} TFLAGS;
unsigned int flags;
switch_core_session *session;
switch_frame read_frame;
- switch_frame cng_frame;
switch_codec read_codec;
switch_codec write_codec;
- unsigned char cng_buf[320];
switch_caller_profile *caller_profile;
int cid;
int did;
switch_mutex_t *rtp_lock;
switch_queue_t *dtmf_queue;
char out_digit;
- switch_time_t cng_next;
switch_time_t last_read;
unsigned char out_digit_packet[4];
unsigned int out_digit_sofar;
tech_pvt = switch_core_session_get_private(session);
assert(tech_pvt != NULL);
- tech_pvt->read_frame.data = tech_pvt->cng_buf;
- tech_pvt->read_frame.buflen = sizeof(tech_pvt->cng_buf);
-
- tech_pvt->cng_frame.data = tech_pvt->cng_buf;
- tech_pvt->cng_frame.buflen = sizeof(tech_pvt->cng_buf);
+ tech_pvt->read_frame.buflen = SWITCH_RTP_MAX_BUF_LEN;
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "EXOSIP INIT\n");
while (!switch_test_flag(tech_pvt, TFLAG_BYE) && switch_test_flag(tech_pvt, TFLAG_IO)
&& tech_pvt->read_frame.datalen == 0) {
now = switch_time_now();
- tech_pvt->read_frame.datalen = switch_rtp_zerocopy_read(tech_pvt->rtp_session, &tech_pvt->read_frame.data, &payload);
-
- if (switch_test_flag(tech_pvt, TFLAG_SILENCE)) {
- if (tech_pvt->read_frame.datalen) {
- switch_clear_flag(tech_pvt, TFLAG_SILENCE);
- } else {
- now = switch_time_now();
- if (now >= tech_pvt->cng_next) {
- tech_pvt->cng_next += ms;
- if (!tech_pvt->cng_frame.datalen) {
- tech_pvt->cng_frame.datalen = bytes;
- }
- memset(tech_pvt->cng_frame.data, 255, tech_pvt->cng_frame.datalen);
- //printf("GENERATE X bytes=%d payload=%d frames=%d samples=%d ms=%d ts=%d sampcount=%d\n", tech_pvt->cng_frame.datalen, payload, frames, samples, ms, tech_pvt->timestamp_recv, tech_pvt->read_frame.samples);
- *frame = &tech_pvt->cng_frame;
- return SWITCH_STATUS_SUCCESS;
- }
- switch_yield(1000);
- continue;
- }
- }
+ tech_pvt->read_frame.flags = 0;
+ tech_pvt->read_frame.datalen = switch_rtp_zerocopy_read(tech_pvt->rtp_session, &tech_pvt->read_frame.data, &payload, &tech_pvt->read_frame.flags);
if (timeout > -1) {
}
- if (switch_test_flag(&globals, TFLAG_SILENCE)) {
- if ((switch_test_flag(tech_pvt, TFLAG_SILENCE) || payload == 13) && tech_pvt->cng_frame.datalen) {
- *frame = &tech_pvt->cng_frame;
- //printf("GENERATE bytes=%d payload=%d frames=%d samples=%d ms=%d ts=%d sampcount=%d\n", tech_pvt->cng_frame.datalen, payload, frames, samples, ms, tech_pvt->timestamp_recv, tech_pvt->read_frame.samples);
- switch_set_flag(tech_pvt, TFLAG_SILENCE);
- tech_pvt->cng_next = switch_time_now() + ms;
- return SWITCH_STATUS_SUCCESS;
- }
- }
-
-
- if (payload != tech_pvt->payload_num) {
- tech_pvt->read_frame.datalen = 0;
- switch_yield(1000);
- continue;
- }
-
if (tech_pvt->read_frame.datalen > 0) {
tech_pvt->last_read = switch_time_now();
bytes = tech_pvt->read_codec.implementation->encoded_bytes_per_frame;
ms = frames * tech_pvt->read_codec.implementation->microseconds_per_frame;
tech_pvt->timestamp_recv += (int32_t) samples;
tech_pvt->read_frame.samples = (int) samples;
- if (switch_test_flag(&globals, TFLAG_SILENCE)) {
- tech_pvt->cng_frame.datalen = tech_pvt->read_frame.datalen;
- tech_pvt->cng_frame.samples = tech_pvt->read_frame.samples;
- switch_clear_flag(tech_pvt, TFLAG_SILENCE);
- }
break;
}
switch_yield(1000);
}
- } else {
- memset(tech_pvt->cng_buf, 0, 160);
- tech_pvt->read_frame.data = tech_pvt->cng_buf;
- tech_pvt->read_frame.datalen = 160;
}
switch_clear_flag(tech_pvt, TFLAG_READING);
ms = tech_pvt->write_codec.implementation->microseconds_per_frame / 1000;
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Activate Inbound Codec %s/%d %d ms\n", dname, rate, ms);
tech_pvt->read_frame.codec = &tech_pvt->read_codec;
- tech_pvt->cng_frame.rate = tech_pvt->read_codec.implementation->samples_per_second;
- tech_pvt->cng_frame.codec = &tech_pvt->read_codec;
- memset(tech_pvt->cng_buf,255, sizeof(tech_pvt->cng_buf));
switch_core_session_set_read_codec(session, &tech_pvt->read_codec);
switch_core_session_set_write_codec(session, &tech_pvt->write_codec);
}
ms = tech_pvt->write_codec.implementation->microseconds_per_frame / 1000;
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Activate Outbound Codec %s/%d %d ms\n", dname, rate, ms);
tech_pvt->read_frame.codec = &tech_pvt->read_codec;
- tech_pvt->cng_frame.rate = tech_pvt->read_codec.implementation->samples_per_second;
- tech_pvt->cng_frame.codec = &tech_pvt->read_codec;
- memset(tech_pvt->cng_buf,255, sizeof(tech_pvt->cng_buf));
switch_core_session_set_read_codec(tech_pvt->session, &tech_pvt->read_codec);
switch_core_session_set_write_codec(tech_pvt->session, &tech_pvt->write_codec);
}
globals.port = atoi(val);
} else if (!strcmp(var, "host")) {
set_global_host(val);
- } else if (!strcmp(var, "cng")) {
- if (switch_true(val)) {
- switch_set_flag(&globals, TFLAG_SILENCE);
- }
} else if (!strcmp(var, "dialplan")) {
set_global_dialplan(val);
} else if (!strcmp(var, "codec_prefs")) {
switch_swap_linear(frame->data, (int) frame->datalen / 2);
}
#endif
+ //printf("Send %ld %d\n", time(NULL), (int) frame->datalen);
iax_send_voice(tech_pvt->iax_session, tech_pvt->codec, frame->data, (int) frame->datalen,
tech_pvt->write_codec.implementation->samples_per_frame);
assert(session != NULL);
assert(*frame != NULL);
- /* if you think this code is redundant.... too bad! I like to understand what I'm doing */
- if ((session->read_codec && (*frame)->codec
- && session->read_codec->implementation != (*frame)->codec->implementation)) {
+ if (switch_test_flag(*frame, SFF_CNG)) {
+ return SWITCH_STATUS_SUCCESS;
+ }
+
+ if ((session->read_codec && (*frame)->codec && session->read_codec->implementation != (*frame)->codec->implementation)) {
need_codec = TRUE;
}
return status;
}
-static switch_status perform_write(switch_core_session *session, switch_frame *frame, int timeout, switch_io_flag flags,
- int stream_id)
+static switch_status perform_write(switch_core_session *session, switch_frame *frame, int timeout, switch_io_flag flags, int stream_id)
{
struct switch_io_event_hook_write_frame *ptr;
switch_status status = SWITCH_STATUS_FALSE;
assert(frame != NULL);
assert(frame->codec != NULL);
- /* if you think this code is redundant.... too bad! I like to understand what I'm doing */
+ if (switch_test_flag(frame, SFF_CNG)) {
+
+ if (switch_channel_test_flag(session->channel, CF_ACCEPT_CNG)) {
+ return perform_write(session, frame, timeout, flag, stream_id);
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+ }
+
+
if ((session->write_codec && frame->codec && session->write_codec->implementation != frame->codec->implementation)) {
need_codec = TRUE;
}
return NULL;
}
- switch_channel_init(session->channel, session, CS_NEW, (CF_SEND_AUDIO | CF_RECV_AUDIO));
+ switch_channel_init(session->channel, session, CS_NEW, 0);
/* The session *IS* the pool you may not alter it because you have no idea how
its all private it will be passed to the thread run function */
#define MAX_KEY_LEN 64
#define rtp_header_len 12
-#define RTP_MAX_BUF_LEN 16384
#define RTP_START_PORT 16384
#define RTP_END_PORT 32768
+#define SWITCH_RTP_CNG_PAYLOAD 13
static switch_port_t NEXT_PORT = RTP_START_PORT;
static switch_mutex_t *port_lock = NULL;
typedef srtp_hdr_t rtp_hdr_t;
typedef struct {
- srtp_hdr_t header;
- char body[RTP_MAX_BUF_LEN];
+ srtp_hdr_t header;
+ char body[SWITCH_RTP_MAX_BUF_LEN];
} rtp_msg_t;
struct switch_rtp {
static int global_init = 0;
+
+
+
static switch_status ice_out(switch_rtp *rtp_session)
{
rtp_session->invalid_handler = on_invalid;
}
-SWITCH_DECLARE(int) switch_rtp_read(switch_rtp *rtp_session, void *data, uint32_t datalen, int *payload_type)
+SWITCH_DECLARE(int) switch_rtp_read(switch_rtp *rtp_session, void *data, uint32_t datalen, int *payload_type, switch_frame_flag *flags)
{
switch_size_t bytes;
}
memcpy(data, rtp_session->recv_msg.body, bytes);
*payload_type = rtp_session->recv_msg.header.pt;
+
+ if (*payload_type == SWITCH_RTP_CNG_PAYLOAD) {
+ *flags |= SFF_CNG;
+ }
+
return (int)(bytes - rtp_header_len);
+
}
-SWITCH_DECLARE(int) switch_rtp_zerocopy_read(switch_rtp *rtp_session, void **data, int *payload_type)
+SWITCH_DECLARE(int) switch_rtp_zerocopy_read(switch_rtp *rtp_session, void **data, int *payload_type, switch_frame_flag *flags)
{
switch_size_t bytes;
*payload_type = rtp_session->recv_msg.header.pt;
*data = rtp_session->recv_msg.body;
+ if (*payload_type == SWITCH_RTP_CNG_PAYLOAD) {
+ *flags |= SFF_CNG;
+ }
+
return (int)(bytes - rtp_header_len);
}
rtp_session->payload = htonl(rtp_session->payload);
memcpy(rtp_session->send_msg.body, data, datalen);
-
+
bytes = datalen + rtp_header_len;
switch_socket_sendto(rtp_session->sock, rtp_session->remote_addr, 0, (void*)&rtp_session->send_msg, &bytes);
if (rtp_session->ice_user) {
rtp_session->send_msg.header.pt = (uint8_t)htonl(payload);
memcpy(rtp_session->send_msg.body, data, datalen);
+
bytes = datalen + rtp_header_len;
switch_socket_sendto(rtp_session->sock, rtp_session->remote_addr, 0, (void*)&rtp_session->send_msg, &bytes);