From 7392fa5807d115a3c1795d49eba773ad18cbed3e Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Thu, 10 Sep 2009 00:46:24 +0000 Subject: [PATCH] try to improve autoflush and other silly audio glitches from edge cases and help FSCORE-416 git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@14800 d0543943-73ff-0310-b7d9-9358b9ac24b2 --- src/include/switch_rtp.h | 9 +- src/mod/endpoints/mod_sofia/sofia_glue.c | 4 +- src/switch_core_io.c | 255 +++++++++++------------ src/switch_rtp.c | 37 +++- src/switch_time.c | 4 +- 5 files changed, 158 insertions(+), 151 deletions(-) diff --git a/src/include/switch_rtp.h b/src/include/switch_rtp.h index 246a275772..1a6b586657 100644 --- a/src/include/switch_rtp.h +++ b/src/include/switch_rtp.h @@ -112,6 +112,8 @@ SWITCH_DECLARE(switch_port_t) switch_rtp_set_end_port(switch_port_t port); SWITCH_DECLARE(switch_port_t) switch_rtp_request_port(const char *ip); SWITCH_DECLARE(void) switch_rtp_release_port(const char *ip, switch_port_t port); +SWITCH_DECLARE(switch_status_t) switch_rtp_set_interval(switch_rtp_t *rtp_session, uint32_t ms_per_packet, uint32_t samples_per_interval); + SWITCH_DECLARE(switch_status_t) switch_rtp_change_interval(switch_rtp_t *rtp_session, uint32_t ms_per_packet, uint32_t samples_per_interval); /*! \brief create a new RTP session handle @@ -248,13 +250,6 @@ SWITCH_DECLARE(void) switch_rtp_clear_flag(switch_rtp_t *rtp_session, switch_rtp */ SWITCH_DECLARE(switch_socket_t *) switch_rtp_get_rtp_socket(switch_rtp_t *rtp_session); -/*! - \brief Set the default samples per interval for a given RTP session - \param rtp_session the RTP session to set the samples per interval on - \param samples_per_interval the new default samples per interval -*/ -SWITCH_DECLARE(void) switch_rtp_set_default_samples_per_interval(switch_rtp_t *rtp_session, uint32_t samples_per_interval); - /*! \brief Get the default samples per interval for a given RTP session \param rtp_session the RTP session to get the samples per interval from diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index 702c6d1e1e..c0e7b18719 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -2076,7 +2076,9 @@ switch_status_t sofia_glue_tech_set_codec(private_object_t *tech_pvt, int force) if (switch_rtp_ready(tech_pvt->rtp_session)) { switch_assert(tech_pvt->read_codec.implementation); - switch_rtp_set_default_samples_per_interval(tech_pvt->rtp_session, tech_pvt->read_impl.samples_per_packet); + switch_rtp_set_interval(tech_pvt->rtp_session, + tech_pvt->write_codec.implementation->microseconds_per_packet, + tech_pvt->read_impl.samples_per_packet); } tech_pvt->read_frame.rate = tech_pvt->rm_rate; diff --git a/src/switch_core_io.c b/src/switch_core_io.c index cce81886cc..461fd02702 100644 --- a/src/switch_core_io.c +++ b/src/switch_core_io.c @@ -402,6 +402,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi (uint32_t) bytes, (uint32_t) (*frame)->datalen); switch_buffer_create_dynamic(&session->raw_read_buffer, bytes * SWITCH_BUFFER_BLOCK_FRAMES, bytes * SWITCH_BUFFER_START_FRAMES, 0); } + if (!switch_buffer_write(session->raw_read_buffer, read_frame->data, read_frame->datalen)) { status = SWITCH_STATUS_MEMERR; goto done; @@ -883,10 +884,6 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_sess status = perform_write(session, write_frame, flags, stream_id); goto error; } else { - switch_size_t used; - uint32_t bytes; - switch_size_t frames; - if (!session->raw_write_buffer) { switch_size_t bytes_per_packet = session->write_impl.decoded_bytes_per_packet; switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, @@ -905,140 +902,139 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_sess status = SWITCH_STATUS_MEMERR; goto error; } - used = switch_buffer_inuse(session->raw_write_buffer); - bytes = session->write_impl.decoded_bytes_per_packet; - frames = (used / bytes); - status = SWITCH_STATUS_SUCCESS; - if (!frames) { - goto error; - } else { - switch_size_t x; - for (x = 0; x < frames; x++) { - if (switch_channel_down(session->channel) || !session->raw_write_buffer) { - goto error; - } - if ((session->raw_write_frame.datalen = (uint32_t) - switch_buffer_read(session->raw_write_buffer, session->raw_write_frame.data, bytes)) != 0) { - int rate; - enc_frame = &session->raw_write_frame; - session->raw_write_frame.rate = session->write_impl.actual_samples_per_second; - session->enc_write_frame.datalen = session->enc_write_frame.buflen; - session->enc_write_frame.timestamp = 0; + + while(switch_buffer_inuse(session->raw_write_buffer) >= session->write_impl.decoded_bytes_per_packet) { + int rate; + + if (switch_channel_down(session->channel) || !session->raw_write_buffer) { + goto error; + } + if ((session->raw_write_frame.datalen = (uint32_t) + switch_buffer_read(session->raw_write_buffer, session->raw_write_frame.data, session->write_impl.decoded_bytes_per_packet)) == 0) { + goto error; + } + + enc_frame = &session->raw_write_frame; + session->raw_write_frame.rate = session->write_impl.actual_samples_per_second; + session->enc_write_frame.datalen = session->enc_write_frame.buflen; + session->enc_write_frame.timestamp = 0; + + + if (frame->codec && frame->codec->implementation && switch_core_codec_ready(frame->codec)) { + rate = frame->codec->implementation->actual_samples_per_second; + } else { + rate = session->write_impl.actual_samples_per_second; + } - - if (frame->codec && frame->codec->implementation && switch_core_codec_ready(frame->codec)) { - rate = frame->codec->implementation->actual_samples_per_second; - } else { - rate = session->write_impl.actual_samples_per_second; + status = switch_core_codec_encode(session->write_codec, + frame->codec, + enc_frame->data, + enc_frame->datalen, + rate, + session->enc_write_frame.data, + &session->enc_write_frame.datalen, + &session->enc_write_frame.rate, &flag); + + + switch (status) { + case SWITCH_STATUS_RESAMPLE: + resample++; + session->enc_write_frame.codec = session->write_codec; + session->enc_write_frame.samples = enc_frame->datalen / sizeof(int16_t); + session->enc_write_frame.m = frame->m; + session->enc_write_frame.ssrc = frame->ssrc; + session->enc_write_frame.payload = session->write_impl.ianacode; + write_frame = &session->enc_write_frame; + if (!session->write_resampler) { + switch_mutex_lock(session->resample_mutex); + if (!session->write_resampler) { + status = switch_resample_create(&session->write_resampler, + frame->codec->implementation->actual_samples_per_second, + session->write_impl.actual_samples_per_second, + session->write_impl.decoded_bytes_per_packet, + SWITCH_RESAMPLE_QUALITY, 1); } - - status = switch_core_codec_encode(session->write_codec, - frame->codec, - enc_frame->data, - enc_frame->datalen, - rate, - session->enc_write_frame.data, - &session->enc_write_frame.datalen, - &session->enc_write_frame.rate, &flag); - - - - - switch (status) { - case SWITCH_STATUS_RESAMPLE: - resample++; - session->enc_write_frame.codec = session->write_codec; - session->enc_write_frame.samples = enc_frame->datalen / sizeof(int16_t); - session->enc_write_frame.m = frame->m; - session->enc_write_frame.ssrc = frame->ssrc; - session->enc_write_frame.payload = session->write_impl.ianacode; - write_frame = &session->enc_write_frame; - if (!session->write_resampler) { - switch_mutex_lock(session->resample_mutex); - if (!session->write_resampler) { - status = switch_resample_create(&session->write_resampler, - frame->codec->implementation->actual_samples_per_second, - session->write_impl.actual_samples_per_second, - session->write_impl.decoded_bytes_per_packet, - SWITCH_RESAMPLE_QUALITY, 1); - } - switch_mutex_unlock(session->resample_mutex); + switch_mutex_unlock(session->resample_mutex); - if (status != SWITCH_STATUS_SUCCESS) { - goto done; - } - } - break; - case SWITCH_STATUS_SUCCESS: - session->enc_write_frame.codec = session->write_codec; - session->enc_write_frame.samples = enc_frame->datalen / sizeof(int16_t); - session->enc_write_frame.m = frame->m; - session->enc_write_frame.ssrc = frame->ssrc; - session->enc_write_frame.payload = session->write_impl.ianacode; - write_frame = &session->enc_write_frame; - break; - case SWITCH_STATUS_NOOP: - if (session->write_resampler) { - switch_mutex_lock(session->resample_mutex); - if (session->write_resampler) { - switch_resample_destroy(&session->write_resampler); - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Deactivating write resampler\n"); - } - switch_mutex_unlock(session->resample_mutex); - } - enc_frame->codec = session->write_codec; - enc_frame->samples = enc_frame->datalen / sizeof(int16_t); - enc_frame->m = frame->m; - enc_frame->ssrc = frame->ssrc; - enc_frame->payload = enc_frame->codec->implementation->ianacode; - write_frame = enc_frame; - status = SWITCH_STATUS_SUCCESS; - break; - case SWITCH_STATUS_NOT_INITALIZED: - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Codec init error!\n"); - write_frame = NULL; - goto error; - default: - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Codec %s encoder error %d!\n", - session->read_codec->codec_interface->interface_name, status); - write_frame = NULL; - goto error; - } - - if (!did_write_resample && session->read_resampler) { - short *data = write_frame->data; - switch_mutex_lock(session->resample_mutex); - if (session->read_resampler) { - switch_resample_process(session->read_resampler, data, write_frame->datalen / 2); - memcpy(data, session->read_resampler->to, session->read_resampler->to_len * 2); - write_frame->samples = session->read_resampler->to_len; - write_frame->datalen = session->read_resampler->to_len * 2; - write_frame->rate = session->read_resampler->to_rate; - } - switch_mutex_unlock(session->resample_mutex); - - } - - if (flag & SFF_CNG) { - switch_set_flag(write_frame, SFF_CNG); - } - - if (ptime_mismatch || resample) { - write_frame->timestamp = 0; - } - - if ((status = perform_write(session, write_frame, flags, stream_id)) != SWITCH_STATUS_SUCCESS) { - break; + if (status != SWITCH_STATUS_SUCCESS) { + goto done; } } + break; + case SWITCH_STATUS_SUCCESS: + session->enc_write_frame.codec = session->write_codec; + session->enc_write_frame.samples = enc_frame->datalen / sizeof(int16_t); + session->enc_write_frame.m = frame->m; + session->enc_write_frame.ssrc = frame->ssrc; + session->enc_write_frame.payload = session->write_impl.ianacode; + write_frame = &session->enc_write_frame; + break; + case SWITCH_STATUS_NOOP: + if (session->write_resampler) { + switch_mutex_lock(session->resample_mutex); + if (session->write_resampler) { + switch_resample_destroy(&session->write_resampler); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Deactivating write resampler\n"); + } + switch_mutex_unlock(session->resample_mutex); + } + enc_frame->codec = session->write_codec; + enc_frame->samples = enc_frame->datalen / sizeof(int16_t); + enc_frame->m = frame->m; + enc_frame->ssrc = frame->ssrc; + enc_frame->payload = enc_frame->codec->implementation->ianacode; + write_frame = enc_frame; + status = SWITCH_STATUS_SUCCESS; + break; + case SWITCH_STATUS_NOT_INITALIZED: + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Codec init error!\n"); + write_frame = NULL; + goto error; + default: + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Codec %s encoder error %d!\n", + session->read_codec->codec_interface->interface_name, status); + write_frame = NULL; + goto error; } - goto error; + + if (!did_write_resample && session->read_resampler) { + short *data = write_frame->data; + switch_mutex_lock(session->resample_mutex); + if (session->read_resampler) { + switch_resample_process(session->read_resampler, data, write_frame->datalen / 2); + memcpy(data, session->read_resampler->to, session->read_resampler->to_len * 2); + write_frame->samples = session->read_resampler->to_len; + write_frame->datalen = session->read_resampler->to_len * 2; + write_frame->rate = session->read_resampler->to_rate; + } + switch_mutex_unlock(session->resample_mutex); + + } + + if (flag & SFF_CNG) { + switch_set_flag(write_frame, SFF_CNG); + } + + if (ptime_mismatch || resample) { + write_frame->timestamp = 0; + } + + if ((status = perform_write(session, write_frame, flags, stream_id)) != SWITCH_STATUS_SUCCESS) { + break; + } + } + + goto error; } } + + + + done: @@ -1047,12 +1043,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_sess } if (do_write) { - - - - status = perform_write(session, write_frame, flags, stream_id); - - + status = perform_write(session, write_frame, flags, stream_id); } error: diff --git a/src/switch_rtp.c b/src/switch_rtp.c index f5f33b2fe0..8578e273b8 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -182,6 +182,7 @@ struct switch_rtp { char *remote_host_str; switch_time_t last_stun; uint32_t samples_per_interval; + uint32_t samples_per_second; uint32_t conf_samples_per_interval; uint32_t rsamples_per_interval; uint32_t ms_per_packet; @@ -213,6 +214,7 @@ struct switch_rtp { switch_rtp_bug_flag_t rtp_bugs; switch_rtp_stats_t stats; int hot_hits; + int sync_packets; #ifdef ENABLE_ZRTP zrtp_session_t *zrtp_session; @@ -1038,12 +1040,21 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_add_crypto_key(switch_rtp_t *rtp_sess return SWITCH_STATUS_SUCCESS; } -SWITCH_DECLARE(switch_status_t) switch_rtp_change_interval(switch_rtp_t *rtp_session, uint32_t ms_per_packet, uint32_t samples_per_interval) +SWITCH_DECLARE(switch_status_t) switch_rtp_set_interval(switch_rtp_t *rtp_session, uint32_t ms_per_packet, uint32_t samples_per_interval) { rtp_session->ms_per_packet = ms_per_packet; rtp_session->samples_per_interval = rtp_session->conf_samples_per_interval = samples_per_interval; rtp_session->missed_count = 0; + rtp_session->samples_per_second = (uint32_t)((double)(1000.0f / (double)(rtp_session->ms_per_packet / 1000)) * (double)rtp_session->samples_per_interval); + return SWITCH_STATUS_SUCCESS; +} + +SWITCH_DECLARE(switch_status_t) switch_rtp_change_interval(switch_rtp_t *rtp_session, uint32_t ms_per_packet, uint32_t samples_per_interval) +{ + + switch_rtp_set_interval(rtp_session, ms_per_packet, samples_per_interval); + if (rtp_session->timer_name) { if (rtp_session->timer.timer_interface) { switch_core_timer_destroy(&rtp_session->timer); @@ -1123,8 +1134,9 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_create(switch_rtp_t **new_rtp_session rtp_session->recv_msg.header.cc = 0; rtp_session->payload = payload; - rtp_session->ms_per_packet = ms_per_packet; - rtp_session->samples_per_interval = rtp_session->conf_samples_per_interval = samples_per_interval; + + switch_rtp_set_interval(rtp_session, ms_per_packet, samples_per_interval); + rtp_session->conf_samples_per_interval = samples_per_interval; if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_USE_TIMER) && switch_strlen_zero(timer_name)) { timer_name = "soft"; @@ -1490,11 +1502,6 @@ SWITCH_DECLARE(switch_socket_t *) switch_rtp_get_rtp_socket(switch_rtp_t *rtp_se return rtp_session->sock_input; } -SWITCH_DECLARE(void) switch_rtp_set_default_samples_per_interval(switch_rtp_t *rtp_session, uint32_t samples_per_interval) -{ - rtp_session->samples_per_interval = samples_per_interval; -} - SWITCH_DECLARE(uint32_t) switch_rtp_get_default_samples_per_interval(switch_rtp_t *rtp_session) { return rtp_session->samples_per_interval; @@ -1783,7 +1790,9 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ if ((switch_test_flag(rtp_session, SWITCH_RTP_FLAG_AUTOFLUSH) || switch_test_flag(rtp_session, SWITCH_RTP_FLAG_STICKY_FLUSH)) && rtp_session->read_pollfd) { if (switch_poll(rtp_session->read_pollfd, 1, &fdr, 1) == SWITCH_STATUS_SUCCESS) { - if (++rtp_session->hot_hits >= 10) { + rtp_session->hot_hits += rtp_session->samples_per_interval; + + if (rtp_session->hot_hits >= rtp_session->samples_per_second * 60) { hot_socket = 1; } } else { @@ -1792,8 +1801,17 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ } if (hot_socket) { + rtp_session->sync_packets++; switch_core_timer_sync(&rtp_session->timer); } else { + if (rtp_session->sync_packets) { +#if 0 + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "Auto-Flush catching up %d packets (%d)ms.\n", + rtp_session->sync_packets, rtp_session->ms_per_packet * rtp_session->sync_packets); +#endif + rtp_session->sync_packets = 0; + } switch_core_timer_next(&rtp_session->timer); } } @@ -2440,6 +2458,7 @@ static int rtp_common_write(switch_rtp_t *rtp_session, rtp_session->ts = (uint32_t) timestamp; } else if (rtp_session->timer.timer_interface) { rtp_session->ts = rtp_session->timer.samplecount; + if (rtp_session->ts <= rtp_session->last_write_ts) { rtp_session->ts = rtp_session->last_write_ts + rtp_session->samples_per_interval; } diff --git a/src/switch_time.c b/src/switch_time.c index 8779e2e714..50e52ebfbe 100644 --- a/src/switch_time.c +++ b/src/switch_time.c @@ -307,8 +307,8 @@ static switch_status_t timer_sync(switch_timer_t *timer) /* apply timestamp */ if (timer_step(timer) == SWITCH_STATUS_SUCCESS) { - /* push the reference into the future 2 more intervals to prevent collision */ - private_info->reference += 2; + /* push the reference into the future to prevent collision */ + private_info->reference++; } return SWITCH_STATUS_SUCCESS;