Changeset 6103


Ignore:
Timestamp:
Nov 8, 2019 10:17:16 AM (10 days ago)
Author:
nanang
Message:

Close #2088: Generate and negotiate telephone-event with multiple clock-rates in SDP offer/answer.

Location:
pjproject/trunk/pjmedia/src
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjmedia/src/pjmedia/endpoint.c

    r5311 r6103  
    417417    unsigned max_bitrate = 0; 
    418418    pj_status_t status; 
     419#if defined(PJMEDIA_RTP_PT_TELEPHONE_EVENTS) && \ 
     420            PJMEDIA_RTP_PT_TELEPHONE_EVENTS != 0 
     421    unsigned televent_num = 0; 
     422    unsigned televent_clockrates[8]; 
     423    unsigned used_pt_num = 0; 
     424    unsigned used_pt[PJMEDIA_MAX_SDP_FMT]; 
     425#endif 
    419426 
    420427    PJ_UNUSED_ARG(options); 
     
    541548        if (max_bitrate < codec_param.info.max_bps) 
    542549            max_bitrate = codec_param.info.max_bps; 
    543     } 
    544  
     550 
     551        /* List clock rate & channel count of audio codecs for generating 
     552         * telephone-event later. 
     553         */ 
    545554#if defined(PJMEDIA_RTP_PT_TELEPHONE_EVENTS) && \ 
    546     PJMEDIA_RTP_PT_TELEPHONE_EVENTS != 0 
     555            PJMEDIA_RTP_PT_TELEPHONE_EVENTS != 0 
     556        { 
     557            unsigned j; 
     558 
     559            /* Take a note of used dynamic PT */ 
     560            if (codec_info->pt >= 96) 
     561                used_pt[used_pt_num++] = codec_info->pt; 
     562 
     563            for (j=0; j<televent_num; ++j) { 
     564                if (televent_clockrates[j] == rtpmap.clock_rate) 
     565                    break; 
     566            } 
     567            if (j==televent_num && 
     568                televent_num<PJ_ARRAY_SIZE(televent_clockrates)) 
     569            { 
     570                /* List this clockrate for tel-event generation */ 
     571                televent_clockrates[televent_num++] = rtpmap.clock_rate; 
     572            } 
     573        } 
     574#endif 
     575    } 
     576 
     577#if defined(PJMEDIA_RTP_PT_TELEPHONE_EVENTS) && \ 
     578            PJMEDIA_RTP_PT_TELEPHONE_EVENTS != 0 
    547579    /* 
    548580     * Add support telephony event 
    549581     */ 
    550582    if (endpt->has_telephone_event) { 
    551         m->desc.fmt[m->desc.fmt_count++] = 
    552             pj_str(PJMEDIA_RTP_PT_TELEPHONE_EVENTS_STR); 
    553  
    554         /* Add rtpmap. */ 
    555         attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr); 
    556         attr->name = pj_str("rtpmap"); 
    557         attr->value = pj_str(PJMEDIA_RTP_PT_TELEPHONE_EVENTS_STR 
    558                              " telephone-event/8000"); 
    559         m->attr[m->attr_count++] = attr; 
    560  
    561         /* Add fmtp */ 
    562         attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr); 
    563         attr->name = pj_str("fmtp"); 
     583        for (i=0; i<televent_num; i++) { 
     584            char buf[160]; 
     585            unsigned j = 0; 
     586            unsigned pt = PJMEDIA_RTP_PT_TELEPHONE_EVENTS; 
     587 
     588            /* Find PT for this tel-event */ 
     589            while (j < used_pt_num && pt <= 127) { 
     590                if (pt == used_pt[j]) { 
     591                    pt++; 
     592                    j = 0; 
     593                } else { 
     594                    j++; 
     595                } 
     596            } 
     597            if (pt > 127) { 
     598                /* No more available PT */ 
     599                break; 
     600            } 
     601            used_pt[used_pt_num++] = pt; 
     602 
     603            /* Print tel-event PT */ 
     604            pj_ansi_snprintf(buf, sizeof(buf), "%d", pt); 
     605            m->desc.fmt[m->desc.fmt_count++] = pj_strdup3(pool, buf); 
     606 
     607            /* Add rtpmap. */ 
     608            attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr); 
     609            attr->name = pj_str("rtpmap"); 
     610            pj_ansi_snprintf(buf, sizeof(buf), "%d telephone-event/%d", 
     611                             pt, televent_clockrates[i]); 
     612            attr->value = pj_strdup3(pool, buf); 
     613            m->attr[m->attr_count++] = attr; 
     614 
     615            /* Add fmtp */ 
     616            attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr); 
     617            attr->name = pj_str("fmtp"); 
    564618#if defined(PJMEDIA_HAS_DTMF_FLASH) && PJMEDIA_HAS_DTMF_FLASH!= 0 
    565         attr->value = pj_str(PJMEDIA_RTP_PT_TELEPHONE_EVENTS_STR " 0-16"); 
     619            pj_ansi_snprintf(buf, sizeof(buf), "%d 0-16", pt); 
    566620#else 
    567         attr->value = pj_str(PJMEDIA_RTP_PT_TELEPHONE_EVENTS_STR " 0-15"); 
     621            pj_ansi_snprintf(buf, sizeof(buf), "%d 0-15", pt); 
    568622#endif 
    569         m->attr[m->attr_count++] = attr; 
     623            attr->value = pj_strdup3(pool, buf); 
     624            m->attr[m->attr_count++] = attr; 
     625        } 
    570626    } 
    571627#endif 
  • pjproject/trunk/pjmedia/src/pjmedia/sdp_neg.c

    r5828 r6103  
    10711071    pjmedia_sdp_media *answer; 
    10721072    const pjmedia_sdp_media *master, *slave; 
     1073    unsigned nclockrate = 0, clockrate[PJMEDIA_MAX_SDP_FMT]; 
    10731074 
    10741075    /* If offer has zero port, just clone the offer */ 
     
    11311132                    p = pj_strtoul(&slave->desc.fmt[j]); 
    11321133                    if (p == pt && pj_isdigit(*slave->desc.fmt[j].ptr)) { 
     1134                        unsigned k; 
     1135 
    11331136                        found_matching_codec = 1; 
    11341137                        pt_offer[pt_answer_count] = slave->desc.fmt[j]; 
    11351138                        pt_answer[pt_answer_count++] = slave->desc.fmt[j]; 
     1139 
     1140                        /* Take note of clock rate for tel-event. Note: for 
     1141                         * static PT, we assume the clock rate is 8000. 
     1142                         */ 
     1143                        for (k=0; k<nclockrate; ++k) 
     1144                            if (clockrate[k] == 8000) 
     1145                                break; 
     1146                        if (k == nclockrate) 
     1147                            clockrate[nclockrate++] = 8000; 
    11361148                        break; 
    11371149                    } 
     
    11451157                const pjmedia_sdp_attr *a; 
    11461158                pjmedia_sdp_rtpmap or_; 
    1147                 pj_bool_t is_codec; 
     1159                pj_bool_t is_codec = 0; 
    11481160 
    11491161                /* Get the rtpmap for the payload type in the master. */ 
     
    11561168                pjmedia_sdp_attr_get_rtpmap(a, &or_); 
    11571169 
    1158                 if (!pj_stricmp2(&or_.enc_name, "telephone-event")) { 
    1159                     if (found_matching_telephone_event) 
    1160                         continue; 
    1161                     is_codec = 0; 
    1162                 } else { 
     1170                if (pj_stricmp2(&or_.enc_name, "telephone-event")) { 
    11631171                    master_has_codec = 1; 
    11641172                    if (!answer_with_multiple_codecs && found_matching_codec) 
     
    11921200                                pjmedia_sdp_media *o_med, *a_med; 
    11931201                                unsigned o_fmt_idx, a_fmt_idx; 
     1202                                unsigned k; 
    11941203 
    11951204                                o_med = (pjmedia_sdp_media*)offer; 
     
    12081217                                } 
    12091218                                found_matching_codec = 1; 
     1219 
     1220                                /* Take note of clock rate for tel-event */ 
     1221                                for (k=0; k<nclockrate; ++k) 
     1222                                    if (clockrate[k] == or_.clock_rate) 
     1223                                        break; 
     1224                                if (k == nclockrate) 
     1225                                    clockrate[nclockrate++] = or_.clock_rate; 
    12101226                            } else { 
    12111227                                found_matching_telephone_event = 1; 
     
    12701286    } 
    12711287 
    1272     /* Seems like everything is in order. 
    1273      * Build the answer by cloning from preanswer, but rearrange the payload 
     1288    /* Seems like everything is in order. */ 
     1289 
     1290    /* Remove unwanted telephone-event formats. */ 
     1291    if (found_matching_telephone_event) { 
     1292        pj_str_t first_televent_offer = {0}; 
     1293        pj_str_t first_televent_answer = {0}; 
     1294        unsigned matched_cnt = 0; 
     1295 
     1296        for (i=0; i<pt_answer_count; ) { 
     1297            const pjmedia_sdp_attr *a; 
     1298            pjmedia_sdp_rtpmap r; 
     1299            unsigned j; 
     1300 
     1301            /* Skip static PT, as telephone-event uses dynamic PT */ 
     1302            if (!pj_isdigit(*pt_answer[i].ptr) || pj_strtol(&pt_answer[i])<96) 
     1303            { 
     1304                ++i; 
     1305                continue; 
     1306            } 
     1307 
     1308            /* Get the rtpmap for format. */ 
     1309            a = pjmedia_sdp_media_find_attr2(preanswer, "rtpmap", 
     1310                                             &pt_answer[i]); 
     1311            pj_assert(a); 
     1312            pjmedia_sdp_attr_get_rtpmap(a, &r); 
     1313 
     1314            /* Only care for telephone-event format */ 
     1315            if (pj_stricmp2(&r.enc_name, "telephone-event")) { 
     1316                ++i; 
     1317                continue; 
     1318            } 
     1319 
     1320            if (first_televent_offer.slen == 0) { 
     1321                first_televent_offer = pt_offer[i]; 
     1322                first_televent_answer = pt_answer[i]; 
     1323            } 
     1324 
     1325            for (j=0; j<nclockrate; ++j) { 
     1326                if (r.clock_rate==clockrate[j]) 
     1327                    break; 
     1328            } 
     1329 
     1330            /* This tel-event's clockrate is unwanted, remove the tel-event */ 
     1331            if (j==nclockrate) { 
     1332                pj_array_erase(pt_answer, sizeof(pt_answer[0]), 
     1333                               pt_answer_count, i); 
     1334                pj_array_erase(pt_offer, sizeof(pt_offer[0]), 
     1335                               pt_answer_count, i); 
     1336                pt_answer_count--; 
     1337            } else { 
     1338                ++matched_cnt; 
     1339                ++i; 
     1340            } 
     1341        } 
     1342 
     1343        /* Tel-event is wanted, but no matched clock rate (to the selected 
     1344         * audio codec), just put back any first matched tel-event formats. 
     1345         */ 
     1346        if (!matched_cnt) { 
     1347            pt_offer[pt_answer_count] = first_televent_offer; 
     1348            pt_answer[pt_answer_count++] = first_televent_answer; 
     1349        } 
     1350    } 
     1351 
     1352    /* Build the answer by cloning from preanswer, and reorder the payload 
    12741353     * to suit the offer. 
    12751354     */ 
  • pjproject/trunk/pjmedia/src/test/sdp_neg_test.c

    r5619 r6103  
    12461246    }, 
    12471247 
     1248    /* test 17: */ 
     1249    { 
     1250        /********************************************************************* 
     1251         * Ticket #2088: : Handle multiple telephone-event formats. 
     1252         */ 
     1253 
     1254        "Ticket #2088: Handle multiple telephone-event formats", 
     1255        2, 
     1256        { 
     1257          { 
     1258            REMOTE_OFFER, 
     1259            /* Bob sends offer: */ 
     1260            "v=0\r\n" 
     1261            "o=bob 2808844564 2808844563 IN IP4 host.biloxi.example.com\r\n" 
     1262            "s=bob\r\n" 
     1263            "c=IN IP4 host.biloxi.example.com\r\n" 
     1264            "t=0 0\r\n" 
     1265            "m=audio 3000 RTP/AVP 97 0 98 99\r\n" 
     1266            "a=rtpmap:97 Speex/16000\r\n" 
     1267            "a=rtpmap:0 PCMU/8000\r\n" 
     1268            "a=rtpmap:98 telephone-event/8000\r\n" 
     1269            "a=rtpmap:99 telephone-event/16000\r\n" 
     1270            "", 
     1271            /* Alice initial capability: */ 
     1272            "v=0\r\n" 
     1273            "o=alice 2890844526 2890844526 IN IP4 host.atlanta.example.com\r\n" 
     1274            "s=alice\r\n" 
     1275            "c=IN IP4 host.atlanta.example.com\r\n" 
     1276            "t=0 0\r\n" 
     1277            "m=audio 4000 RTP/AVP 0 100 96 98\r\n" 
     1278            "a=rtpmap:0 PCMU/8000\r\n" 
     1279            "a=rtpmap:100 Speex/16000\r\n" 
     1280            "a=rtpmap:96 telephone-event/8000\r\n" 
     1281            "a=rtpmap:98 telephone-event/16000\r\n" 
     1282            "", 
     1283            /* Alice's local SDP should be: */ 
     1284            "v=0\r\n" 
     1285            "o=alice 2890844526 2890844527 IN IP4 host.atlanta.example.com\r\n" 
     1286            "s=alice\r\n" 
     1287            "c=IN IP4 host.atlanta.example.com\r\n" 
     1288            "t=0 0\r\n" 
     1289            "m=audio 4000 RTP/AVP 97 99\r\n" 
     1290            "a=rtpmap:97 Speex/16000\r\n" 
     1291            "a=rtpmap:99 telephone-event/16000\r\n" 
     1292            "", 
     1293          }, 
     1294          { 
     1295            LOCAL_OFFER, 
     1296            /* Alice updates offer */ 
     1297            "v=0\r\n" 
     1298            "o=alice 2890844526 2890844528 IN IP4 host.atlanta.example.com\r\n" 
     1299            "s=alice\r\n" 
     1300            "c=IN IP4 host.atlanta.example.com\r\n" 
     1301            "t=0 0\r\n" 
     1302            "m=audio 4000 RTP/AVP 0 97 98 99\r\n" 
     1303            "a=rtpmap:0 PCMU/8000\r\n" 
     1304            "a=rtpmap:97 Speex/16000\r\n" 
     1305            "a=rtpmap:98 telephone-event/8000\r\n" 
     1306            "a=rtpmap:99 telephone-event/16000\r\n" 
     1307            "", 
     1308            /* Receive Bob's answer: */ 
     1309            "v=0\r\n" 
     1310            "o=bob 2808844564 2808844563 IN IP4 host.biloxi.example.com\r\n" 
     1311            "s=bob\r\n" 
     1312            "c=IN IP4 host.biloxi.example.com\r\n" 
     1313            "t=0 0\r\n" 
     1314            "m=audio 3000 RTP/AVP 99 100\r\n" 
     1315            "a=rtpmap:99 Speex/16000\r\n" 
     1316            "a=rtpmap:100 telephone-event/16000\r\n" 
     1317            "", 
     1318            /* Alice's local SDP should be: */ 
     1319            "v=0\r\n" 
     1320            "o=alice 2890844526 2890844528 IN IP4 host.atlanta.example.com\r\n" 
     1321            "s=alice\r\n" 
     1322            "c=IN IP4 host.atlanta.example.com\r\n" 
     1323            "t=0 0\r\n" 
     1324            "m=audio 4000 RTP/AVP 97 99\r\n" 
     1325            "a=rtpmap:97 Speex/16000\r\n" 
     1326            "a=rtpmap:99 telephone-event/16000\r\n" 
     1327            "", 
     1328          } 
     1329        } 
     1330    }, 
     1331 
    12481332}; 
    12491333 
Note: See TracChangeset for help on using the changeset viewer.