Changeset 1813


Ignore:
Timestamp:
Feb 21, 2008 4:46:34 PM (17 years ago)
Author:
bennylp
Message:

Ticket #486: Handle G.722 wong clock rate bug and other codec with inconsistent clock rate

Location:
pjproject/trunk/pjmedia
Files:
4 edited

Legend:

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

    r1735 r1813  
    486486 
    487487/** 
    488  * SRTP Transport 
     488 * Enable support for SRTP media transport. This will require linking 
     489 * with libsrtp from the third_party directory. 
     490 * 
    489491 * By default it is enabled. 
    490492 */ 
     
    495497 
    496498/** 
     499 * Enable support to handle codecs with inconsistent clock rate 
     500 * between clock rate in SDP/RTP & the clock rate that is actually used. 
     501 * This happens for example with G.722 and MPEG audio codecs. 
     502 * See: 
     503 *  - G.722      : RFC 3551 4.5.2 
     504 *  - MPEG audio : RFC 3551 4.5.13 & RFC 3119 
     505 * 
     506 * Also when this feature is enabled, some handling will be performed 
     507 * to deal with clock rate incompatibilities of some phones. 
     508 * 
     509 * By default it is enabled. 
     510 */ 
     511#ifndef PJMEDIA_HANDLE_G722_MPEG_BUG 
     512#   define PJMEDIA_HANDLE_G722_MPEG_BUG             1 
     513#endif 
     514 
     515 
     516/** 
    497517 * @} 
    498518 */ 
  • pjproject/trunk/pjmedia/src/pjmedia/endpoint.c

    r1615 r1813  
    413413 
    414414        rtpmap.pt = *fmt; 
     415        rtpmap.enc_name = codec_info->encoding_name; 
     416 
     417#if defined(PJMEDIA_HANDLE_G722_MPEG_BUG) && (PJMEDIA_HANDLE_G722_MPEG_BUG != 0) 
     418        if (codec_info->pt == PJMEDIA_RTP_PT_G722) 
     419            rtpmap.clock_rate = 8000; 
     420        else 
     421            rtpmap.clock_rate = codec_info->clock_rate; 
     422#else 
    415423        rtpmap.clock_rate = codec_info->clock_rate; 
    416         rtpmap.enc_name = codec_info->encoding_name; 
    417          
     424#endif 
     425 
    418426        /* For audio codecs, rtpmap parameters denotes the number 
    419427         * of channels, which can be omited if the value is 1. 
  • pjproject/trunk/pjmedia/src/pjmedia/session.c

    r1810 r1813  
    389389            si->fmt.clock_rate = rtpmap->clock_rate; 
    390390             
     391#if defined(PJMEDIA_HANDLE_G722_MPEG_BUG) && (PJMEDIA_HANDLE_G722_MPEG_BUG != 0) 
     392            /* The session info should have the actual clock rate, because  
     393             * this info is used for calculationg buffer size, etc in stream */ 
     394            if (si->fmt.pt == PJMEDIA_RTP_PT_G722) 
     395                si->fmt.clock_rate = 16000; 
     396#endif 
     397 
    391398            /* For audio codecs, rtpmap parameters denotes the number of 
    392399             * channels. 
  • pjproject/trunk/pjmedia/src/pjmedia/stream.c

    r1809 r1813  
    9393                                                 Otherwise it's NULL.       */ 
    9494 
    95     unsigned                 enc_samples_per_frame; 
     95    unsigned                 enc_samples_per_pkt; 
    9696    unsigned                 enc_buf_size;  /**< Encoding buffer size, in 
    9797                                                 samples.                   */ 
     
    132132    void                    (*dtmf_cb)(pjmedia_stream*, void*, int); 
    133133    void                     *dtmf_cb_user_data; 
     134 
     135#if defined(PJMEDIA_HANDLE_G722_MPEG_BUG) && (PJMEDIA_HANDLE_G722_MPEG_BUG!=0) 
     136    /* Enable support to handle codecs with inconsistent clock rate 
     137     * between clock rate in SDP/RTP & the clock rate that is actually used. 
     138     * This happens for example with G.722 and MPEG audio codecs. 
     139     */ 
     140    pj_bool_t                has_g722_mpeg_bug; 
     141                                            /**< Flag to specify whether  
     142                                                 normalization process  
     143                                                 is needed                  */ 
     144    unsigned                 rtp_tx_samples_per_pkt; 
     145                                            /**< Normalized samples per packet  
     146                                                 transmitted according to  
     147                                                 'erroneous' definition     */ 
     148    unsigned                 rtp_rx_samples_per_frame; 
     149                                            /**< Normalized samples per frame  
     150                                                 received according to  
     151                                                 'erroneous' definition     */ 
     152    pj_uint32_t              rtp_rx_last_ts;/**< Last received RTP timestamp 
     153                                                 for timestamp checking     */ 
     154    unsigned                 rtp_rx_last_cnt;/**< Nb of frames in last pkt  */ 
     155    unsigned                 rtp_rx_check_cnt; 
     156                                            /**< Counter of remote timestamp 
     157                                                 checking */ 
     158#endif 
     159 
    134160}; 
    135161 
     
    522548    pj_status_t status = 0; 
    523549    pjmedia_frame frame_out; 
    524     unsigned ts_len, samples_per_frame; 
     550    unsigned ts_len, rtp_ts_len, samples_per_frame; 
    525551    void *rtphdr; 
    526552    int rtphdrlen; 
     
    542568    stream->tx_duration += ts_len; 
    543569 
     570#if defined(PJMEDIA_HANDLE_G722_MPEG_BUG) && (PJMEDIA_HANDLE_G722_MPEG_BUG!=0) 
     571    /* Handle special case for audio codec with RTP timestamp inconsistence  
     572     * e.g: G722, MPEG audio. 
     573     */ 
     574    if (stream->has_g722_mpeg_bug) 
     575        rtp_ts_len = stream->rtp_tx_samples_per_pkt; 
     576    else 
     577        rtp_ts_len = ts_len; 
     578#else 
     579    rtp_ts_len = ts_len; 
     580#endif 
     581 
    544582    /* Init frame_out buffer. */ 
    545583    frame_out.buf = ((char*)channel->out_pkt) + sizeof(pjmedia_rtp_hdr); 
     
    547585 
    548586    /* Calculate number of samples per frame */ 
    549     samples_per_frame = stream->enc_samples_per_frame; 
     587    samples_per_frame = stream->enc_samples_per_pkt; 
    550588 
    551589 
     
    564602        status = pjmedia_rtp_encode_rtp( &channel->rtp,  
    565603                                         stream->tx_event_pt, first,  
    566                                          frame_out.size, (first?ts_len:0),  
     604                                         frame_out.size, 
     605                                         (first ? rtp_ts_len : 0),  
    567606                                         (const void**)&rtphdr,  
    568607                                         &rtphdrlen); 
     
    573612             * RTP packets. 
    574613             */ 
    575             inc_timestamp = PJMEDIA_DTMF_DURATION - ts_len; 
     614            inc_timestamp = PJMEDIA_DTMF_DURATION - rtp_ts_len; 
    576615        } 
    577616 
     
    641680        status = pjmedia_rtp_encode_rtp( &channel->rtp,  
    642681                                         channel->pt, 0,  
    643                                          frame_out.size, ts_len,  
     682                                         frame_out.size, rtp_ts_len,  
    644683                                         (const void**)&rtphdr,  
    645684                                         &rtphdrlen); 
     
    649688        status = pjmedia_rtp_encode_rtp( &channel->rtp,  
    650689                                         0, 0,  
    651                                          0, ts_len,  
     690                                         0, rtp_ts_len,  
    652691                                         (const void**)&rtphdr,  
    653692                                         &rtphdrlen); 
     
    730769    unsigned samples_per_frame; 
    731770 
    732     samples_per_frame = stream->enc_samples_per_frame; 
     771    samples_per_frame = stream->enc_samples_per_pkt; 
    733772 
    734773    /* http://www.pjsip.org/trac/ticket/56: 
     
    807846             * rebuffer() with NULL frame. 
    808847             */ 
    809             if (stream->enc_buf_count >= stream->enc_samples_per_frame) { 
     848            if (stream->enc_buf_count >= stream->enc_samples_per_pkt) { 
    810849 
    811850                tmp_rebuffer_frame.type = PJMEDIA_FRAME_TYPE_NONE; 
     
    10271066        pj_timestamp ts; 
    10281067        unsigned i, count = MAX; 
    1029         unsigned samples_per_frame; 
     1068        unsigned ts_span; 
    10301069        pjmedia_frame frames[MAX]; 
    10311070 
     
    10471086        } 
    10481087 
     1088#if defined(PJMEDIA_HANDLE_G722_MPEG_BUG) && (PJMEDIA_HANDLE_G722_MPEG_BUG!=0) 
     1089        /* This code is used to learn the samples per frame value that is put 
     1090         * by remote endpoint, for codecs with inconsistent clock rate such 
     1091         * as G.722 or MPEG audio. We need to learn the samples per frame  
     1092         * value as it is used as divider when inserting frames into the 
     1093         * jitter buffer. 
     1094         */ 
     1095        if (stream->has_g722_mpeg_bug) { 
     1096            if (stream->rtp_rx_check_cnt) { 
     1097                /* Make sure the detection performed only on two consecutive  
     1098                 * packets with valid RTP sequence and no wrapped timestamp. 
     1099                 */ 
     1100                if (seq_st.diff == 1 && stream->rtp_rx_last_ts &&  
     1101                    ts.u64 > stream->rtp_rx_last_ts) 
     1102                { 
     1103                    unsigned peer_frm_ts_diff; 
     1104 
     1105                    peer_frm_ts_diff =  
     1106                        ((pj_uint32_t)ts.u64-stream->rtp_rx_last_ts) /  
     1107                        stream->rtp_rx_last_cnt; 
     1108 
     1109                    /* Possibilities remote's samples per frame for G.722  
     1110                     * are only 160 and 320, this validation is needed 
     1111                     * to avoid wrong decision because of silence frames. 
     1112                     */ 
     1113                    if (stream->codec_param.info.pt == PJMEDIA_RTP_PT_G722 && 
     1114                        (peer_frm_ts_diff==stream->port.info.samples_per_frame 
     1115                         || peer_frm_ts_diff ==  
     1116                                    stream->port.info.samples_per_frame >> 1)) 
     1117                    { 
     1118                        if (peer_frm_ts_diff < stream->rtp_rx_samples_per_frame) 
     1119                            stream->rtp_rx_samples_per_frame = peer_frm_ts_diff; 
     1120 
     1121                        if (--stream->rtp_rx_check_cnt == 0) { 
     1122                            PJ_LOG(4, (THIS_FILE, "G722 codec used, remote" 
     1123                                       " samples per frame detected = %d",  
     1124                                       stream->rtp_rx_samples_per_frame)); 
     1125                             
     1126                            /* Reset jitter buffer once detection done */ 
     1127                            pjmedia_jbuf_reset(stream->jb); 
     1128                        } 
     1129                    } 
     1130                } 
     1131 
     1132                stream->rtp_rx_last_ts = (pj_uint32_t)ts.u64; 
     1133                stream->rtp_rx_last_cnt = count; 
     1134            } 
     1135 
     1136            ts_span = stream->rtp_rx_samples_per_frame; 
     1137 
     1138        } else { 
     1139            ts_span = stream->codec_param.info.frm_ptime *  
     1140                      stream->codec_param.info.clock_rate * 
     1141                      stream->codec_param.info.channel_cnt / 
     1142                      1000; 
     1143        } 
     1144#else 
     1145        ts_span = stream->codec_param.info.frm_ptime *  
     1146                  stream->codec_param.info.clock_rate * 
     1147                  stream->codec_param.info.channel_cnt / 
     1148                  1000; 
     1149#endif 
     1150 
    10491151        /* Put each frame to jitter buffer. */ 
    1050         samples_per_frame = stream->codec_param.info.frm_ptime *  
    1051                             stream->codec_param.info.clock_rate * 
    1052                             stream->codec_param.info.channel_cnt / 
    1053                             1000; 
    1054                              
    10551152        for (i=0; i<count; ++i) { 
    10561153            unsigned ext_seq; 
    10571154 
    1058             ext_seq = (unsigned)(frames[i].timestamp.u64 / 
    1059                                  samples_per_frame); 
     1155            ext_seq = (unsigned)(frames[i].timestamp.u64 / ts_span); 
    10601156            pjmedia_jbuf_put_frame(stream->jb, frames[i].buf,  
    10611157                                   frames[i].size, ext_seq); 
     
    11901286    name.ptr = (char*) pj_pool_alloc(pool, M); 
    11911287    name.slen = pj_ansi_snprintf(name.ptr, M, "strm%p", stream); 
    1192  
    11931288 
    11941289    /* Init some port-info. Some parts of the info will be set later 
     
    12641359                                        1000; 
    12651360 
    1266  
    12671361    /* Open the codec: */ 
    12681362 
     
    12801374        unsigned ptime; 
    12811375 
    1282         stream->enc_samples_per_frame = stream->codec_param.info.enc_ptime * 
    1283                                         stream->port.info.clock_rate / 1000; 
     1376        stream->enc_samples_per_pkt = stream->codec_param.info.enc_ptime * 
     1377                                      stream->port.info.clock_rate / 1000; 
    12841378 
    12851379        /* Set buffer size as twice the largest ptime value between 
     
    13041398 
    13051399    } else { 
    1306         stream->enc_samples_per_frame = stream->port.info.samples_per_frame; 
    1307     } 
     1400        stream->enc_samples_per_pkt = stream->port.info.samples_per_frame; 
     1401    } 
     1402 
    13081403 
    13091404    /* Initially disable the VAD in the stream, to help traverse NAT better */ 
     
    13221417 
    13231418 
     1419#if defined(PJMEDIA_HANDLE_G722_MPEG_BUG) && (PJMEDIA_HANDLE_G722_MPEG_BUG!=0) 
     1420    stream->rtp_rx_check_cnt = 5; 
     1421    stream->has_g722_mpeg_bug = PJ_FALSE; 
     1422    stream->rtp_rx_last_ts = 0; 
     1423    stream->rtp_rx_last_cnt = 0; 
     1424    stream->rtp_tx_samples_per_pkt = stream->enc_samples_per_pkt; 
     1425    stream->rtp_rx_samples_per_frame = stream->port.info.samples_per_frame; 
     1426 
    13241427    /* Init RTCP session: */ 
    13251428 
     1429    /* Special case for G.722 */ 
     1430    if (info->fmt.pt == PJMEDIA_RTP_PT_G722) { 
     1431        pjmedia_rtcp_init(&stream->rtcp, stream->port.info.name.ptr, 
     1432                          8000,  
     1433                          160, 
     1434                          info->ssrc); 
     1435        stream->has_g722_mpeg_bug = PJ_TRUE; 
     1436        /* RTP clock rate = 1/2 real clock rate */ 
     1437        stream->rtp_tx_samples_per_pkt >>= 1; 
     1438    } else { 
     1439        pjmedia_rtcp_init(&stream->rtcp, stream->port.info.name.ptr, 
     1440                          info->fmt.clock_rate,  
     1441                          stream->port.info.samples_per_frame,  
     1442                          info->ssrc); 
     1443    } 
     1444#else 
    13261445    pjmedia_rtcp_init(&stream->rtcp, stream->port.info.name.ptr, 
    13271446                      info->fmt.clock_rate,  
    13281447                      stream->port.info.samples_per_frame,  
    13291448                      info->ssrc); 
    1330  
     1449#endif 
    13311450 
    13321451    /* Init jitter buffer parameters: */ 
Note: See TracChangeset for help on using the changeset viewer.