add management interface and some rtp goodies

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@4464 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
Anthony Minessale 2007-03-07 18:34:22 +00:00
parent 30a9513b5a
commit 5131ee1cae
12 changed files with 242 additions and 24 deletions

View File

@ -47,6 +47,10 @@
#include <switch_am_config.h>
#endif
#define FREESWITCH_PEN "27880"
#define FREESWITCH_MIB ".1.3.6.1.4.1." FREESWITCH_PEN
#define FREESWITCH_ITAD "543"
#include <switch_platform.h>
#include <assert.h>
#include <setjmp.h>

View File

@ -1405,6 +1405,19 @@ SWITCH_DECLARE(switch_status_t) switch_core_directory_close(switch_directory_han
*/
SWITCH_DECLARE(FILE *) switch_core_data_channel(switch_text_channel_t channel);
/*!
\brief Execute a management operation.
\param relative_oid the relative oid of the operation.
\param action the action to perform.
\param data input/output string.
\param datalen size in bytes of data.
\return SUCCESS on sucess.
*/
SWITCH_DECLARE(switch_status_t) switch_core_management_exec(char *relative_oid,
switch_management_action_t action,
char *data,
switch_size_t datalen);
/*!
\brief Set the maximum priority the process can obtain

View File

@ -76,9 +76,11 @@ struct switch_loadable_module_interface {
/*! the table of chat interfaces the module has implmented */
const switch_chat_interface_t *chat_interface;
/*! the table of say interfaces the module has implmented */
const switch_say_interface_t *say_interface;
const switch_say_interface_t *say_interface;
/*! the table of asr interfaces the module has implmented */
const switch_asr_interface_t *asr_interface;
/*! the table of management interfaces the module has implmented */
const switch_management_interface_t *management_interface;
};
/*!
@ -190,6 +192,12 @@ SWITCH_DECLARE(switch_chat_interface_t *) switch_loadable_module_get_chat_interf
*/
SWITCH_DECLARE(switch_say_interface_t *) switch_loadable_module_get_say_interface(char *name);
/*!
\brief Retrieve the management interface by it's registered name
\param relative_oid the relative oid of the management interface
\return the desired management interface
*/
SWITCH_DECLARE(switch_management_interface_t *) switch_loadable_module_get_management_interface(char *relative_oid);
/*!
\brief Retrieve the list of loaded codecs into an array

View File

@ -430,6 +430,15 @@ struct switch_chat_interface {
const struct switch_chat_interface *next;
};
/*! \brief Abstract interface to a management module */
struct switch_management_interface {
/*! the name of the interface */
const char *relative_oid;
/*! function to open the directory interface */
switch_status_t (*management_function)(char *relative_oid, switch_management_action_t action, char *data, switch_size_t datalen);
const struct switch_management_interface *next;
};
/*! \brief Abstract interface to a directory module */
struct switch_directory_interface {
/*! the name of the interface */

View File

@ -375,6 +375,13 @@ SWITCH_DECLARE(void) switch_rtp_set_private(switch_rtp_t *rtp_session, void *pri
*/
SWITCH_DECLARE(void) switch_rtp_set_telephony_event(switch_rtp_t *rtp_session, switch_payload_t te);
/*!
\brief Set the payload type for comfort noise
\param rtp_session the RTP session to modify
\param pt the payload type
*/
SWITCH_DECLARE(void) switch_rtp_set_cng_pt(switch_rtp_t *rtp_session, switch_payload_t pt);
/*!
\brief Retrieve the private data from a given RTP session
\param rtp_session the RTP session to retrieve the data from

View File

@ -187,6 +187,11 @@ typedef enum {
SST_NAME_PHONETIC,
} switch_say_type_t;
typedef enum {
SMA_NONE,
SMA_GET,
SMA_SET
} switch_management_action_t;
typedef enum {
SMF_NONE = 0,
@ -248,6 +253,7 @@ SWITCH_DECLARE_DATA extern switch_directories SWITCH_GLOBAL_dirs;
#define SWITCH_TRUE 1
#define SWITCH_FALSE 0
#define SWITCH_CORE_QUEUE_LEN 100000
#define SWITCH_MAX_MANAGEMENT_BUFFER_LEN 1024 * 8
typedef enum {
SWITCH_CPF_SCREEN = (1 << 0),
@ -289,6 +295,7 @@ typedef enum {
SWITCH_VAD_FLAG_CNG = ( 1 << 3)
} switch_vad_flag_t;
#define SWITCH_RTP_CNG_PAYLOAD 13
/*!
\enum switch_rtp_flag_t
@ -307,7 +314,8 @@ typedef enum {
SWITCH_RTP_FLAG_MINI - Use mini RTP when possible
SWITCH_RTP_FLAG_DATAWAIT - Do not return from reads unless there is data even when non blocking
SWITCH_RTP_FLAG_BUGGY_2833 - Emulate the bug in cisco equipment to allow interop
SWITCH_RTP_FLAG_PASS_RFC2833 - Pass 2833 (ignore it)
SWITCH_RTP_FLAG_PASS_RFC2833 - Pass 2833 (ignore it)
SWITCH_RTP_FLAG_AUTO_CNG - Generate outbound CNG frames when idle
</pre>
*/
typedef enum {
@ -324,7 +332,8 @@ typedef enum {
SWITCH_RTP_FLAG_MINI = ( 1 << 10),
SWITCH_RTP_FLAG_DATAWAIT = (1 << 11),
SWITCH_RTP_FLAG_BUGGY_2833 = (1 << 12),
SWITCH_RTP_FLAG_PASS_RFC2833 = (1 << 13)
SWITCH_RTP_FLAG_PASS_RFC2833 = (1 << 13),
SWITCH_RTP_FLAG_AUTO_CNG = (1 << 14)
} switch_rtp_flag_t;
/*!
@ -985,6 +994,7 @@ typedef struct switch_speech_interface switch_speech_interface_t;
typedef struct switch_asr_interface switch_asr_interface_t;
typedef struct switch_directory_interface switch_directory_interface_t;
typedef struct switch_chat_interface switch_chat_interface_t;
typedef struct switch_management_interface switch_management_interface_t;
typedef struct switch_core_port_allocator switch_core_port_allocator_t;
typedef struct switch_media_bug switch_media_bug_t;
typedef void (*switch_media_bug_callback_t)(switch_media_bug_t *, void *, switch_abc_type_t);

View File

@ -753,6 +753,8 @@ static int activate_rtp(struct private_object *tech_pvt)
flags |= SWITCH_RTP_FLAG_USE_TIMER;
}
flags |= SWITCH_RTP_FLAG_AUTO_CNG;
if (!(tech_pvt->rtp_session = switch_rtp_new(tech_pvt->profile->ip,
tech_pvt->local_port,
tech_pvt->remote_ip,
@ -1357,7 +1359,7 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc
samples = frames * tech_pvt->read_codec.implementation->samples_per_frame;
tech_pvt->timestamp_send += samples;
if (switch_rtp_write_frame(tech_pvt->rtp_session, frame, tech_pvt->timestamp_send) < 0) {
if (switch_rtp_write_frame(tech_pvt->rtp_session, frame, 0) < 0) {
terminate_session(&session, __LINE__, SWITCH_CAUSE_NORMAL_CLEARING);
return SWITCH_STATUS_FALSE;
}

View File

@ -252,6 +252,7 @@ struct sofia_profile {
su_root_t *s_root;
sip_alias_node_t *aliases;
switch_payload_t te;
switch_payload_t cng_pt;
uint32_t codec_flags;
switch_mutex_t *ireg_mutex;
switch_mutex_t *oreg_mutex;
@ -319,6 +320,8 @@ struct private_object {
switch_mutex_t *flag_mutex;
switch_payload_t te;
switch_payload_t bte;
switch_payload_t cng_pt;
switch_payload_t bcng_pt;
nua_handle_t *nh;
nua_handle_t *nh2;
su_home_t *home;
@ -747,6 +750,14 @@ static void set_local_sdp(private_object_t *tech_pvt, char *ip, uint32_t port, c
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %d", tech_pvt->te);
}
if (tech_pvt->read_codec.implementation->samples_per_second == 8000) {
tech_pvt->cng_pt = SWITCH_RTP_CNG_PAYLOAD;
}
if (tech_pvt->cng_pt) {
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %d", tech_pvt->cng_pt);
}
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "\n");
if (tech_pvt->rm_encoding) {
@ -776,6 +787,8 @@ static void set_local_sdp(private_object_t *tech_pvt, char *ip, uint32_t port, c
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=rtpmap:%d telephone-event/8000\na=fmtp:%d 0-16\n", tech_pvt->te, tech_pvt->te);
}
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=rtpmap:%d CN/%d\n", tech_pvt->cng_pt, tech_pvt->read_codec.implementation->samples_per_second);
if (ptime) {
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=ptime:%d\n", ptime);
}
@ -870,9 +883,16 @@ static void attach_private(switch_core_session_t *session,
} else {
tech_pvt->te = profile->te;
}
if (tech_pvt->bcng_pt) {
tech_pvt->cng_pt = tech_pvt->bcng_pt;
} else {
tech_pvt->cng_pt = profile->cng_pt;
}
tech_pvt->session = session;
tech_pvt->home = su_home_new(sizeof(*tech_pvt->home));
switch_core_session_set_private(session, tech_pvt);
@ -1543,6 +1563,10 @@ static switch_status_t activate_rtp(private_object_t *tech_pvt)
flags |= SWITCH_RTP_FLAG_PASS_RFC2833;
}
if (tech_pvt->cng_pt) {
flags |= SWITCH_RTP_FLAG_AUTO_CNG;
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "RTP [%s] %s:%d->%s:%d codec: %u ms: %d\n",
switch_channel_get_name(channel),
tech_pvt->local_sdp_audio_ip,
@ -1602,6 +1626,12 @@ static switch_status_t activate_rtp(private_object_t *tech_pvt)
switch_channel_get_name(switch_core_session_get_channel(tech_pvt->session)),
vad_in ? "in" : "", vad_out ? "out" : "");
}
switch_rtp_set_telephony_event(tech_pvt->rtp_session, tech_pvt->te);
if (tech_pvt->cng_pt) {
switch_rtp_set_cng_pt(tech_pvt->rtp_session, tech_pvt->cng_pt);
}
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "RTP REPORTS ERROR: [%s]\n", err);
terminate_session(&tech_pvt->session, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__);
@ -1881,7 +1911,8 @@ static switch_status_t sofia_write_frame(switch_core_session_t *session, switch_
#endif
tech_pvt->timestamp_send += samples;
switch_rtp_write_frame(tech_pvt->rtp_session, frame, tech_pvt->timestamp_send);
//switch_rtp_write_frame(tech_pvt->rtp_session, frame, tech_pvt->timestamp_send);
switch_rtp_write_frame(tech_pvt->rtp_session, frame, 0);
switch_clear_flag_locked(tech_pvt, TFLAG_WRITING);
return status;
@ -2347,6 +2378,7 @@ static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session
ctech_pvt = switch_core_session_get_private(session);
assert(ctech_pvt != NULL);
tech_pvt->bte = ctech_pvt->te;
tech_pvt->bcng_pt = ctech_pvt->cng_pt;
}
}
@ -5181,6 +5213,8 @@ static switch_status_t config_sofia(int reload)
switch_set_flag(profile, TFLAG_LATE_NEGOTIATION);
} else if (!strcasecmp(var, "rfc2833-pt")) {
profile->te = (switch_payload_t) atoi(val);
} else if (!strcasecmp(var, "cng-pt")) {
profile->cng_pt = (switch_payload_t) atoi(val);
} else if (!strcasecmp(var, "sip-port")) {
profile->sip_port = atoi(val);
} else if (!strcasecmp(var, "vad")) {
@ -5270,6 +5304,10 @@ static switch_status_t config_sofia(int reload)
}
}
if (!profile->cng_pt) {
profile->cng_pt = 127;
}
if (!profile->sipip) {
profile->sipip = switch_core_strdup(profile->pool, globals.guess_ip);
}

View File

@ -197,13 +197,13 @@ abyss_bool HandleHook(TSession *r)
return TRUE;
}
#define CMDLEN 1024 * 256
static xmlrpc_value *freeswitch_api(xmlrpc_env *const envP, xmlrpc_value *const paramArrayP, void *const userData)
{
char *command, *arg;
char *retbuf = malloc(CMDLEN);
switch_stream_handle_t stream = {0};
xmlrpc_value *val;
xmlrpc_value *val = NULL;
/* Parse our argument array. */
xmlrpc_decompose_value(envP, paramArrayP, "(ss)", &command, &arg);
@ -211,16 +211,67 @@ static xmlrpc_value *freeswitch_api(xmlrpc_env *const envP, xmlrpc_value *const
return NULL;
}
memset(retbuf, 0, CMDLEN);
stream.data = retbuf;
stream.end = stream.data;
stream.data_size = CMDLEN;
stream.write_function = switch_console_stream_write;
switch_api_execute(command, arg, NULL, &stream);
SWITCH_STANDARD_STREAM(stream);
if (switch_api_execute(command, arg, NULL, &stream) == SWITCH_STATUS_SUCCESS) {
/* Return our result. */
val = xmlrpc_build_value(envP, "s", stream.data);
free(stream.data);
} else {
val = xmlrpc_build_value(envP, "s", "ERROR!");
}
return val;
}
static xmlrpc_value *freeswitch_man(xmlrpc_env *const envP, xmlrpc_value *const paramArrayP, void *const userData)
{
char *oid, *relative_oid, *s_action, *data;
char buf[SWITCH_MAX_MANAGEMENT_BUFFER_LEN] = "";
switch_management_action_t action = SMA_NONE;
switch_stream_handle_t stream = {0};
xmlrpc_value *val;
/* Parse our argument array. */
xmlrpc_decompose_value(envP, paramArrayP, "(sss)", &oid, &s_action, &data);
if (envP->fault_occurred) {
return NULL;
}
if (!strncasecmp(oid, FREESWITCH_MIB, strlen(FREESWITCH_MIB))) {
relative_oid = oid + strlen(FREESWITCH_MIB);
} else {
relative_oid = oid;
}
if (!switch_strlen_zero(data)) {
switch_copy_string(buf, data, sizeof(buf));
}
if (!strcasecmp(s_action, "get")) {
action = SMA_GET;
} else if (!strcasecmp(s_action, "set")) {
action = SMA_SET;
}
if (action) {
if (switch_core_management_exec(relative_oid, action, buf, sizeof(buf)) == SWITCH_STATUS_SUCCESS) {
if (action == SMA_SET) {
if (switch_strlen_zero(buf)) {
snprintf(buf, sizeof(buf), "OK\n");
}
}
} else {
if (switch_strlen_zero(buf)) {
snprintf(buf, sizeof(buf), "ERROR\n");
}
}
} else {
snprintf(buf, sizeof(buf), "Invalid Action %s\n", s_action);
}
/* Return our result. */
val = xmlrpc_build_value(envP, "s", retbuf);
free(retbuf);
val = xmlrpc_build_value(envP, "s", buf);
return val;
}
@ -240,6 +291,8 @@ SWITCH_MOD_DECLARE(switch_status_t) switch_module_runtime(void)
xmlrpc_registry_add_method(&env, registryP, NULL, "freeswitch.api", &freeswitch_api, NULL);
xmlrpc_registry_add_method(&env, registryP, NULL,"freeswitch_api", &freeswitch_api, NULL);
xmlrpc_registry_add_method(&env, registryP, NULL, "freeswitch.management", &freeswitch_man, NULL);
xmlrpc_registry_add_method(&env, registryP, NULL,"freeswitch_management", &freeswitch_man, NULL);
MIMETypeInit();
MIMETypeAdd("text/html", "html");

View File

@ -447,6 +447,23 @@ SWITCH_DECLARE(switch_status_t) switch_core_port_allocator_new(switch_port_t sta
return SWITCH_STATUS_SUCCESS;
}
SWITCH_DECLARE(switch_status_t) switch_core_management_exec(char *relative_oid,
switch_management_action_t action,
char *data,
switch_size_t datalen)
{
const switch_management_interface_t *ptr;
switch_status_t status = SWITCH_STATUS_FALSE;
if ((ptr = switch_loadable_module_get_management_interface(relative_oid))) {
status = ptr->management_function(relative_oid, action, data, datalen);
}
return status;
}
SWITCH_DECLARE(switch_port_t) switch_core_port_allocator_request_port(switch_core_port_allocator_t *alloc)
{
switch_port_t port;

View File

@ -55,6 +55,7 @@ struct switch_loadable_module_container {
switch_hash_t *directory_hash;
switch_hash_t *chat_hash;
switch_hash_t *say_hash;
switch_hash_t *management_hash;
switch_memory_pool_t *pool;
};
@ -332,6 +333,24 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable
}
}
}
if (new_module->module_interface->management_interface) {
const switch_management_interface_t *ptr;
for (ptr = new_module->module_interface->management_interface; ptr; ptr = ptr->next) {
if (!ptr->relative_oid) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to load management interface from %s due to no interface name.\n", key);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Adding Management interface '%s'\n", ptr->relative_oid);
if (switch_event_create(&event, SWITCH_EVENT_MODULE_LOAD) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "type", "management");
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "name", "%s", ptr->relative_oid);
switch_event_fire(&event);
}
switch_core_hash_insert(loadable_modules.management_hash, ptr->relative_oid, (const void *) ptr);
}
}
}
return SWITCH_STATUS_SUCCESS;
@ -585,6 +604,7 @@ SWITCH_DECLARE(switch_status_t) switch_loadable_module_init()
switch_core_hash_init(&loadable_modules.directory_hash, loadable_modules.pool);
switch_core_hash_init(&loadable_modules.chat_hash, loadable_modules.pool);
switch_core_hash_init(&loadable_modules.say_hash, loadable_modules.pool);
switch_core_hash_init(&loadable_modules.management_hash, loadable_modules.pool);
switch_core_hash_init(&loadable_modules.dialplan_hash, loadable_modules.pool);
if ((xml = switch_xml_open_cfg(cf, &cfg, NULL))) {
@ -767,6 +787,11 @@ SWITCH_DECLARE(switch_say_interface_t *) switch_loadable_module_get_say_interfac
return switch_core_hash_find(loadable_modules.say_hash, name);
}
SWITCH_DECLARE(switch_management_interface_t *) switch_loadable_module_get_management_interface(char *relative_oid)
{
return switch_core_hash_find(loadable_modules.management_hash, relative_oid);
}
SWITCH_DECLARE(int) switch_loadable_module_get_codecs(switch_memory_pool_t *pool, const switch_codec_implementation_t **array,
int arraylen)
{

View File

@ -46,7 +46,6 @@
#define rtp_header_len 12
#define RTP_START_PORT 16384
#define RTP_END_PORT 32768
#define SWITCH_RTP_CNG_PAYLOAD 13
#define MAX_KEY_LEN 64
#define MASTER_KEY_LEN 30
#define RTP_MAGIC_NUMBER 42
@ -131,11 +130,10 @@ struct switch_rtp {
uint16_t rseq;
switch_payload_t payload;
switch_payload_t rpayload;
switch_rtp_invalid_handler_t invalid_handler;
void *private_data;
uint32_t ts;
uint32_t auto_write_ts;
uint32_t last_write_ts;
uint16_t last_write_seq;
uint32_t last_write_ssrc;
@ -157,6 +155,7 @@ struct switch_rtp {
struct switch_rtp_vad_data vad_data;
struct switch_rtp_rfc2833_data dtmf_data;
switch_payload_t te;
switch_payload_t cng_pt;
switch_mutex_t *flag_mutex;
switch_timer_t timer;
uint8_t ready;
@ -164,6 +163,7 @@ struct switch_rtp {
};
static int global_init = 0;
static int rtp_common_write(switch_rtp_t *rtp_session, void *data, uint32_t datalen, uint8_t m, switch_payload_t payload, switch_frame_flag_t *flags);
static switch_status_t ice_out(switch_rtp_t *rtp_session)
{
@ -536,6 +536,13 @@ SWITCH_DECLARE(void) switch_rtp_set_telephony_event(switch_rtp_t *rtp_session, s
}
}
SWITCH_DECLARE(void) switch_rtp_set_cng_pt(switch_rtp_t *rtp_session, switch_payload_t pt)
{
rtp_session->cng_pt = pt;
}
SWITCH_DECLARE(switch_status_t) switch_rtp_activate_ice(switch_rtp_t *rtp_session, char *login, char *rlogin)
{
char ice_user[80];
@ -773,15 +780,16 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
switch_core_timer_step(&rtp_session->timer);
}
if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_BREAK)) {
if (!bytes && switch_test_flag(rtp_session, SWITCH_RTP_FLAG_BREAK)) {
switch_clear_flag_locked(rtp_session, SWITCH_RTP_FLAG_BREAK);
memset(&rtp_session->recv_msg, 0, SWITCH_RTP_CNG_PAYLOAD);
memset(&rtp_session->recv_msg.body, 0, 2);
rtp_session->recv_msg.body[0] = 127;
rtp_session->recv_msg.header.pt = SWITCH_RTP_CNG_PAYLOAD;
*flags |= SFF_CNG;
/* Return a CNG frame */
*payload_type = SWITCH_RTP_CNG_PAYLOAD;
return SWITCH_RTP_CNG_PAYLOAD + rtp_header_len;
return 2 + rtp_header_len;
}
if (!switch_test_flag(rtp_session, SWITCH_RTP_FLAG_IO)) {
@ -807,8 +815,25 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
if (rtp_session->timer.interval) {
check = (uint8_t)(switch_core_timer_check(&rtp_session->timer) == SWITCH_STATUS_SUCCESS);
if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_AUTO_CNG) &&
rtp_session->timer.samplecount >= (rtp_session->auto_write_ts + (rtp_session->packet_size * 5))) {
uint8_t data[2] = {0};
switch_frame_flag_t flags = SFF_NONE;
data[0] = 127;
rtp_session->auto_write_ts = rtp_session->timer.samplecount;
rtp_session->seq = ntohs(rtp_session->seq) + 1;
rtp_session->seq = htons(rtp_session->seq);
rtp_session->send_msg.header.seq = rtp_session->seq;
rtp_session->send_msg.header.ts = htonl(rtp_session->auto_write_ts);
rtp_common_write(rtp_session, (void *) data, sizeof(data), 0, rtp_session->cng_pt, &flags);
}
}
if (check) {
do_2833(rtp_session);
@ -1047,6 +1072,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_zerocopy_read_frame(switch_rtp_t *rtp
frame->packetlen = bytes;
frame->source = __FILE__;
frame->flags |= SFF_RAW_RTP;
frame->timestamp = ntohl(rtp_session->recv_msg.header.ts);
if (bytes < 0) {
frame->datalen = 0;
@ -1309,7 +1335,11 @@ SWITCH_DECLARE(int) switch_rtp_write(switch_rtp_t *rtp_session, void *data, uint
return -1;
}
rtp_session->ts = ts;
if (!ts && rtp_session->timer.timer_interface) {
rtp_session->auto_write_ts = rtp_session->ts = rtp_session->timer.samplecount;
} else {
rtp_session->ts = ts;
}
if (rtp_session->ts > rtp_session->last_write_ts + rtp_session->packet_size || rtp_session->ts == rtp_session->packet_size) {
mark++;
@ -1345,6 +1375,8 @@ SWITCH_DECLARE(int) switch_rtp_write_frame(switch_rtp_t *rtp_session, switch_fra
if (frame->timestamp) {
rtp_session->ts = (uint32_t) frame->timestamp;
} else if (!ts && rtp_session->timer.timer_interface) {
rtp_session->auto_write_ts = rtp_session->ts = rtp_session->timer.samplecount;
} else {
rtp_session->ts = ts;
}