diff --git a/libs/freetdm/mod_freetdm/tdm.c b/libs/freetdm/mod_freetdm/tdm.c index 7f44b640a9..1b401d364c 100644 --- a/libs/freetdm/mod_freetdm/tdm.c +++ b/libs/freetdm/mod_freetdm/tdm.c @@ -39,6 +39,7 @@ void ctdm_init(switch_loadable_module_interface_t *module_interface); #define kSPAN_ID "span" #define kCHAN_ID "chan" #define kSPAN_NAME "span_name" +#define kPREBUFFER_LEN "prebuffer_len" static struct { switch_memory_pool_t *pool; @@ -52,6 +53,7 @@ typedef struct { switch_core_session_t *session; switch_codec_t read_codec, write_codec; switch_frame_t read_frame; + int prebuffer_len; unsigned char databuf[SWITCH_RECOMMENDED_BUFFER_SIZE]; } ctdm_private_t; @@ -66,6 +68,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id); static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id); static switch_status_t channel_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg); +static switch_status_t channel_receive_event(switch_core_session_t *session, switch_event_t *event); static switch_status_t channel_send_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf); @@ -81,7 +84,8 @@ switch_io_routines_t ctdm_io_routines = { .outgoing_channel = channel_outgoing_channel, .read_frame = channel_read_frame, .write_frame = channel_write_frame, - .receive_message = channel_receive_message + .receive_message = channel_receive_message, + .receive_event = channel_receive_event }; static void ctdm_report_alarms(ftdm_channel_t *channel) @@ -293,7 +297,8 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi switch_originate_flag_t flags, switch_call_cause_t *cancel_cause) { const char *szchanid = switch_event_get_header(var_event, kCHAN_ID), - *span_name = switch_event_get_header(var_event, kSPAN_NAME); + *span_name = switch_event_get_header(var_event, kSPAN_NAME), + *szprebuffer_len = switch_event_get_header(var_event, kPREBUFFER_LEN); int chan_id; int span_id; switch_caller_profile_t *caller_profile; @@ -341,6 +346,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi tech_pvt->session = *new_session; tech_pvt->read_frame.buflen = sizeof(tech_pvt->databuf); tech_pvt->read_frame.data = tech_pvt->databuf; + tech_pvt->prebuffer_len = zstr(szprebuffer_len) ? 0 : atoi(szprebuffer_len); switch_core_session_set_private(*new_session, tech_pvt); @@ -363,6 +369,11 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi return SWITCH_STATUS_GENERR; } + if (FTDM_SUCCESS != ftdm_channel_command(chan, FTDM_COMMAND_SET_PRE_BUFFER_SIZE, &tech_pvt->prebuffer_len)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to set channel pre buffer size.\n"); + return SWITCH_STATUS_GENERR; + } + switch(codec) { case FTDM_CODEC_ULAW: { @@ -623,3 +634,25 @@ static switch_status_t channel_receive_message(switch_core_session_t *session, s return SWITCH_STATUS_SUCCESS; } +static switch_status_t channel_receive_event(switch_core_session_t *session, switch_event_t *event) +{ + const char *command = switch_event_get_header(event, "command"); + ctdm_private_t *tech_pvt = switch_core_session_get_private(session); + + if (!zstr(command) && !strcasecmp(command, kPREBUFFER_LEN)) { + const char *szval = switch_event_get_header(event, kPREBUFFER_LEN); + int val = !zstr(szval) ? atoi(szval) : 0; + + if (tech_pvt->prebuffer_len == val) { + tech_pvt->prebuffer_len = val; + if (FTDM_SUCCESS != ftdm_channel_command(tech_pvt->ftdm_channel, FTDM_COMMAND_SET_PRE_BUFFER_SIZE, &tech_pvt->prebuffer_len)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to set channel pre buffer size.\n"); + return SWITCH_STATUS_GENERR; + } + } + } + + + return SWITCH_STATUS_SUCCESS; +} + diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway.c b/src/mod/endpoints/mod_media_gateway/media_gateway.c index 87201b4dbb..7387343d52 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway.c @@ -134,6 +134,7 @@ switch_status_t megaco_activate_termination(mg_termination_t *term) switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, kSPAN_NAME, term->u.tdm.span_name); switch_event_add_header(var_event, SWITCH_STACK_BOTTOM, kCHAN_ID, "%d", term->u.tdm.channel); + switch_event_add_header(var_event, SWITCH_STACK_BOTTOM, kPREBUFFER_LEN, "%d", term->profile->tdm_pre_buffer_size); } /* Set common variables on the channel */ @@ -146,9 +147,15 @@ switch_status_t megaco_activate_termination(mg_termination_t *term) switch_channel_t *channel = switch_core_session_get_channel(session); switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "command", "media_modify"); - if (term->u.rtp.t38_options) { - switch_channel_set_private(channel, "t38_options", term->u.rtp.t38_options); - } + if (term->type == MG_TERM_RTP) { + if (term->u.rtp.t38_options) { + switch_channel_set_private(channel, "t38_options", term->u.rtp.t38_options); + } + + if (term->u.rtp.media_type == MGM_IMAGE) { + mg_term_set_pre_buffer_size(term, 0); + } + } switch_core_session_receive_event(session, &var_event); @@ -176,10 +183,10 @@ switch_status_t megaco_activate_termination(mg_termination_t *term) channel = switch_core_session_get_channel(session); switch_channel_set_private(channel, PVT_MG_TERM, term); - if (term->u.rtp.t38_options) { - switch_channel_set_private(channel, "t38_options", term->u.rtp.t38_options); - } - + if (term->type == MG_TERM_RTP && term->u.rtp.t38_options) { + switch_channel_set_private(channel, "t38_options", term->u.rtp.t38_options); + } + switch_core_event_hook_add_recv_dtmf(session, mg_on_dtmf); if (term->type == MG_TERM_TDM) { @@ -724,6 +731,34 @@ switch_status_t megaco_peer_profile_destroy(mg_peer_profile_t **profile) return SWITCH_STATUS_SUCCESS; } +void mg_term_set_pre_buffer_size(mg_termination_t *term, int newval) +{ + switch_event_t *event = NULL, *event2 = NULL; + switch_core_session_t *session, *session2; + + if (!zstr(term->uuid) && (session = switch_core_session_locate(term->uuid))) { + switch_event_create(&event, SWITCH_EVENT_CLONE); + + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "command", kPREBUFFER_LEN); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, kPREBUFFER_LEN, "%d", newval); + + /* Propagate event to bridged session if there is one */ + if (switch_core_session_get_partner(session, &session2) == SWITCH_STATUS_SUCCESS) { + switch_event_dup(&event2, event); + switch_core_session_receive_event(session2, &event2); + switch_core_session_rwunlock(session2); + } + + switch_core_session_receive_event(session, &event); + switch_core_session_rwunlock(session); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Sent prebuffer_size event to [%s] to [%d ms]\n", term->uuid, newval); + } + +done: + switch_event_destroy(&event); +} + /* For Emacs: * Local Variables: * mode:c diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c index 4d1269fea7..d2c0e991b4 100644 --- a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c +++ b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c @@ -288,6 +288,13 @@ static switch_xml_config_item_t *get_instructions(megaco_profile_t *profile) { 9 }; + static switch_xml_config_int_options_t pre_buffer_len = { + SWITCH_TRUE, /* enforce min */ + 0, + SWITCH_TRUE, /* enforce Max */ + 10000 + }; + #if 0 static switch_xml_config_enum_item_t opt_default_codec_enum[] = { { "PCMA", MEGACO_CODEC_PCMA}, @@ -311,6 +318,7 @@ static switch_xml_config_item_t *get_instructions(megaco_profile_t *profile) { SWITCH_CONFIG_ITEM("rtp-port-range", SWITCH_CONFIG_STRING, CONFIG_REQUIRED, &profile->rtp_port_range, "1-65535", &switch_config_string_strdup, "", "rtp port range"), SWITCH_CONFIG_ITEM("rtp-termination-id-prefix", SWITCH_CONFIG_STRING, CONFIG_RELOADABLE, &profile->rtp_termination_id_prefix, "", &switch_config_string_strdup, "", "rtp termination prefix"), SWITCH_CONFIG_ITEM("rtp-termination-id-length", SWITCH_CONFIG_INT, CONFIG_RELOADABLE, &profile->rtp_termination_id_len, "", &opt_termination_id_len, "", "rtp termination id"), + SWITCH_CONFIG_ITEM("rtp-pre-buffer-size", SWITCH_CONFIG_INT, CONFIG_RELOADABLE, &profile->tdm_pre_buffer_size, 200, &pre_buffer_len, "", "freetdm pre buffer size"), SWITCH_CONFIG_ITEM("codec-prefs", SWITCH_CONFIG_STRING, 0, &profile->codec_prefs, "", &switch_config_string_strdup, "", "codec preferences, coma-separated"), SWITCH_CONFIG_ITEM_END() }; diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h index 62c1367f6f..15f1cf7bed 100644 --- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h +++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.h @@ -87,7 +87,7 @@ typedef struct mg_context_s mg_context_t; #define kSPAN_ID "span" #define kCHAN_ID "chan" #define kSPAN_NAME "span_name" - +#define kPREBUFFER_LEN "prebuffer_len" typedef struct mg_termination_s mg_termination_t; @@ -200,6 +200,7 @@ struct megaco_profile_s { char* rtp_port_range; char* rtp_termination_id_prefix; int rtp_termination_id_len; + int tdm_pre_buffer_size; char* peer_list[MG_MAX_PEERS]; /* MGC Peer ID LIST */ char* codec_prefs; int inact_tmr; /* inactivity timer value */ @@ -267,6 +268,7 @@ switch_status_t megaco_profile_destroy(megaco_profile_t **profile); uint32_t mg_rtp_request_id(megaco_profile_t *profile); void mg_rtp_release_id(megaco_profile_t *profile, uint32_t id); +void mg_term_set_pre_buffer_size(mg_termination_t *term, int newval); mg_context_t *megaco_get_context(megaco_profile_t *profile, uint32_t context_id); mg_context_t *megaco_choose_context(megaco_profile_t *profile); @@ -295,6 +297,9 @@ switch_status_t megaco_context_is_term_present(mg_context_t *ctx, mg_termination switch_status_t megaco_prepare_tdm_termination(mg_termination_t *term); switch_status_t megaco_check_tdm_termination(mg_termination_t *term); + + + #endif /* MOD_MEGACO_H */