Ignore:
Timestamp:
Dec 15, 2011 6:45:23 AM (12 years ago)
Author:
nanang
Message:

Close #1279: Implemented custom SDP format match for G.722.1 and AMR-NB/WB.

File:
1 edited

Legend:

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

    r3869 r3911  
    5353}; 
    5454 
    55 #define GET_FMTP_IVAL_BASE(ival, base, fmtp, param, default_val) \ 
    56     do { \ 
    57         pj_str_t s; \ 
    58         char *p; \ 
    59         p = pj_stristr(&fmtp.fmt_param, &param); \ 
    60         if (!p) { \ 
    61             ival = default_val; \ 
    62             break; \ 
    63         } \ 
    64         pj_strset(&s, p + param.slen, fmtp.fmt_param.slen - \ 
    65                   (p - fmtp.fmt_param.ptr) - param.slen); \ 
    66         ival = pj_strtoul2(&s, NULL, base); \ 
    67     } while (0) 
    68  
    69 #define GET_FMTP_IVAL(ival, fmtp, param, default_val) \ 
    70         GET_FMTP_IVAL_BASE(ival, 10, fmtp, param, default_val) 
    71  
    72  
    7355/* Definition of customized SDP format negotiation callback */ 
    7456struct fmt_match_cb_t 
     
    611593} 
    612594 
    613 /* Matching G722.1 bitrates between offer and answer. 
    614  */ 
    615 static pj_bool_t match_g7221( const pjmedia_sdp_media *offer, 
    616                               unsigned o_fmt_idx, 
    617                               const pjmedia_sdp_media *answer, 
    618                               unsigned a_fmt_idx) 
    619 { 
    620     const pjmedia_sdp_attr *attr_ans; 
    621     const pjmedia_sdp_attr *attr_ofr; 
    622     pjmedia_sdp_fmtp fmtp; 
    623     unsigned a_bitrate, o_bitrate; 
    624     const pj_str_t bitrate = {"bitrate=", 8}; 
    625  
    626     /* Parse offer */ 
    627     attr_ofr = pjmedia_sdp_media_find_attr2(offer, "fmtp",  
    628                                             &offer->desc.fmt[o_fmt_idx]); 
    629     if (!attr_ofr) 
    630         return PJ_FALSE; 
    631  
    632     if (pjmedia_sdp_attr_get_fmtp(attr_ofr, &fmtp) != PJ_SUCCESS) 
    633         return PJ_FALSE; 
    634  
    635     GET_FMTP_IVAL(o_bitrate, fmtp, bitrate, 0); 
    636  
    637     /* Parse answer */ 
    638     attr_ans = pjmedia_sdp_media_find_attr2(answer, "fmtp",  
    639                                             &answer->desc.fmt[a_fmt_idx]); 
    640     if (!attr_ans) 
    641         return PJ_FALSE; 
    642  
    643     if (pjmedia_sdp_attr_get_fmtp(attr_ans, &fmtp) != PJ_SUCCESS) 
    644         return PJ_FALSE; 
    645  
    646     GET_FMTP_IVAL(a_bitrate, fmtp, bitrate, 0); 
    647  
    648     /* Compare bitrate in answer and offer. */ 
    649     return (a_bitrate == o_bitrate); 
    650 } 
    651  
    652 /* Negotiate AMR format params between offer and answer. Format params 
    653  * to be matched are: octet-align, crc, robust-sorting, interleaving,  
    654  * and channels (channels is negotiated by rtpmap line negotiation).  
    655  * Note: For answerer, octet-align mode setting is adaptable to offerer  
    656  *       setting. In the case that octet-align mode need to be adjusted, 
    657  *       pt_need_adapt will be set to the format ID. 
    658  *        
    659  */ 
    660 static pj_bool_t match_amr( const pjmedia_sdp_media *offer, 
    661                             unsigned o_fmt_idx, 
    662                             const pjmedia_sdp_media *answer, 
    663                             unsigned a_fmt_idx, 
    664                             pj_bool_t answerer, 
    665                             pj_str_t *pt_need_adapt) 
    666 { 
    667     /* Negotiated format-param field-names constants. */ 
    668     const pj_str_t STR_OCTET_ALIGN      = {"octet-align=", 12}; 
    669     const pj_str_t STR_CRC              = {"crc=", 4}; 
    670     const pj_str_t STR_ROBUST_SORTING   = {"robust-sorting=", 15}; 
    671     const pj_str_t STR_INTERLEAVING     = {"interleaving=", 13}; 
    672  
    673     /* Negotiated params and their default values. */ 
    674     unsigned a_octet_align = 0, o_octet_align = 0; 
    675     unsigned a_crc = 0, o_crc = 0; 
    676     unsigned a_robust_sorting = 0, o_robust_sorting = 0; 
    677     unsigned a_interleaving = 0, o_interleaving = 0; 
    678  
    679     const pjmedia_sdp_attr *attr_ans; 
    680     const pjmedia_sdp_attr *attr_ofr; 
    681     pjmedia_sdp_fmtp fmtp; 
    682     pj_bool_t match; 
    683  
    684     /* Parse offerer FMTP */ 
    685     attr_ofr = pjmedia_sdp_media_find_attr2(offer, "fmtp",  
    686                                             &offer->desc.fmt[o_fmt_idx]); 
    687     if (attr_ofr) { 
    688         if (pjmedia_sdp_attr_get_fmtp(attr_ofr, &fmtp) != PJ_SUCCESS) 
    689             /* Invalid fmtp format. */ 
    690             return PJ_FALSE; 
    691  
    692         GET_FMTP_IVAL(o_octet_align, fmtp, STR_OCTET_ALIGN, 0); 
    693         GET_FMTP_IVAL(o_crc, fmtp, STR_CRC, 0); 
    694         GET_FMTP_IVAL(o_robust_sorting, fmtp, STR_ROBUST_SORTING, 0); 
    695         GET_FMTP_IVAL(o_interleaving, fmtp, STR_INTERLEAVING, 0); 
    696     } 
    697  
    698     /* Parse answerer FMTP */ 
    699     attr_ans = pjmedia_sdp_media_find_attr2(answer, "fmtp",  
    700                                             &answer->desc.fmt[a_fmt_idx]); 
    701     if (attr_ans) { 
    702         if (pjmedia_sdp_attr_get_fmtp(attr_ans, &fmtp) != PJ_SUCCESS) 
    703             /* Invalid fmtp format. */ 
    704             return PJ_FALSE; 
    705  
    706         GET_FMTP_IVAL(a_octet_align, fmtp, STR_OCTET_ALIGN, 0); 
    707         GET_FMTP_IVAL(a_crc, fmtp, STR_CRC, 0); 
    708         GET_FMTP_IVAL(a_robust_sorting, fmtp, STR_ROBUST_SORTING, 0); 
    709         GET_FMTP_IVAL(a_interleaving, fmtp, STR_INTERLEAVING, 0); 
    710     } 
    711  
    712     if (answerer) { 
    713         match = a_crc == o_crc && 
    714                 a_robust_sorting == o_robust_sorting && 
    715                 a_interleaving == o_interleaving; 
    716  
    717         /* If answerer octet-align setting doesn't match to the offerer's,  
    718          * set pt_need_adapt to this media format ID to signal the caller 
    719          * that this format ID needs to be adjusted. 
    720          */ 
    721         if (a_octet_align != o_octet_align && match) { 
    722             pj_assert(pt_need_adapt != NULL); 
    723             *pt_need_adapt = answer->desc.fmt[a_fmt_idx]; 
    724         } 
    725     } else { 
    726         match = (a_octet_align == o_octet_align && 
    727                  a_crc == o_crc && 
    728                  a_robust_sorting == o_robust_sorting && 
    729                  a_interleaving == o_interleaving); 
    730     } 
    731  
    732     return match; 
    733 } 
    734  
    735  
    736 /* Toggle AMR octet-align setting in the fmtp. 
    737  */ 
    738 static pj_status_t amr_toggle_octet_align(pj_pool_t *pool, 
    739                                           pjmedia_sdp_media *media, 
    740                                           unsigned fmt_idx) 
    741 { 
    742     pjmedia_sdp_attr *attr; 
    743     pjmedia_sdp_fmtp fmtp; 
    744     const pj_str_t STR_OCTET_ALIGN = {"octet-align=", 12}; 
    745      
    746     enum { MAX_FMTP_STR_LEN = 160 }; 
    747  
    748     attr = pjmedia_sdp_media_find_attr2(media, "fmtp",  
    749                                         &media->desc.fmt[fmt_idx]); 
    750     /* Check if the AMR media format has FMTP attribute */ 
    751     if (attr) { 
    752         char *p; 
    753         pj_status_t status; 
    754  
    755         status = pjmedia_sdp_attr_get_fmtp(attr, &fmtp); 
    756         if (status != PJ_SUCCESS) 
    757             return status; 
    758  
    759         /* Check if the fmtp has octet-align field. */ 
    760         p = pj_stristr(&fmtp.fmt_param, &STR_OCTET_ALIGN); 
    761         if (p) { 
    762             /* It has, just toggle the value */ 
    763             unsigned octet_align; 
    764             pj_str_t s; 
    765  
    766             pj_strset(&s, p + STR_OCTET_ALIGN.slen, fmtp.fmt_param.slen - 
    767                       (p - fmtp.fmt_param.ptr) - STR_OCTET_ALIGN.slen); 
    768             octet_align = pj_strtoul(&s); 
    769             *(p + STR_OCTET_ALIGN.slen) = (char)(octet_align? '0' : '1'); 
    770         } else { 
    771             /* It doesn't, append octet-align field */ 
    772             char buf[MAX_FMTP_STR_LEN]; 
    773  
    774             pj_ansi_snprintf(buf, MAX_FMTP_STR_LEN, "%.*s;octet-align=1", 
    775                              (int)fmtp.fmt_param.slen, fmtp.fmt_param.ptr); 
    776             attr->value = pj_strdup3(pool, buf); 
    777         } 
    778     } else { 
    779         /* Add new attribute for the AMR media format with octet-align  
    780          * field set. 
    781          */ 
    782         char buf[MAX_FMTP_STR_LEN]; 
    783  
    784         attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr); 
    785         attr->name = pj_str("fmtp"); 
    786         pj_ansi_snprintf(buf, MAX_FMTP_STR_LEN, "%.*s octet-align=1", 
    787                          (int)media->desc.fmt[fmt_idx].slen, 
    788                          media->desc.fmt[fmt_idx].ptr); 
    789         attr->value = pj_strdup3(pool, buf); 
    790         media->attr[media->attr_count++] = attr; 
    791     } 
    792  
    793     return PJ_SUCCESS; 
    794 } 
    795  
    796595 
    797596/* Update single local media description to after receiving answer 
     
    931730                             (ar.param.slen==1 && *ar.param.ptr=='1'))) 
    932731                        { 
    933                             /* Further check for G7221, negotiate bitrate. */ 
    934                             if (pj_stricmp2(&or_.enc_name, "G7221") == 0) 
    935                             { 
    936                                 if (match_g7221(offer, i, answer, j)) 
    937                                     break; 
    938                             } else 
    939  
    940                             /* Further check for AMR, negotiate fmtp. */ 
    941                             if (pj_stricmp2(&or_.enc_name, "AMR") == 0 || 
    942                                 pj_stricmp2(&or_.enc_name, "AMR-WB") == 0)  
    943                             { 
    944                                 if (match_amr(offer, i, answer, j, PJ_FALSE,  
    945                                               NULL)) 
    946                                     break; 
    947                             } else 
    948                              
    949732                            /* Call custom format matching callbacks */ 
    950733                            if (custom_fmt_match(pool, &or_.enc_name, 
     
    12181001    pjmedia_sdp_media *answer; 
    12191002    const pjmedia_sdp_media *master, *slave; 
    1220     pj_str_t pt_amr_need_adapt = {NULL, 0}; 
    12211003 
    12221004    /* If offer has zero port, just clone the offer */ 
     
    13551137                                { 
    13561138                                    continue; 
    1357                                 } else 
    1358  
    1359                                 /* Further check for G7221, negotiate bitrate */ 
    1360                                 if (pj_stricmp2(&or_.enc_name, "G7221") == 0 && 
    1361                                     !match_g7221(master, i, slave, j)) 
    1362                                 { 
    1363                                     continue; 
    1364                                 } else 
    1365  
    1366                                 /* Further check for AMR, negotiate fmtp */ 
    1367                                 if (pj_stricmp2(&or_.enc_name, "AMR")==0 || 
    1368                                     pj_stricmp2(&or_.enc_name, "AMR-WB")==0)  
    1369                                 { 
    1370                                     unsigned o_med_idx, a_med_idx; 
    1371  
    1372                                     o_med_idx = prefer_remote_codec_order? i:j; 
    1373                                     a_med_idx = prefer_remote_codec_order? j:i; 
    1374                                     if (!match_amr(offer, o_med_idx,  
    1375                                                    preanswer, a_med_idx, 
    1376                                                    PJ_TRUE, &pt_amr_need_adapt)) 
    1377                                         continue; 
    13781139                                } 
    1379  
    13801140                                found_matching_codec = 1; 
    13811141                            } else { 
     
    14541214        pj_assert(j != answer->desc.fmt_count); 
    14551215        str_swap(&answer->desc.fmt[i], &answer->desc.fmt[j]); 
    1456          
    1457         /* For AMR/AMRWB format, adapt octet-align setting if required. */ 
    1458         if (!pj_strcmp(&pt_amr_need_adapt, &pt_answer[i])) 
    1459             amr_toggle_octet_align(pool, answer, i); 
    14601216    } 
    14611217     
     
    17841540    } 
    17851541 
    1786     /* Further check for G7221, negotiate bitrate. */ 
    1787     if (pj_stricmp2(&o_rtpmap.enc_name, "G7221") == 0) { 
    1788         if (match_g7221(offer, o_fmt_idx, answer, a_fmt_idx)) 
    1789             return PJ_SUCCESS; 
    1790         else 
    1791             return PJMEDIA_SDP_EFORMATNOTEQUAL; 
    1792     } else 
    1793     /* Further check for AMR, negotiate fmtp. */ 
    1794     if (pj_stricmp2(&o_rtpmap.enc_name, "AMR") == 0 || 
    1795         pj_stricmp2(&o_rtpmap.enc_name, "AMR-WB") == 0)  
    1796     { 
    1797         if (match_amr(offer, o_fmt_idx, answer, a_fmt_idx, PJ_FALSE, NULL)) 
    1798             return PJ_SUCCESS; 
    1799         else 
    1800             return PJMEDIA_SDP_EFORMATNOTEQUAL; 
    1801     } 
    1802     PJ_TODO(replace_hardcoded_fmt_match_in_sdp_neg_with_custom_fmt_match_cb); 
    1803      
    18041542    return custom_fmt_match(pool, &o_rtpmap.enc_name, 
    18051543                            offer, o_fmt_idx, answer, a_fmt_idx, option); 
Note: See TracChangeset for help on using the changeset viewer.