summaryrefslogtreecommitdiff
path: root/pjmedia/src/pjmedia/sdp_neg.c
diff options
context:
space:
mode:
Diffstat (limited to 'pjmedia/src/pjmedia/sdp_neg.c')
-rw-r--r--pjmedia/src/pjmedia/sdp_neg.c233
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);
+}
+