Changeset 2364 for pjproject/trunk
- Timestamp:
- Nov 11, 2008 11:51:18 AM (16 years ago)
- Location:
- pjproject/trunk
- Files:
-
- 3 added
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjmedia/src/pjmedia/sdp_neg.c
r2236 r2364 52 52 }; 53 53 54 #define GET_FMTP_IVAL(ival, fmtp, param, default_val) \ 55 do { \ 56 pj_str_t s; \ 57 char *p; \ 58 p = pj_stristr(&fmtp.fmt_param, ¶m); \ 59 if (!p) { \ 60 ival = default_val; \ 61 break; \ 62 } \ 63 pj_strset(&s, p + param.slen, fmtp.fmt_param.slen - \ 64 (p - fmtp.fmt_param.ptr) - param.slen); \ 65 ival = pj_strtoul(&s); \ 66 } while (0) 67 54 68 /* 55 69 * Get string representation of negotiator state. … … 541 555 unsigned a_fmt_idx) 542 556 { 543 const pjmedia_sdp_attr *a _ans;544 const pjmedia_sdp_attr *a _off;557 const pjmedia_sdp_attr *attr_ans; 558 const pjmedia_sdp_attr *attr_ofr; 545 559 pjmedia_sdp_fmtp fmtp; 546 unsigned a_bitrate = 0, o_bitrate = 0;560 unsigned a_bitrate, o_bitrate; 547 561 const pj_str_t bitrate = {"bitrate=", 8}; 548 const char *p; 549 550 a _ans = pjmedia_sdp_media_find_attr2(answer, "fmtp",551 &answer->desc.fmt[a_fmt_idx]);552 if (!a _ans)562 563 /* Parse offer */ 564 attr_ofr = pjmedia_sdp_media_find_attr2(offer, "fmtp", 565 &offer->desc.fmt[o_fmt_idx]); 566 if (!attr_ofr) 553 567 return PJ_FALSE; 554 568 555 if (pjmedia_sdp_attr_get_fmtp(a _ans, &fmtp) != PJ_SUCCESS)569 if (pjmedia_sdp_attr_get_fmtp(attr_ofr, &fmtp) != PJ_SUCCESS) 556 570 return PJ_FALSE; 557 571 558 p = pj_stristr(&fmtp.fmt_param, &bitrate); 559 if (p == NULL) 572 GET_FMTP_IVAL(o_bitrate, fmtp, bitrate, 0); 573 574 /* Parse answer */ 575 attr_ans = pjmedia_sdp_media_find_attr2(answer, "fmtp", 576 &answer->desc.fmt[a_fmt_idx]); 577 if (!attr_ans) 560 578 return PJ_FALSE; 561 579 562 a_bitrate = atoi(p + bitrate.slen); 563 564 a_off = pjmedia_sdp_media_find_attr2(offer, "fmtp", 565 &offer->desc.fmt[o_fmt_idx]); 566 if (!a_off) 580 if (pjmedia_sdp_attr_get_fmtp(attr_ans, &fmtp) != PJ_SUCCESS) 567 581 return PJ_FALSE; 568 582 569 if (pjmedia_sdp_attr_get_fmtp(a_off, &fmtp) != PJ_SUCCESS) 570 return PJ_FALSE; 571 572 p = pj_stristr(&fmtp.fmt_param, &bitrate); 573 if (p == NULL) 574 return PJ_FALSE; 575 576 o_bitrate = atoi(p + bitrate.slen); 577 583 GET_FMTP_IVAL(a_bitrate, fmtp, bitrate, 0); 584 585 /* Compare bitrate in answer and offer. */ 578 586 return (a_bitrate == o_bitrate); 579 587 } 588 589 /* Negotiate AMR format params between offer and answer. Format params 590 * to be matched are: octet-align, crc, robust-sorting, interleaving, 591 * and channels (channels is negotiated by rtpmap line negotiation). 592 * Note: For answerer, octet-align mode setting is adaptable to offerer 593 * setting. In the case that octet-align mode need to be adjusted, 594 * pt_need_adapt will be set to the format ID. 595 * 596 */ 597 static pj_bool_t match_amr( const pjmedia_sdp_media *offer, 598 unsigned o_fmt_idx, 599 const pjmedia_sdp_media *answer, 600 unsigned a_fmt_idx, 601 pj_bool_t answerer, 602 pj_str_t *pt_need_adapt) 603 { 604 /* Negotiated format-param field-names constants. */ 605 const pj_str_t STR_OCTET_ALIGN = {"octet-align=", 12}; 606 const pj_str_t STR_CRC = {"crc=", 4}; 607 const pj_str_t STR_ROBUST_SORTING = {"robust-sorting=", 15}; 608 const pj_str_t STR_INTERLEAVING = {"interleaving=", 13}; 609 610 /* Negotiated params and their default values. */ 611 unsigned a_octet_align = 0, o_octet_align = 0; 612 unsigned a_crc = 0, o_crc = 0; 613 unsigned a_robust_sorting = 0, o_robust_sorting = 0; 614 unsigned a_interleaving = 0, o_interleaving = 0; 615 616 const pjmedia_sdp_attr *attr_ans; 617 const pjmedia_sdp_attr *attr_ofr; 618 pjmedia_sdp_fmtp fmtp; 619 pj_bool_t match; 620 621 /* Parse offerer FMTP */ 622 attr_ofr = pjmedia_sdp_media_find_attr2(offer, "fmtp", 623 &offer->desc.fmt[o_fmt_idx]); 624 if (attr_ofr) { 625 if (pjmedia_sdp_attr_get_fmtp(attr_ofr, &fmtp) != PJ_SUCCESS) 626 /* Invalid fmtp format. */ 627 return PJ_FALSE; 628 629 GET_FMTP_IVAL(o_octet_align, fmtp, STR_OCTET_ALIGN, 0); 630 GET_FMTP_IVAL(o_crc, fmtp, STR_CRC, 0); 631 GET_FMTP_IVAL(o_robust_sorting, fmtp, STR_ROBUST_SORTING, 0); 632 GET_FMTP_IVAL(o_interleaving, fmtp, STR_INTERLEAVING, 0); 633 } 634 635 /* Parse answerer FMTP */ 636 attr_ans = pjmedia_sdp_media_find_attr2(answer, "fmtp", 637 &answer->desc.fmt[a_fmt_idx]); 638 if (attr_ans) { 639 if (pjmedia_sdp_attr_get_fmtp(attr_ans, &fmtp) != PJ_SUCCESS) 640 /* Invalid fmtp format. */ 641 return PJ_FALSE; 642 643 GET_FMTP_IVAL(a_octet_align, fmtp, STR_OCTET_ALIGN, 0); 644 GET_FMTP_IVAL(a_crc, fmtp, STR_CRC, 0); 645 GET_FMTP_IVAL(a_robust_sorting, fmtp, STR_ROBUST_SORTING, 0); 646 GET_FMTP_IVAL(a_interleaving, fmtp, STR_INTERLEAVING, 0); 647 } 648 649 if (answerer) { 650 match = a_crc == o_crc && 651 a_robust_sorting == o_robust_sorting && 652 a_interleaving == o_interleaving; 653 654 /* If answerer octet-align setting doesn't match to the offerer's, 655 * set pt_need_adapt to this media format ID to signal the caller 656 * that this format ID needs to be adjusted. 657 */ 658 if (a_octet_align != o_octet_align && match) { 659 pj_assert(pt_need_adapt != NULL); 660 *pt_need_adapt = answer->desc.fmt[a_fmt_idx]; 661 } 662 } else { 663 match = (a_octet_align == o_octet_align && 664 a_crc == o_crc && 665 a_robust_sorting == o_robust_sorting && 666 a_interleaving == o_interleaving); 667 } 668 669 return match; 670 } 671 672 673 /* Toggle AMR octet-align setting in the fmtp. 674 */ 675 static pj_status_t amr_toggle_octet_align(pj_pool_t *pool, 676 pjmedia_sdp_media *media, 677 unsigned fmt_idx) 678 { 679 pjmedia_sdp_attr *attr; 680 pjmedia_sdp_fmtp fmtp; 681 const pj_str_t STR_OCTET_ALIGN = {"octet-align=", 12}; 682 683 enum { MAX_FMTP_STR_LEN = 160 }; 684 685 attr = pjmedia_sdp_media_find_attr2(media, "fmtp", 686 &media->desc.fmt[fmt_idx]); 687 /* Check if the AMR media format has FMTP attribute */ 688 if (attr) { 689 char *p; 690 pj_status_t status; 691 692 status = pjmedia_sdp_attr_get_fmtp(attr, &fmtp); 693 if (status != PJ_SUCCESS) 694 return status; 695 696 /* Check if the fmtp has octet-align field. */ 697 p = pj_stristr(&fmtp.fmt_param, &STR_OCTET_ALIGN); 698 if (p) { 699 /* It has, just toggle the value */ 700 unsigned octet_align; 701 pj_str_t s; 702 703 pj_strset(&s, p + STR_OCTET_ALIGN.slen, fmtp.fmt_param.slen - 704 (p - fmtp.fmt_param.ptr) - STR_OCTET_ALIGN.slen); 705 octet_align = pj_strtoul(&s); 706 *(p + STR_OCTET_ALIGN.slen) = (char)(octet_align? '0' : '1'); 707 } else { 708 /* It doesn't, append octet-align field */ 709 char buf[MAX_FMTP_STR_LEN]; 710 711 pj_ansi_snprintf(buf, MAX_FMTP_STR_LEN, "%.*s;octet-align=1", 712 (int)fmtp.fmt_param.slen, fmtp.fmt_param.ptr); 713 attr->value = pj_strdup3(pool, buf); 714 } 715 } else { 716 /* Add new attribute for the AMR media format with octet-align 717 * field set. 718 */ 719 char buf[MAX_FMTP_STR_LEN]; 720 721 attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr); 722 attr->name = pj_str("fmtp"); 723 pj_ansi_snprintf(buf, MAX_FMTP_STR_LEN, "%.*s octet-align=1", 724 (int)media->desc.fmt[fmt_idx].slen, 725 media->desc.fmt[fmt_idx].ptr); 726 attr->value = pj_strdup3(pool, buf); 727 media->attr[media->attr_count++] = attr; 728 } 729 730 return PJ_SUCCESS; 731 } 732 580 733 581 734 /* Update single local media description to after receiving answer … … 707 860 if (match_g7221(offer, i, answer, j)) 708 861 break; 862 } else 863 /* Further check for AMR, negotiate fmtp. */ 864 if (pj_strcmp2(&or_.enc_name, "AMR") == 0) { 865 if (match_amr(offer, i, answer, j, PJ_FALSE, 866 NULL)) 867 break; 709 868 } else { 710 869 /* Match! */ … … 819 978 /* Try to match offer with answer. */ 820 979 static pj_status_t match_offer(pj_pool_t *pool, 980 pj_bool_t prefer_remote_codec_order, 821 981 const pjmedia_sdp_media *offer, 822 982 const pjmedia_sdp_media *preanswer, 823 const pjmedia_sdp_media *orig_local,824 983 pjmedia_sdp_media **p_answer) 825 984 { 826 985 unsigned i; 827 pj_bool_t offer_has_codec = 0,828 offer_has_telephone_event = 0,829 offer_has_other = 0,986 pj_bool_t master_has_codec = 0, 987 master_has_telephone_event = 0, 988 master_has_other = 0, 830 989 found_matching_codec = 0, 831 990 found_matching_telephone_event = 0, … … 834 993 pj_str_t pt_answer[PJMEDIA_MAX_SDP_FMT]; 835 994 pjmedia_sdp_media *answer; 836 995 const pjmedia_sdp_media *master, *slave; 996 pj_str_t pt_amr_need_adapt = {NULL, 0}; 997 998 /* Set master/slave negotiator based on prefer_remote_codec_order. */ 999 if (prefer_remote_codec_order) { 1000 master = offer; 1001 slave = preanswer; 1002 } else { 1003 master = preanswer; 1004 slave = offer; 1005 } 1006 837 1007 /* With the addition of telephone-event and dodgy MS RTC SDP, 838 1008 * the answer generation algorithm looks really shitty... 839 1009 */ 840 for (i=0; i< offer->desc.fmt_count; ++i) {1010 for (i=0; i<master->desc.fmt_count; ++i) { 841 1011 unsigned j; 842 1012 843 if (pj_isdigit(* offer->desc.fmt[i].ptr)) {1013 if (pj_isdigit(*master->desc.fmt[i].ptr)) { 844 1014 /* This is normal/standard payload type, where it's identified 845 1015 * by payload number. … … 847 1017 unsigned pt; 848 1018 849 pt = pj_strtoul(& offer->desc.fmt[i]);1019 pt = pj_strtoul(&master->desc.fmt[i]); 850 1020 851 1021 if (pt < 96) { … … 854 1024 */ 855 1025 856 offer_has_codec = 1;1026 master_has_codec = 1; 857 1027 858 1028 /* We just need to select one codec. … … 864 1034 865 1035 /* Find matching codec in local descriptor. */ 866 for (j=0; j< preanswer->desc.fmt_count; ++j) {1036 for (j=0; j<slave->desc.fmt_count; ++j) { 867 1037 unsigned p; 868 p = pj_strtoul(& preanswer->desc.fmt[j]);869 if (p == pt && pj_isdigit(* preanswer->desc.fmt[j].ptr)) {1038 p = pj_strtoul(&slave->desc.fmt[j]); 1039 if (p == pt && pj_isdigit(*slave->desc.fmt[j].ptr)) { 870 1040 found_matching_codec = 1; 871 pt_answer[pt_answer_count++] = preanswer->desc.fmt[j];1041 pt_answer[pt_answer_count++] = slave->desc.fmt[j]; 872 1042 break; 873 1043 } … … 883 1053 pj_bool_t is_codec; 884 1054 885 /* Get the rtpmap for the payload type in the offer. */886 a = pjmedia_sdp_media_find_attr2( offer, "rtpmap",887 & offer->desc.fmt[i]);1055 /* Get the rtpmap for the payload type in the master. */ 1056 a = pjmedia_sdp_media_find_attr2(master, "rtpmap", 1057 &master->desc.fmt[i]); 888 1058 if (!a) { 889 1059 pj_assert(!"Bug! Offer should have been validated"); … … 893 1063 894 1064 if (!pj_strcmp2(&or_.enc_name, "telephone-event")) { 895 offer_has_telephone_event = 1;1065 master_has_telephone_event = 1; 896 1066 if (found_matching_telephone_event) 897 1067 continue; 898 1068 is_codec = 0; 899 1069 } else { 900 offer_has_codec = 1;1070 master_has_codec = 1; 901 1071 if (found_matching_codec) 902 1072 continue; … … 907 1077 * encoding name and clock rate. 908 1078 */ 909 for (j=0; j< preanswer->desc.fmt_count; ++j) {910 a = pjmedia_sdp_media_find_attr2( preanswer, "rtpmap",911 & preanswer->desc.fmt[j]);1079 for (j=0; j<slave->desc.fmt_count; ++j) { 1080 a = pjmedia_sdp_media_find_attr2(slave, "rtpmap", 1081 &slave->desc.fmt[j]); 912 1082 if (a) { 913 1083 pjmedia_sdp_rtpmap lr; … … 924 1094 /* Match! */ 925 1095 if (is_codec) { 926 /* Further check for G7221, negotiate bitrate .*/927 if (pj_strcmp2(&or_.enc_name, "G7221") 928 match_g7221(offer, i, preanswer, j) == 0)1096 /* Further check for G7221, negotiate bitrate */ 1097 if (pj_strcmp2(&or_.enc_name, "G7221") == 0 && 1098 !match_g7221(master, i, slave, j)) 929 1099 { 930 1100 continue; 1101 } else 1102 /* Further check for AMR, negotiate fmtp */ 1103 if (pj_strcmp2(&or_.enc_name, "AMR")==0) { 1104 unsigned o_med_idx, a_med_idx; 1105 1106 o_med_idx = prefer_remote_codec_order? i:j; 1107 a_med_idx = prefer_remote_codec_order? j:i; 1108 if (!match_amr(offer, o_med_idx, 1109 preanswer, a_med_idx, 1110 PJ_TRUE, &pt_amr_need_adapt)) 1111 continue; 931 1112 } 932 1113 found_matching_codec = 1; … … 935 1116 } 936 1117 937 pt_answer[pt_answer_count++] = preanswer->desc.fmt[j]; 1118 pt_answer[pt_answer_count++] = 1119 prefer_remote_codec_order? 1120 preanswer->desc.fmt[j]: 1121 preanswer->desc.fmt[i]; 938 1122 break; 939 1123 } … … 949 1133 * - m=x-ms-message 5060 sip null 950 1134 */ 951 offer_has_other = 1;1135 master_has_other = 1; 952 1136 if (found_matching_other) 953 1137 continue; 954 1138 955 for (j=0; j< preanswer->desc.fmt_count; ++j) {956 if (!pj_strcmp(& offer->desc.fmt[i], &preanswer->desc.fmt[j])) {1139 for (j=0; j<slave->desc.fmt_count; ++j) { 1140 if (!pj_strcmp(&master->desc.fmt[i], &slave->desc.fmt[j])) { 957 1141 /* Match */ 958 1142 found_matching_other = 1; 959 pt_answer[pt_answer_count++] = preanswer->desc.fmt[j]; 1143 pt_answer[pt_answer_count++] = prefer_remote_codec_order? 1144 preanswer->desc.fmt[j]: 1145 preanswer->desc.fmt[i]; 960 1146 break; 961 1147 } … … 964 1150 } 965 1151 966 /* See if all types of offer can be matched. */967 if ( offer_has_codec && !found_matching_codec) {1152 /* See if all types of master can be matched. */ 1153 if (master_has_codec && !found_matching_codec) { 968 1154 return PJMEDIA_SDPNEG_NOANSCODEC; 969 1155 } … … 977 1163 */ 978 1164 979 if ( offer_has_other && !found_matching_other) {1165 if (master_has_other && !found_matching_other) { 980 1166 return PJMEDIA_SDPNEG_NOANSUNKNOWN; 981 1167 } 982 1168 983 1169 /* Seems like everything is in order. 984 * Build the answer by cloning from local media, but rearrange the payload1170 * Build the answer by cloning from preanswer, but rearrange the payload 985 1171 * to suit the offer. 986 1172 */ 987 answer = pjmedia_sdp_media_clone(pool, orig_local);1173 answer = pjmedia_sdp_media_clone(pool, preanswer); 988 1174 for (i=0; i<pt_answer_count; ++i) { 989 1175 unsigned j; … … 994 1180 pj_assert(j != answer->desc.fmt_count); 995 1181 str_swap(&answer->desc.fmt[i], &answer->desc.fmt[j]); 1182 1183 /* For AMR/AMRWB format, adapt octet-align setting if required. */ 1184 if (!pj_strcmp(&pt_amr_need_adapt, &pt_answer[i])) 1185 amr_toggle_octet_align(pool, answer, i); 996 1186 } 997 1187 … … 1017 1207 1018 1208 /* If offer has zero port, set our answer with zero port too */ 1019 if (offer->desc.port ==0)1209 if (offer->desc.port == 0) 1020 1210 answer->desc.port = 0; 1021 1211 … … 1077 1267 { 1078 1268 /* See if it has matching codec. */ 1079 if (prefer_remote_codec_order) { 1080 status = match_offer(pool, om, im, im, &am); 1081 } else { 1082 status = match_offer(pool, im, om, im, &am); 1083 } 1084 1269 status = match_offer(pool, prefer_remote_codec_order, 1270 om, im, &am); 1085 1271 if (status == PJ_SUCCESS) { 1086 1272 /* Mark media as used. */
Note: See TracChangeset
for help on using the changeset viewer.