]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
try to improve autoflush and other silly audio glitches from edge cases and help...
authorAnthony Minessale <anthony.minessale@gmail.com>
Thu, 10 Sep 2009 00:46:24 +0000 (00:46 +0000)
committerAnthony Minessale <anthony.minessale@gmail.com>
Thu, 10 Sep 2009 00:46:24 +0000 (00:46 +0000)
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@14800 d0543943-73ff-0310-b7d9-9358b9ac24b2

src/include/switch_rtp.h
src/mod/endpoints/mod_sofia/sofia_glue.c
src/switch_core_io.c
src/switch_rtp.c
src/switch_time.c

index 246a275772cf453ab2699a5e7a137d78cf525293..1a6b586657b82fb524cdd0ddc452893cfcb28218 100644 (file)
@@ -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
index 702c6d1e1e73ebe382fe7fe42d86f46dc7345f41..c0e7b18719509e8c7216e6ac6a2114539146201d 100644 (file)
@@ -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;
index cce81886cc91e6191c2d1e8a8e7ee8fd9cd7a6f3..461fd0270220c8ea2c6d2d260b31862f74f3eb59 100644 (file)
@@ -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;
-                                               
-                                               
-                                               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);
 
+                       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;
+                               }
                                                
-                                               
+                               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 (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);
 
                                                                
 
-                                                               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 (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 (!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 (flag & SFF_CNG) {
+                                       switch_set_flag(write_frame, SFF_CNG);
+                               }
                                                
-                                               if (ptime_mismatch || resample) {
-                                                       write_frame->timestamp = 0;
-                                               }
+                               if (ptime_mismatch || resample) {
+                                       write_frame->timestamp = 0;
+                               }
 
-                                               if ((status = perform_write(session, write_frame, flags, stream_id)) != SWITCH_STATUS_SUCCESS) {
-                                                       break;
-                                               }
-                                       }
+                               if ((status = perform_write(session, write_frame, flags, stream_id)) != SWITCH_STATUS_SUCCESS) {
+                                       break;
                                }
-                               goto error;
+
                        }
+                       
+                       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:
index f5f33b2fe005cf4ef618a287a5cc023f641d6bda..8578e273b8426025653cd9864d49200108b8cf02 100644 (file)
@@ -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;
                        }
index 8779e2e714e5c3604c470476bdffa1a6d10d3b96..50e52ebfbedddf6cec17cb0330cd9108657276ad 100644 (file)
@@ -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;