diff options
Diffstat (limited to 'pjmedia/src/pjmedia/sdp_neg.c')
-rw-r--r-- | pjmedia/src/pjmedia/sdp_neg.c | 233 |
1 files changed, 224 insertions, 9 deletions
diff --git a/pjmedia/src/pjmedia/sdp_neg.c b/pjmedia/src/pjmedia/sdp_neg.c index 2e3dde6d..dbba836d 100644 --- a/pjmedia/src/pjmedia/sdp_neg.c +++ b/pjmedia/src/pjmedia/sdp_neg.c @@ -52,7 +52,7 @@ static const char *state_str[] = "STATE_DONE", }; -#define GET_FMTP_IVAL(ival, fmtp, param, default_val) \ +#define GET_FMTP_IVAL_BASE(ival, base, fmtp, param, default_val) \ do { \ pj_str_t s; \ char *p; \ @@ -63,9 +63,39 @@ static const char *state_str[] = } \ pj_strset(&s, p + param.slen, fmtp.fmt_param.slen - \ (p - fmtp.fmt_param.ptr) - param.slen); \ - ival = pj_strtoul(&s); \ + ival = pj_strtoul2(&s, NULL, base); \ } while (0) +#define GET_FMTP_IVAL(ival, fmtp, param, default_val) \ + GET_FMTP_IVAL_BASE(ival, 10, fmtp, param, default_val) + + +/* Definition of customized SDP format negotiation callback */ +struct fmt_match_cb_t +{ + pj_str_t fmt_name; + pjmedia_sdp_neg_fmt_match_cb cb; +}; + +/* Number of registered customized SDP format negotiation callbacks */ +static unsigned fmt_match_cb_cnt; + +/* The registered customized SDP format negotiation callbacks */ +static struct fmt_match_cb_t + fmt_match_cb[PJMEDIA_SDP_NEG_MAX_CUSTOM_FMT_NEG_CB]; + +/* Redefining a very long identifier name, just for convenience */ +#define ALLOW_MODIFY_ANSWER PJMEDIA_SDP_NEG_FMT_MATCH_ALLOW_MODIFY_ANSWER + +static pj_status_t custom_fmt_match( pj_pool_t *pool, + const pj_str_t *fmt_name, + pjmedia_sdp_media *offer, + unsigned o_fmt_idx, + pjmedia_sdp_media *answer, + unsigned a_fmt_idx, + unsigned option); + + /* * Get string representation of negotiator state. */ @@ -231,6 +261,31 @@ PJ_DEF(pj_status_t) pjmedia_sdp_neg_get_neg_local( pjmedia_sdp_neg *neg, return PJ_SUCCESS; } +static pjmedia_sdp_media *sdp_media_clone_deactivate( + pj_pool_t *pool, + const pjmedia_sdp_media *rem_med, + const pjmedia_sdp_media *local_med, + const pjmedia_sdp_session *local_sess) +{ + pjmedia_sdp_media *res; + + res = pjmedia_sdp_media_clone_deactivate(pool, rem_med); + if (!res) + return NULL; + + if (!res->conn && (!local_sess || !local_sess->conn)) { + if (local_med && local_med->conn) + res->conn = pjmedia_sdp_conn_clone(pool, local_med->conn); + else { + res->conn = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_conn); + res->conn->net_type = pj_str("IN"); + res->conn->addr_type = pj_str("IP4"); + res->conn->addr = pj_str("127.0.0.1"); + } + } + + return res; +} /* * Modify local SDP and wait for remote answer. @@ -311,7 +366,7 @@ PJ_DEF(pj_status_t) pjmedia_sdp_neg_modify_local_offer( pj_pool_t *pool, if (!found) { pjmedia_sdp_media *m; - m = pjmedia_sdp_media_clone_deactivate(pool, om); + m = sdp_media_clone_deactivate(pool, om, om, local); pj_array_insert(new_offer->media, sizeof(new_offer->media[0]), new_offer->media_count++, oi, &m); @@ -876,10 +931,12 @@ static pj_status_t process_m_answer( pj_pool_t *pool, (ar.param.slen==1 && *ar.param.ptr=='1'))) { /* Further check for G7221, negotiate bitrate. */ - if (pj_stricmp2(&or_.enc_name, "G7221") == 0) { + if (pj_stricmp2(&or_.enc_name, "G7221") == 0) + { if (match_g7221(offer, i, answer, j)) break; } else + /* Further check for AMR, negotiate fmtp. */ if (pj_stricmp2(&or_.enc_name, "AMR") == 0 || pj_stricmp2(&or_.enc_name, "AMR-WB") == 0) @@ -887,7 +944,13 @@ static pj_status_t process_m_answer( pj_pool_t *pool, if (match_amr(offer, i, answer, j, PJ_FALSE, NULL)) break; - } else { + } else + + /* Call custom format matching callbacks */ + if (custom_fmt_match(pool, &or_.enc_name, + offer, i, answer, j, 0) == + PJ_SUCCESS) + { /* Match! */ break; } @@ -1016,7 +1079,8 @@ static pj_status_t process_answer(pj_pool_t *pool, pjmedia_sdp_media *am; /* Generate matching-but-disabled-media for the answer */ - am = pjmedia_sdp_media_clone_deactivate(pool, offer->media[omi]); + am = sdp_media_clone_deactivate(pool, offer->media[omi], + offer->media[omi], offer); answer->media[answer->media_count++] = am; ++ami; @@ -1078,7 +1142,7 @@ static pj_status_t match_offer(pj_pool_t *pool, /* If offer has zero port, just clone the offer */ if (offer->desc.port == 0) { - answer = pjmedia_sdp_media_clone_deactivate(pool, offer); + answer = sdp_media_clone_deactivate(pool, offer, preanswer, NULL); *p_answer = answer; return PJ_SUCCESS; } @@ -1181,12 +1245,31 @@ static pj_status_t match_offer(pj_pool_t *pool, { /* Match! */ if (is_codec) { + pjmedia_sdp_media *o, *a; + unsigned o_fmt_idx, a_fmt_idx; + + o = (pjmedia_sdp_media*)offer; + a = (pjmedia_sdp_media*)preanswer; + o_fmt_idx = prefer_remote_codec_order? i:j; + a_fmt_idx = prefer_remote_codec_order? j:i; + + /* Call custom format matching callbacks */ + if (custom_fmt_match(pool, &or_.enc_name, + o, o_fmt_idx, + a, a_fmt_idx, + ALLOW_MODIFY_ANSWER) != + PJ_SUCCESS) + { + continue; + } else + /* Further check for G7221, negotiate bitrate */ if (pj_stricmp2(&or_.enc_name, "G7221") == 0 && !match_g7221(master, i, slave, j)) { continue; - } else + } else + /* Further check for AMR, negotiate fmtp */ if (pj_stricmp2(&or_.enc_name, "AMR")==0 || pj_stricmp2(&or_.enc_name, "AMR-WB")==0) @@ -1200,6 +1283,7 @@ static pj_status_t match_offer(pj_pool_t *pool, PJ_TRUE, &pt_amr_need_adapt)) continue; } + found_matching_codec = 1; } else { found_matching_telephone_event = 1; @@ -1371,7 +1455,7 @@ static pj_status_t create_answer( pj_pool_t *pool, * ignore anything in the media once it sees that the port * number is zero. */ - am = pjmedia_sdp_media_clone_deactivate(pool, om); + am = sdp_media_clone_deactivate(pool, om, om, answer); } else { /* The answer is in am */ pj_assert(am != NULL); @@ -1473,3 +1557,134 @@ PJ_DEF(pj_status_t) pjmedia_sdp_neg_negotiate( pj_pool_t *pool, return status; } + +static pj_status_t custom_fmt_match(pj_pool_t *pool, + const pj_str_t *fmt_name, + pjmedia_sdp_media *offer, + unsigned o_fmt_idx, + pjmedia_sdp_media *answer, + unsigned a_fmt_idx, + unsigned option) +{ + unsigned i; + + for (i = 0; i < fmt_match_cb_cnt; ++i) { + if (pj_stricmp(fmt_name, &fmt_match_cb[i].fmt_name) == 0) { + pj_assert(fmt_match_cb[i].cb); + return (*fmt_match_cb[i].cb)(pool, offer, o_fmt_idx, + answer, a_fmt_idx, + option); + } + } + + /* Not customized format matching found, should be matched */ + return PJ_SUCCESS; +} + +/* Register customized SDP format negotiation callback function. */ +PJ_DECL(pj_status_t) pjmedia_sdp_neg_register_fmt_match_cb( + const pj_str_t *fmt_name, + pjmedia_sdp_neg_fmt_match_cb cb) +{ + struct fmt_match_cb_t *f = NULL; + unsigned i; + + PJ_ASSERT_RETURN(fmt_name, PJ_EINVAL); + + /* Check if the callback for the format name has been registered */ + for (i = 0; i < fmt_match_cb_cnt; ++i) { + if (pj_stricmp(fmt_name, &fmt_match_cb[i].fmt_name) == 0) + break; + } + + /* Unregistration */ + + if (cb == NULL) { + if (i == fmt_match_cb_cnt) + return PJ_ENOTFOUND; + + pj_array_erase(fmt_match_cb, sizeof(fmt_match_cb[0]), + fmt_match_cb_cnt, i); + fmt_match_cb_cnt--; + + return PJ_SUCCESS; + } + + /* Registration */ + + if (i < fmt_match_cb_cnt) { + /* The same format name has been registered before */ + if (cb != fmt_match_cb[i].cb) + return PJ_EEXISTS; + else + return PJ_SUCCESS; + } + + if (fmt_match_cb_cnt >= PJ_ARRAY_SIZE(fmt_match_cb)) + return PJ_ETOOMANY; + + f = &fmt_match_cb[fmt_match_cb_cnt++]; + f->fmt_name = *fmt_name; + f->cb = cb; + + return PJ_SUCCESS; +} + + +/* Match format in the SDP media offer and answer. */ +PJ_DEF(pj_bool_t) pjmedia_sdp_neg_fmt_match( pj_pool_t *pool, + pjmedia_sdp_media *offer, + unsigned o_fmt_idx, + pjmedia_sdp_media *answer, + unsigned a_fmt_idx, + unsigned option) +{ + const pjmedia_sdp_attr *attr; + pjmedia_sdp_rtpmap o_rtpmap, a_rtpmap; + + /* Get the format rtpmap from the offer. */ + attr = pjmedia_sdp_media_find_attr2(offer, "rtpmap", + &offer->desc.fmt[o_fmt_idx]); + if (!attr) { + pj_assert(!"Bug! Offer haven't been validated"); + return PJ_EBUG; + } + pjmedia_sdp_attr_get_rtpmap(attr, &o_rtpmap); + + /* Get the format rtpmap from the answer. */ + attr = pjmedia_sdp_media_find_attr2(answer, "rtpmap", + &answer->desc.fmt[a_fmt_idx]); + if (!attr) { + pj_assert(!"Bug! Answer haven't been validated"); + return PJ_EBUG; + } + pjmedia_sdp_attr_get_rtpmap(attr, &a_rtpmap); + + if (pj_stricmp(&o_rtpmap.enc_name, &a_rtpmap.enc_name) != 0 || + o_rtpmap.clock_rate != a_rtpmap.clock_rate) + { + return PJMEDIA_SDP_EFORMATNOTEQUAL; + } + + /* Further check for G7221, negotiate bitrate. */ + if (pj_stricmp2(&o_rtpmap.enc_name, "G7221") == 0) { + if (match_g7221(offer, o_fmt_idx, answer, a_fmt_idx)) + return PJ_SUCCESS; + else + return PJMEDIA_SDP_EFORMATNOTEQUAL; + } else + /* Further check for AMR, negotiate fmtp. */ + if (pj_stricmp2(&o_rtpmap.enc_name, "AMR") == 0 || + pj_stricmp2(&o_rtpmap.enc_name, "AMR-WB") == 0) + { + if (match_amr(offer, o_fmt_idx, answer, a_fmt_idx, PJ_FALSE, NULL)) + return PJ_SUCCESS; + else + return PJMEDIA_SDP_EFORMATNOTEQUAL; + } + PJ_TODO(replace_hardcoded_fmt_match_in_sdp_neg_with_custom_fmt_match_cb); + + return custom_fmt_match(pool, &o_rtpmap.enc_name, + offer, o_fmt_idx, answer, a_fmt_idx, option); +} + |