From fc938ab05ef6ea7e2c81c5d1e72a75eb89b03b13 Mon Sep 17 00:00:00 2001 From: Liong Sauw Ming Date: Tue, 9 Jul 2013 07:17:39 +0000 Subject: Closed #1687: Allow media type change during SDP negotiation git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@4554 74dad513-b988-da41-8d7b-12977e46ad98 --- pjmedia/include/pjmedia/sdp_neg.h | 42 ++++++++++++++++- pjmedia/src/pjmedia/sdp_neg.c | 97 +++++++++++++++++++++++++-------------- 2 files changed, 103 insertions(+), 36 deletions(-) (limited to 'pjmedia') diff --git a/pjmedia/include/pjmedia/sdp_neg.h b/pjmedia/include/pjmedia/sdp_neg.h index bc8c52cb..0be9e528 100644 --- a/pjmedia/include/pjmedia/sdp_neg.h +++ b/pjmedia/include/pjmedia/sdp_neg.h @@ -312,6 +312,22 @@ typedef enum pjmedia_sdp_neg_state pjmedia_sdp_neg_state; typedef struct pjmedia_sdp_neg pjmedia_sdp_neg; +/** + * Flags to be given to pjmedia_sdp_neg_modify_local_offer2(). + */ +typedef enum pjmedia_mod_offer_flag +{ + /** + * Allow media type in the SDP to be changed. + * When generating a new offer, in the case that a media line doesn't match + * the active SDP, the new media line will be considered to replace the + * existing media at the same position. + */ + PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE = 1 + +} pjmedia_mod_offer_flag; + + /** * Get the state string description of the specified state. * @@ -500,7 +516,8 @@ pjmedia_sdp_neg_get_neg_local( pjmedia_sdp_neg *neg, * After calling this function, application can send the SDP as offer * to remote party, using signaling protocol such as SIP. * The negotiator state will move to PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER, - * where it waits for SDP answer from remote. + * where it waits for SDP answer from remote. See also + * #pjmedia_sdp_neg_modify_local_offer2() * * @param pool Pool to allocate memory. The pool's lifetime needs * to be valid for the duration of the negotiator. @@ -515,6 +532,29 @@ pjmedia_sdp_neg_modify_local_offer( pj_pool_t *pool, pjmedia_sdp_neg *neg, const pjmedia_sdp_session *local); +/** + * Modify local session with a new SDP and treat this as a new offer. + * This function can only be called in state PJMEDIA_SDP_NEG_STATE_DONE. + * After calling this function, application can send the SDP as offer + * to remote party, using signaling protocol such as SIP. + * The negotiator state will move to PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER, + * where it waits for SDP answer from remote. + * + * @param pool Pool to allocate memory. The pool's lifetime needs + * to be valid for the duration of the negotiator. + * @param neg The SDP negotiator instance. + * @param flags Bitmask from pjmedia_mod_offer_flag. + * @param local The new local SDP. + * + * @return PJ_SUCCESS on success, or the appropriate + * error code. + */ +PJ_DECL(pj_status_t) +pjmedia_sdp_neg_modify_local_offer2( pj_pool_t *pool, + pjmedia_sdp_neg *neg, + unsigned flags, + const pjmedia_sdp_session *local); + /** * This function can only be called in PJMEDIA_SDP_NEG_STATE_DONE state. * Application calls this function to retrieve currently active diff --git a/pjmedia/src/pjmedia/sdp_neg.c b/pjmedia/src/pjmedia/sdp_neg.c index a23b6ef0..160a082e 100644 --- a/pjmedia/src/pjmedia/sdp_neg.c +++ b/pjmedia/src/pjmedia/sdp_neg.c @@ -275,6 +275,15 @@ static pjmedia_sdp_media *sdp_media_clone_deactivate( PJ_DEF(pj_status_t) pjmedia_sdp_neg_modify_local_offer( pj_pool_t *pool, pjmedia_sdp_neg *neg, const pjmedia_sdp_session *local) +{ + return pjmedia_sdp_neg_modify_local_offer2(pool, neg, 0, local); +} + +PJ_DEF(pj_status_t) pjmedia_sdp_neg_modify_local_offer2( + pj_pool_t *pool, + pjmedia_sdp_neg *neg, + unsigned flags, + const pjmedia_sdp_session *local) { pjmedia_sdp_session *new_offer; pjmedia_sdp_session *old_offer; @@ -314,45 +323,63 @@ PJ_DEF(pj_status_t) pjmedia_sdp_neg_modify_local_offer( pj_pool_t *pool, pj_strdup(pool, &new_offer->origin.addr_type,&old_offer->origin.addr_type); pj_strdup(pool, &new_offer->origin.addr, &old_offer->origin.addr); - /* Generating the new offer, in the case media lines doesn't match the - * active SDP (e.g. current/active SDP's have m=audio and m=video lines, - * and the new offer only has m=audio line), the negotiator will fix - * the new offer by reordering and adding the missing media line with - * port number set to zero. - */ - for (oi = 0; oi < old_offer->media_count; ++oi) { - pjmedia_sdp_media *om; - pjmedia_sdp_media *nm; - unsigned ni; /* new offer media index */ - pj_bool_t found = PJ_FALSE; - - om = old_offer->media[oi]; - for (ni = oi; ni < new_offer->media_count; ++ni) { - nm = new_offer->media[ni]; - if (pj_strcmp(&nm->desc.media, &om->desc.media) == 0) { - if (ni != oi) { - /* The same media found but the position unmatched to the - * old offer, so let's put this media in the right place, - * and keep the order of the rest. - */ - pj_array_insert(new_offer->media, /* array */ - sizeof(new_offer->media[0]), /* elmt size*/ - ni, /* count */ - oi, /* pos */ - &nm); /* new elmt */ - } - found = PJ_TRUE; - break; + if ((flags & PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE) == 0) { + /* Generating the new offer, in the case media lines doesn't match the + * active SDP (e.g. current/active SDP's have m=audio and m=video lines, + * and the new offer only has m=audio line), the negotiator will fix + * the new offer by reordering and adding the missing media line with + * port number set to zero. + */ + for (oi = 0; oi < old_offer->media_count; ++oi) { + pjmedia_sdp_media *om; + pjmedia_sdp_media *nm; + unsigned ni; /* new offer media index */ + pj_bool_t found = PJ_FALSE; + + om = old_offer->media[oi]; + for (ni = oi; ni < new_offer->media_count; ++ni) { + nm = new_offer->media[ni]; + if (pj_strcmp(&nm->desc.media, &om->desc.media) == 0) { + if (ni != oi) { + /* The same media found but the position unmatched to + * the old offer, so let's put this media in the right + * place, and keep the order of the rest. + */ + pj_array_insert( + new_offer->media, /* array */ + sizeof(new_offer->media[0]), /* elmt size*/ + ni, /* count */ + oi, /* pos */ + &nm); /* new elmt */ + } + found = PJ_TRUE; + break; + } } - } - if (!found) { - pjmedia_sdp_media *m; + if (!found) { + pjmedia_sdp_media *m; + + 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); + } + } + } else { + /* If media type change is allowed, the negotiator only needs to fix + * the new offer by adding the missing media line(s) with port number + * set to zero. + */ + for (oi = new_offer->media_count; oi < old_offer->media_count; ++oi) { + pjmedia_sdp_media *m; - m = sdp_media_clone_deactivate(pool, om, om, local); + m = sdp_media_clone_deactivate(pool, old_offer->media[oi], + old_offer->media[oi], local); pj_array_insert(new_offer->media, sizeof(new_offer->media[0]), - new_offer->media_count++, oi, &m); - } + new_offer->media_count++, oi, &m); + + } } /* New_offer fixed */ -- cgit v1.2.3