Changeset 888


Ignore:
Timestamp:
Jan 20, 2007 5:18:14 AM (13 years ago)
Author:
bennylp
Message:

Implement ticket #56: Periodically transmit RTP packet on silence, to maintain NAT binding etc.

Location:
pjproject/trunk/pjmedia
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjmedia/include/pjmedia/config.h

    r868 r888  
    175175 * Specify how long (in miliseconds) the stream should suspend the 
    176176 * silence detector/voice activity detector (VAD) during the initial 
    177  * period of the session. 
     177 * period of the session. This feature is useful to open bindings in 
     178 * all NAT routers between local and remote endpoint since most NATs 
     179 * do not allow incoming packet to get in before local endpoint sends 
     180 * outgoing packets. 
    178181 * 
    179182 * Specify zero to disable this feature. 
    180183 * 
    181  * Default: 600 msec 
     184 * Default: 600 msec (which gives good probability that some RTP  
     185 *                    packets will reach the destination, but without 
     186 *                    filling up the jitter buffer on the remote end). 
    182187 */ 
    183188#ifndef PJMEDIA_STREAM_VAD_SUSPEND_MSEC 
    184189#   define PJMEDIA_STREAM_VAD_SUSPEND_MSEC      600 
     190#endif 
     191 
     192 
     193/** 
     194 * Specify the maximum duration of silence period in the codec.  
     195 * This is useful for example to keep NAT binding open in the firewall 
     196 * and to prevent server from disconnecting the call because no  
     197 * RTP packet is received. 
     198 * 
     199 * This only applies to codecs that use PJMEDIA's VAD (pretty much 
     200 * everything including iLBC, except Speex, which has its own DTX  
     201 * mechanism). 
     202 * 
     203 * Use (-1) to disable this feature. 
     204 * 
     205 * Default: 8000 (one second on 8KHz). 
     206 * 
     207 */ 
     208#ifndef PJMEDIA_CODEC_MAX_SILENCE_PERIOD 
     209#   define PJMEDIA_CODEC_MAX_SILENCE_PERIOD     8000 
    185210#endif 
    186211 
  • pjproject/trunk/pjmedia/src/pjmedia-codec/gsm.c

    r874 r888  
    120120    pj_bool_t            vad_enabled; 
    121121    pjmedia_silence_det *vad; 
     122    pj_timestamp         last_tx; 
    122123}; 
    123124 
     
    366367    } 
    367368 
     369    /* Re-init silence_period */ 
     370    pj_set_timestamp32(&gsm_data->last_tx, 0, 0); 
     371 
    368372    /* Put in the free list. */ 
    369373    pj_mutex_lock(gsm_codec_factory.mutex); 
     
    498502        return PJMEDIA_CODEC_EFRMTOOSHORT; 
    499503 
    500     if (input->size < 320) 
    501         return PJMEDIA_CODEC_EPCMTOOSHORT; 
     504    PJ_ASSERT_RETURN(input->size==320, PJMEDIA_CODEC_EPCMFRMINLEN); 
    502505 
    503506    /* Detect silence */ 
    504507    if (gsm_data->vad_enabled) { 
    505508        pj_bool_t is_silence; 
     509        pj_int32_t silence_duration; 
     510 
     511        silence_duration = pj_timestamp_diff32(&gsm_data->last_tx,  
     512                                               &input->timestamp); 
    506513 
    507514        is_silence = pjmedia_silence_det_detect(gsm_data->vad,  
    508515                                                input->buf, 
    509                                                 input->size / 2, 
     516                                                (input->size >> 1), 
    510517                                                NULL); 
    511         if (is_silence) { 
     518        if (is_silence && 
     519            PJMEDIA_CODEC_MAX_SILENCE_PERIOD != -1 && 
     520            silence_duration < PJMEDIA_CODEC_MAX_SILENCE_PERIOD)  
     521        { 
    512522            output->type = PJMEDIA_FRAME_TYPE_NONE; 
    513523            output->buf = NULL; 
    514524            output->size = 0; 
    515             output->timestamp.u64 = input->timestamp.u64; 
     525            output->timestamp = input->timestamp; 
    516526            return PJ_SUCCESS; 
     527        } else { 
     528            gsm_data->last_tx = input->timestamp; 
    517529        } 
    518530    } 
  • pjproject/trunk/pjmedia/src/pjmedia-codec/ilbc.c

    r874 r888  
    129129    pj_bool_t            vad_enabled; 
    130130    pj_bool_t            plc_enabled; 
     131    pj_timestamp         last_tx; 
    131132 
    132133    pj_bool_t            enc_ready; 
     
    427428        return status; 
    428429 
     430    /* Init last_tx (not necessary because of zalloc, but better 
     431     * be safe in case someone remove zalloc later. 
     432     */ 
     433    pj_set_timestamp32(&ilbc_codec->last_tx, 0, 0); 
     434 
    429435    PJ_LOG(5,(ilbc_codec->obj_name,  
    430436              "iLBC codec opened, encoder mode=%d, decoder mode=%d", 
     
    513519        return PJMEDIA_CODEC_EFRMTOOSHORT; 
    514520 
    515     if (input->size != ilbc_codec->enc_samples_per_frame * 2) 
     521    if (input->size != (ilbc_codec->enc_samples_per_frame << 1)) 
    516522        return PJMEDIA_CODEC_EPCMFRMINLEN; 
    517523 
     
    519525    if (ilbc_codec->vad_enabled) { 
    520526        pj_bool_t is_silence; 
     527        pj_int32_t silence_period; 
     528 
     529        silence_period = pj_timestamp_diff32(&ilbc_codec->last_tx, 
     530                                              &input->timestamp); 
    521531 
    522532        is_silence = pjmedia_silence_det_detect(ilbc_codec->vad,  
    523533                                                input->buf, 
    524                                                 input->size / 2, 
     534                                                (input->size >> 1), 
    525535                                                NULL); 
    526         if (is_silence) { 
     536        if (is_silence && 
     537            PJMEDIA_CODEC_MAX_SILENCE_PERIOD != -1 && 
     538            silence_period < PJMEDIA_CODEC_MAX_SILENCE_PERIOD) 
     539        { 
    527540            output->type = PJMEDIA_FRAME_TYPE_NONE; 
    528541            output->buf = NULL; 
    529542            output->size = 0; 
    530             output->timestamp.u64 = input->timestamp.u64; 
     543            output->timestamp = input->timestamp; 
    531544            return PJ_SUCCESS; 
     545        } else { 
     546            ilbc_codec->last_tx = input->timestamp; 
    532547        } 
    533548    } 
     
    545560    output->type = PJMEDIA_FRAME_TYPE_AUDIO; 
    546561    output->size = ilbc_codec->enc.no_of_bytes; 
    547     output->timestamp.u64 = input->timestamp.u64; 
     562    output->timestamp = input->timestamp; 
    548563 
    549564    return PJ_SUCCESS; 
     
    564579    PJ_ASSERT_RETURN(input && output, PJ_EINVAL); 
    565580 
    566     if (output_buf_len < ilbc_codec->dec_samples_per_frame*2) 
     581    if (output_buf_len < (ilbc_codec->dec_samples_per_frame << 1)) 
    567582        return PJMEDIA_CODEC_EPCMTOOSHORT; 
    568583 
     
    578593        ((short*)output->buf)[i] = (short)ilbc_codec->dec_block[i]; 
    579594    } 
    580     output->size = ilbc_codec->dec_samples_per_frame * 2; 
     595    output->size = (ilbc_codec->dec_samples_per_frame << 1); 
    581596    output->type = PJMEDIA_FRAME_TYPE_AUDIO; 
    582     output->timestamp.u64 = input->timestamp.u64; 
     597    output->timestamp = input->timestamp; 
    583598 
    584599    return PJ_SUCCESS; 
     
    599614    PJ_ASSERT_RETURN(output, PJ_EINVAL); 
    600615 
    601     if (output_buf_len < ilbc_codec->dec_samples_per_frame*2) 
     616    if (output_buf_len < (ilbc_codec->dec_samples_per_frame << 1)) 
    602617        return PJMEDIA_CODEC_EPCMTOOSHORT; 
    603618 
     
    609624        ((short*)output->buf)[i] = (short)ilbc_codec->dec_block[i]; 
    610625    } 
    611     output->size = ilbc_codec->dec_samples_per_frame * 2; 
     626    output->size = (ilbc_codec->dec_samples_per_frame << 1); 
    612627    output->type = PJMEDIA_FRAME_TYPE_AUDIO; 
    613628 
  • pjproject/trunk/pjmedia/src/pjmedia/g711.c

    r874 r888  
    126126    pj_bool_t            vad_enabled; 
    127127    pjmedia_silence_det *vad; 
     128    pj_timestamp         last_tx; 
    128129}; 
    129130 
     
    466467 
    467468    /* Check output buffer length */ 
    468     if (output_buf_len < input->size / 2) 
     469    if (output_buf_len < (input->size >> 1)) 
    469470        return PJMEDIA_CODEC_EFRMTOOSHORT; 
    470471 
     
    472473    if (priv->vad_enabled) { 
    473474        pj_bool_t is_silence; 
     475        pj_int32_t silence_period; 
     476 
     477        silence_period = pj_timestamp_diff32(&priv->last_tx, 
     478                                             &input->timestamp); 
    474479 
    475480        is_silence = pjmedia_silence_det_detect(priv->vad, input->buf,  
    476                                                 input->size / 2, NULL); 
    477         if (is_silence) { 
     481                                                (input->size >> 1), NULL); 
     482        if (is_silence &&  
     483            PJMEDIA_CODEC_MAX_SILENCE_PERIOD != -1 && 
     484            silence_period < PJMEDIA_CODEC_MAX_SILENCE_PERIOD)  
     485        { 
    478486            output->type = PJMEDIA_FRAME_TYPE_NONE; 
    479487            output->buf = NULL; 
    480488            output->size = 0; 
    481             output->timestamp.u64 = input->timestamp.u64; 
     489            output->timestamp = input->timestamp; 
    482490            return PJ_SUCCESS; 
     491        } else { 
     492            priv->last_tx = input->timestamp; 
    483493        } 
    484494    } 
     
    486496    /* Encode */ 
    487497    if (priv->pt == PJMEDIA_RTP_PT_PCMA) { 
    488         unsigned i; 
     498        unsigned i, n; 
    489499        pj_uint8_t *dst = output->buf; 
    490500 
    491         for (i=0; i!=input->size/2; ++i, ++dst) { 
     501        n = (input->size >> 1); 
     502        for (i=0; i!=n; ++i, ++dst) { 
    492503            *dst = pjmedia_linear2alaw(samples[i]); 
    493504        } 
    494505    } else if (priv->pt == PJMEDIA_RTP_PT_PCMU) { 
    495         unsigned i; 
     506        unsigned i, n; 
    496507        pj_uint8_t *dst = output->buf; 
    497508 
    498         for (i=0; i!=input->size/2; ++i, ++dst) { 
     509        n = (input->size >> 1); 
     510        for (i=0; i!=n; ++i, ++dst) { 
    499511            *dst = pjmedia_linear2ulaw(samples[i]); 
    500512        } 
     
    505517 
    506518    output->type = PJMEDIA_FRAME_TYPE_AUDIO; 
    507     output->size = input->size / 2; 
     519    output->size = (input->size >> 1); 
    508520 
    509521    return PJ_SUCCESS; 
     
    518530 
    519531    /* Check output buffer length */ 
    520     PJ_ASSERT_RETURN(output_buf_len >= input->size * 2, 
     532    PJ_ASSERT_RETURN(output_buf_len >= (input->size << 1), 
    521533                     PJMEDIA_CODEC_EPCMTOOSHORT); 
    522534 
     
    548560 
    549561    output->type = PJMEDIA_FRAME_TYPE_AUDIO; 
    550     output->size = input->size * 2; 
     562    output->size = (input->size << 1); 
    551563 
    552564    if (priv->plc_enabled) 
  • pjproject/trunk/pjmedia/src/pjmedia/silencedet.c

    r838 r888  
    143143        min_signal = sd->ptime; 
    144144    if (recalc_time < 0) 
    145         recalc_time = 5000; 
     145        recalc_time = 2000; 
    146146 
    147147    sd->min_signal_cnt = min_signal / sd->ptime; 
     
    257257            /* Adjust according to signal/silence proportions. */ 
    258258            if (pct_signal > 95) { 
    259                 new_threshold += (sd->weakest_signal - sd->cur_threshold)/4; 
     259                new_threshold += (sd->weakest_signal+1 - sd->cur_threshold)/2; 
    260260            } else if (pct_signal < 5) { 
    261261                new_threshold = (sd->cur_threshold+sd->loudest_silence)/2+1; 
    262             } else if (pct_signal > 90) { 
     262            } else if (pct_signal > 80) { 
    263263                new_threshold++; 
    264264            } else if (pct_signal < 10) { 
     
    269269 
    270270            if (updated && sd->cur_threshold != new_threshold) { 
     271                PJ_LOG(5,(sd->objname,  
     272                          "Vad cur_threshold updated %d-->%d. " 
     273                          "Signal lo=%d", 
     274                          sd->cur_threshold, new_threshold, 
     275                          sd->weakest_signal)); 
    271276                sd->cur_threshold = new_threshold; 
    272                 PJ_LOG(5,(sd->objname, "Vad cur_threshold updated to %d", 
    273                           sd->cur_threshold)); 
    274277            } 
    275278        } 
  • pjproject/trunk/pjmedia/src/pjmedia/stream.c

    r874 r888  
    562562 
    563563    } else if (frame->type != PJMEDIA_FRAME_TYPE_NONE) { 
    564         unsigned ts; 
     564        unsigned ts, codec_samples_per_frame; 
    565565 
    566566        /* Repeatedly call encode if there are multiple frames to be 
    567567         * sent. 
    568568         */ 
    569  
    570         for (ts=0; ts<ts_len; ts += samples_per_frame) { 
     569        codec_samples_per_frame = stream->codec_param.info.enc_ptime * 
     570                                  stream->codec_param.info.clock_rate / 
     571                                  1000; 
     572        if (codec_samples_per_frame == 0) { 
     573            codec_samples_per_frame = stream->codec_param.info.frm_ptime * 
     574                                      stream->codec_param.info.clock_rate / 
     575                                      1000; 
     576        } 
     577 
     578        for (ts=0; ts<ts_len; ts += codec_samples_per_frame) { 
    571579            pjmedia_frame tmp_out_frame, tmp_in_frame; 
    572580            unsigned bytes_per_sample, max_size; 
     
    576584 
    577585            /* Split original PCM input frame into base frame size */ 
     586            tmp_in_frame.timestamp.u64 = frame->timestamp.u64 + ts; 
    578587            tmp_in_frame.buf = ((char*)frame->buf) + ts * bytes_per_sample; 
    579             tmp_in_frame.size = samples_per_frame * bytes_per_sample; 
     588            tmp_in_frame.size = codec_samples_per_frame * bytes_per_sample; 
    580589            tmp_in_frame.type = PJMEDIA_FRAME_TYPE_AUDIO; 
    581590 
     
    690699{ 
    691700    pjmedia_stream *stream = port->port_data.pdata; 
    692     pjmedia_frame tmp_in_frame; 
     701    pjmedia_frame tmp_zero_frame; 
    693702    unsigned samples_per_frame; 
    694703 
    695704    samples_per_frame = stream->enc_samples_per_frame; 
     705 
     706    /* http://www.pjsip.org/trac/ticket/56: 
     707     *  when input is PJMEDIA_FRAME_TYPE_NONE, feed zero PCM frame 
     708     *  instead so that encoder can decide whether or not to transmit 
     709     *  silence frame. 
     710     */ 
     711    if (frame->type == PJMEDIA_FRAME_TYPE_NONE && 
     712        samples_per_frame <= ZERO_PCM_MAX_SIZE)  
     713    { 
     714        pj_memcpy(&tmp_zero_frame, frame, sizeof(pjmedia_frame)); 
     715        frame = &tmp_zero_frame; 
     716 
     717        tmp_zero_frame.buf = zero_frame; 
     718        tmp_zero_frame.size = samples_per_frame * 2; 
     719        tmp_zero_frame.type = PJMEDIA_FRAME_TYPE_AUDIO; 
     720    } 
     721 
     722#if 0 
     723    // This is no longer needed because each TYPE_NONE frame will 
     724    // be converted into zero frame above 
    696725 
    697726    /* If VAD is temporarily disabled during creation, feed zero PCM frame 
     
    710739        tmp_in_frame.type = PJMEDIA_FRAME_TYPE_AUDIO; 
    711740    } 
     741#endif 
    712742 
    713743    /* If VAD is temporarily disabled during creation, enable it 
Note: See TracChangeset for help on using the changeset viewer.