From da1de0865a23a7eb5cde2b4160979164dbc08a39 Mon Sep 17 00:00:00 2001 From: Benny Prijono Date: Tue, 7 Feb 2006 12:34:58 +0000 Subject: Added STATE_REMOTE_OFFER state in negotiator git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@140 74dad513-b988-da41-8d7b-12977e46ad98 --- pjmedia/include/pjmedia/errno.h | 25 +++- pjmedia/include/pjmedia/sdp_neg.h | 266 +++++++++++++++++++++++++++++++------- pjmedia/src/pjmedia/errno.c | 3 + pjmedia/src/pjmedia/sdp.c | 3 +- pjmedia/src/pjmedia/sdp_neg.c | 140 ++++++++++++++------ 5 files changed, 345 insertions(+), 92 deletions(-) diff --git a/pjmedia/include/pjmedia/errno.h b/pjmedia/include/pjmedia/errno.h index 1fe045e0..14da37de 100644 --- a/pjmedia/include/pjmedia/errno.h +++ b/pjmedia/include/pjmedia/errno.h @@ -147,31 +147,46 @@ PJ_DECL(pj_str_t) pjmedia_strerror( pj_status_t status, char *buffer, * Invalid state to perform the specified operation. */ #define PJMEDIA_SDPNEG_EINSTATE (PJMEDIA_ERRNO_START+40) /* 220040 */ +/** + * @hideinitializer + * No initial local SDP. + */ +#define PJMEDIA_SDPNEG_ENOINITIAL (PJMEDIA_ERRNO_START+41) /* 220041 */ /** * @hideinitializer * No currently active SDP. */ -#define PJMEDIA_SDPNEG_ENOACTIVE (PJMEDIA_ERRNO_START+41) /* 220041 */ +#define PJMEDIA_SDPNEG_ENOACTIVE (PJMEDIA_ERRNO_START+42) /* 220042 */ +/** + * @hideinitializer + * No current offer or answer. + */ +#define PJMEDIA_SDPNEG_ENONEG (PJMEDIA_ERRNO_START+43) /* 220043 */ /** * @hideinitializer * Media count mismatch in offer and answer. */ -#define PJMEDIA_SDPNEG_EMISMEDIA (PJMEDIA_ERRNO_START+42) /* 220042 */ +#define PJMEDIA_SDPNEG_EMISMEDIA (PJMEDIA_ERRNO_START+44) /* 220044 */ /** * @hideinitializer * Media type is different in the remote answer. */ -#define PJMEDIA_SDPNEG_EINVANSMEDIA (PJMEDIA_ERRNO_START+43) /* 220043 */ +#define PJMEDIA_SDPNEG_EINVANSMEDIA (PJMEDIA_ERRNO_START+45) /* 220045 */ /** * @hideinitializer * Transport type is different in the remote answer. */ -#define PJMEDIA_SDPNEG_EINVANSTP (PJMEDIA_ERRNO_START+44) /* 220044 */ +#define PJMEDIA_SDPNEG_EINVANSTP (PJMEDIA_ERRNO_START+46) /* 220046 */ /** * @hideinitializer * No common media payload is provided in the answer. */ -#define PJMEDIA_SDPNEG_EANSNOMEDIA (PJMEDIA_ERRNO_START+45) /* 220045 */ +#define PJMEDIA_SDPNEG_EANSNOMEDIA (PJMEDIA_ERRNO_START+47) /* 220047 */ +/** + * @hideinitializer + * No media is active after negotiation. + */ +#define PJMEDIA_SDPNEG_ENOMEDIA (PJMEDIA_ERRNO_START+48) /* 220048 */ /************************************************************ diff --git a/pjmedia/include/pjmedia/sdp_neg.h b/pjmedia/include/pjmedia/sdp_neg.h index 7d0cc086..d67aa49d 100644 --- a/pjmedia/include/pjmedia/sdp_neg.h +++ b/pjmedia/include/pjmedia/sdp_neg.h @@ -39,7 +39,29 @@ PJ_BEGIN_DECL /** - * This enumeration describes SDP negotiation state. + * This enumeration describes SDP negotiation state. The negotiator state + * is illustrated in the following diagram. + * + *
+ *                                              reinit_local_offer()
+ *                                              modify_local_offer()
+ *     create_w_local_offer()  +-------------+  send_local_offer()
+ *     ----------------------->| LOCAL_OFFER |<-----------------------
+ *    |                        +-------------+                        |
+ *    |                               |                               |
+ *    |           set_remote_answer() |                               |
+ *    |                               V                               |
+ * +--+---+                     +-----------+     negotiate()     +------+
+ * | NULL |                     | WAIT_NEGO |-------------------->| DONE |
+ * +------+                     +-----------+                     +------+
+ *    |                               A                               |
+ *    |            set_local_answer() |                               |
+ *    |                               |                               |
+ *    |                        +--------------+   set_remote_offer()  |
+ *     ----------------------->| REMOTE_OFFER |<----------------------
+ *     create_w_remote_offer() +--------------+
+ *
+ * 
*/ enum pjmedia_sdp_neg_state { @@ -50,14 +72,21 @@ enum pjmedia_sdp_neg_state /** * This state occurs when SDP negotiator has sent our offer to remote and - * it is waiting for answer. + * it is waiting for answer. */ PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER, + /** + * This state occurs when SDP negotiator has received offer from remote + * and currently waiting for local answer. + */ + PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER, + /** * This state occurs when an offer (either local or remote) has been * provided with answer. The SDP negotiator is ready to negotiate both - * session descriptors. + * session descriptors. Application can call #pjmedia_sdp_neg_negotiate() + * immediately to begin negotiation process. */ PJMEDIA_SDP_NEG_STATE_WAIT_NEGO, @@ -68,32 +97,23 @@ enum pjmedia_sdp_neg_state PJMEDIA_SDP_NEG_STATE_DONE, }; -/* Negotiator state: - * - * reinit_local_offer() - * modify_local_offer() - * create_w_local_offer() +-------------+ tx_local_offer() - * /------------------------->| LOCAL_OFFER |<----------------------\ - * | +-------------+ | - * | | | - * | rx_remote_answer() | | - * | V | - * +--+---+ +-----------+ negotiate() +------+ - * + NULL |------------------------>| WAIT_NEGO |-------------------->| DONE | - * +------+ create_w_remote_offer() +-----------+ +------+ - * A | - * | rx_remote_offer() | - * \-----------------------------/ - */ - /** * Create the SDP negotiator with local offer. The SDP negotiator then * will move to PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER state, where it waits * until it receives answer from remote. When SDP answer from remote is - * received, application should call #pjmedia_sdp_neg_rx_remote_answer(). + * received, application should call #pjmedia_sdp_neg_set_remote_answer(). * * After calling this function, application should send the local SDP offer - * to remote party and wait for SDP answer. + * to remote party using higher layer signaling protocol (e.g. SIP) and + * wait for SDP answer. + * + * @param pool Pool to allocate memory. The pool's lifetime needs + * to be valid for the duration of the negotiator. + * @param local The initial local capability. + * @param p_neg Pointer to receive the negotiator instance. + * + * @return PJ_SUCCESS on success, or the appropriate error + * code. */ PJ_DECL(pj_status_t) pjmedia_sdp_neg_create_w_local_offer( pj_pool_t *pool, @@ -101,21 +121,44 @@ pjmedia_sdp_neg_create_w_local_offer( pj_pool_t *pool, pjmedia_sdp_neg **p_neg); /** - * Initialize the SDP negotiator with both local and remote offer. - * Application normally calls this function when it receives initial offer - * from remote. Application must also provide initial local offer when - * calling this function. After this function is called, the SDP negotiator - * state will move to PJMEDIA_SDP_NEG_STATE_WAIT_NEGO, and the negotiation - * function can be called. + * Initialize the SDP negotiator with remote offer, and optionally + * specify the initial local capability, if known. Application normally + * calls this function when it receives initial offer + * from remote. + * + * If local media capability is specified, this capability will be set as + * initial local capability of the negotiator, and after this function is + * called, the SDP negotiator state will move to state + * PJMEDIA_SDP_NEG_STATE_WAIT_NEGO, and the negotiation function can be + * called. + * + * If local SDP is not specified, the negotiator will not have initial local + * capability, and after this function is called the negotiator state will + * move to PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER state. Application MUST supply + * local answer later with #pjmedia_sdp_neg_set_local_answer(), before + * calling the negotiation function. + * + * @param pool Pool to allocate memory. The pool's lifetime needs + * to be valid for the duration of the negotiator. + * @param initial Optional initial local capability. + * @param remote The remote offer. + * @param p_neg Pointer to receive the negotiator instance. + * + * @return PJ_SUCCESS on success, or the appropriate error + * code. */ PJ_DECL(pj_status_t) pjmedia_sdp_neg_create_w_remote_offer(pj_pool_t *pool, - const pjmedia_sdp_session *local, + const pjmedia_sdp_session *initial, const pjmedia_sdp_session *remote, pjmedia_sdp_neg **p_neg); /** * Get SDP negotiator state. + * + * @param neg The SDP negotiator instance. + * + * @return The negotiator state. */ PJ_DECL(pjmedia_sdp_neg_state) pjmedia_sdp_neg_get_state( pjmedia_sdp_neg *neg ); @@ -125,28 +168,82 @@ pjmedia_sdp_neg_get_state( pjmedia_sdp_neg *neg ); * function after negotiation has been done, or otherwise there won't be * active SDPs. Calling this function will not change the state of the * negotiator. + * + * @param neg The SDP negotiator instance. + * @param local Pointer to receive the local active SDP. + * + * @return PJ_SUCCESS if local active SDP is present. */ PJ_DECL(pj_status_t) -pjmedia_sdp_neg_get_local( pjmedia_sdp_neg *neg, - const pjmedia_sdp_session **local); +pjmedia_sdp_neg_get_active_local( pjmedia_sdp_neg *neg, + const pjmedia_sdp_session **local); /** * Get the currently active remote SDP. Application can only call this * function after negotiation has been done, or otherwise there won't be * active SDPs. Calling this function will not change the state of the * negotiator. + * + * @param neg The SDP negotiator instance. + * @param remote Pointer to receive the remote active SDP. + * + * @return PJ_SUCCESS if remote active SDP is present. */ PJ_DECL(pj_status_t) -pjmedia_sdp_neg_get_remote( pjmedia_sdp_neg *neg, - const pjmedia_sdp_session **remote); +pjmedia_sdp_neg_get_active_remote( pjmedia_sdp_neg *neg, + const pjmedia_sdp_session **remote); + +/** + * Get the current remote SDP offer or answer. Application can only + * call this function in state PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER or + * PJMEDIA_SDP_NEG_STATE_WAIT_NEGO, or otherwise there won't be remote + * SDP offer/answer. Calling this function will not change the state + * of the negotiator. + * + * @param neg The SDP negotiator instance. + * @param remote Pointer to receive the current remote offer or + * answer. + * + * @return PJ_SUCCESS if the negotiator currently has + * remote offer or answer. + */ +PJ_DECL(pj_status_t) +pjmedia_sdp_neg_get_neg_remote( pjmedia_sdp_neg *neg, + const pjmedia_sdp_session **remote); +/** + * Get the current local SDP offer or answer. Application can only + * call this function in state PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER or + * PJMEDIA_SDP_NEG_STATE_WAIT_NEGO, or otherwise there won't be local + * SDP offer/answer. Calling this function will not change the state + * of the negotiator. + * + * @param neg The SDP negotiator instance. + * @param local Pointer to receive the current local offer or + * answer. + * + * @return PJ_SUCCESS if the negotiator currently has + * local offer or answer. + */ +PJ_DECL(pj_status_t) +pjmedia_sdp_neg_get_neg_local( pjmedia_sdp_neg *neg, + const pjmedia_sdp_session **local); + /** * Completely replaces local offer with new SDP. After calling * This function can only be called in state PJMEDIA_SDP_NEG_STATE_DONE. * this function, application can send the modified offer to remote. * 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 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_offer( pj_pool_t *pool, @@ -157,7 +254,24 @@ pjmedia_sdp_neg_modify_local_offer( pj_pool_t *pool, * Negotiate local and remote answer. Before calling this function, the * SDP negotiator must be in PJMEDIA_SDP_NEG_STATE_WAIT_NEGO state. * After calling this function, the negotiator state will move to - * PJMEDIA_SDP_NEG_STATE_DONE. + * PJMEDIA_SDP_NEG_STATE_DONE regardless whether the negotiation has + * been successfull or not. + * + * If the negotiation succeeds (i.e. the return value is PJ_SUCCESS), + * the active local and remote SDP will be replaced with the new SDP + * from the negotiation process. + * + * If the negotiation fails, the active local and remote SDP will not + * change. + * + * @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 allow_asym Should be zero. + * + * @return PJ_SUCCESS when there is at least one media + * is actuve common in both offer and answer, or + * failure code when negotiation has failed. */ PJ_DECL(pj_status_t) pjmedia_sdp_neg_negotiate( pj_pool_t *pool, pjmedia_sdp_neg *neg, @@ -169,37 +283,91 @@ PJ_DECL(pj_status_t) pjmedia_sdp_neg_negotiate( pj_pool_t *pool, * Application calls this function to retrieve currently active * local SDP to be sent to remote. The negotiator state will then move * to PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER, where it waits for SDP answer - * from remote. + * from remote. When SDP answer has been received from remote, application + * must call #pjmedia_sdp_neg_set_remote_answer(). + * + * @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 offer Pointer to receive active local SDP to be + * offered to remote. + * + * @return PJ_SUCCESS if local offer can be created. + */ +PJ_DECL(pj_status_t) +pjmedia_sdp_neg_send_local_offer( pj_pool_t *pool, + pjmedia_sdp_neg *neg, + const pjmedia_sdp_session **offer); + +/** + * This function can only be called in PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER + * state, i.e. after application calls #pjmedia_sdp_neg_send_local_offer() + * function. Application calls this function when it receives SDP answer + * from remote. After this function is called, the negotiator state will + * move to PJMEDIA_SDP_NEG_STATE_WAIT_NEGO, and application can call the + * negotiation function #pjmedia_sdp_neg_negotiate(). + * + * @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 remote The remote answer. + * + * @return PJ_SUCCESS on success. */ PJ_DECL(pj_status_t) -pjmedia_sdp_neg_tx_local_offer( pj_pool_t *pool, - pjmedia_sdp_neg *neg, - const pjmedia_sdp_session **offer); +pjmedia_sdp_neg_set_remote_answer( pj_pool_t *pool, + pjmedia_sdp_neg *neg, + const pjmedia_sdp_session *remote); + + /** * This function can only be called in PJMEDIA_SDP_NEG_STATE_DONE state. * Application calls this function when it receives SDP offer from remote. * After this function is called, the negotiator state will move to - * PJMEDIA_SDP_NEG_STATE_WAIT_NEGO, and application can call the - * negotiation function #pjmedia_sdp_neg_negotiate(). + * PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER, and application MUST call the + * #pjmedia_sdp_neg_set_local_answer() to set local answer before it can + * call the negotiation function. + * + * @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 remote The remote offer. + * + * @return PJ_SUCCESS on success. */ PJ_DECL(pj_status_t) -pjmedia_sdp_neg_rx_remote_offer( pj_pool_t *pool, - pjmedia_sdp_neg *neg, - const pjmedia_sdp_session *remote); +pjmedia_sdp_neg_set_remote_offer( pj_pool_t *pool, + pjmedia_sdp_neg *neg, + const pjmedia_sdp_session *remote); + /** - * This function can only be called in PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER - * state. Application calls this function when it receives SDP answer - * from remote. After this function is called, the negotiator state will + * This function can only be called in PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER + * state, i.e. after application calls #pjmedia_sdp_neg_set_remote_offer() + * function. After this function is called, the negotiator state will * move to PJMEDIA_SDP_NEG_STATE_WAIT_NEGO, and application can call the * negotiation function #pjmedia_sdp_neg_negotiate(). + * + * @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 local Optional local answer. If negotiator has initial + * local capability, application can specify NULL on + * this argument; in this case, the negotiator will + * create answer by by negotiating remote offer with + * initial local capability. If negotiator doesn't have + * initial local capability, application MUST specify + * local answer here. + * + * @return PJ_SUCCESS on success. */ PJ_DECL(pj_status_t) -pjmedia_sdp_neg_rx_remote_answer( pj_pool_t *pool, +pjmedia_sdp_neg_set_local_answer( pj_pool_t *pool, pjmedia_sdp_neg *neg, - const pjmedia_sdp_session *remote); + const pjmedia_sdp_session *local); + diff --git a/pjmedia/src/pjmedia/errno.c b/pjmedia/src/pjmedia/errno.c index ccf5c8d8..e42b5444 100644 --- a/pjmedia/src/pjmedia/errno.c +++ b/pjmedia/src/pjmedia/errno.c @@ -53,11 +53,14 @@ static const struct /* SDP negotiator errors. */ { PJMEDIA_SDPNEG_EINSTATE, "Invalid SDP negotiator state for operation" }, + { PJMEDIA_SDPNEG_ENOINITIAL, "No initial local SDP in SDP negotiator" }, { PJMEDIA_SDPNEG_ENOACTIVE, "No active SDP in SDP negotiator" }, + { PJMEDIA_SDPNEG_ENONEG, "No current local/remote offer/answer" }, { PJMEDIA_SDPNEG_EMISMEDIA, "SDP media count mismatch in offer/answer" }, { PJMEDIA_SDPNEG_EINVANSMEDIA, "SDP media type mismatch in offer/answer" }, { PJMEDIA_SDPNEG_EINVANSTP, "SDP media transport type mismatch in offer/answer" }, { PJMEDIA_SDPNEG_EANSNOMEDIA, "No common SDP media payload in answer" }, + { PJMEDIA_SDPNEG_ENOMEDIA, "No active media stream after negotiation" }, /* SDP comparison results */ { PJMEDIA_SDP_EMEDIANOTEQUAL, "SDP media descriptor not equal" }, diff --git a/pjmedia/src/pjmedia/sdp.c b/pjmedia/src/pjmedia/sdp.c index 2f6dcfe3..edd83aa5 100644 --- a/pjmedia/src/pjmedia/sdp.c +++ b/pjmedia/src/pjmedia/sdp.c @@ -1093,6 +1093,7 @@ static pj_status_t validate_sdp_conn(const pjmedia_sdp_conn *c) PJ_DEF(pj_status_t) pjmedia_sdp_validate(const pjmedia_sdp_session *sdp) { unsigned i; + const pj_str_t STR_RTPMAP = { "rtpmap", 6 }; CHECK( sdp != NULL, PJ_EINVAL); @@ -1155,7 +1156,7 @@ PJ_DEF(pj_status_t) pjmedia_sdp_validate(const pjmedia_sdp_session *sdp) if (m->desc.port != 0 && pt >= 96) { const pjmedia_sdp_attr *a; - a = pjmedia_sdp_media_find_attr2(m, "rtpmap", &m->desc.fmt[j]); + a = pjmedia_sdp_media_find_attr(m,&STR_RTPMAP,&m->desc.fmt[j]); CHECK( a != NULL, PJMEDIA_SDP_EMISSINGRTPMAP); } } diff --git a/pjmedia/src/pjmedia/sdp_neg.c b/pjmedia/src/pjmedia/sdp_neg.c index 313fff99..37cf5f9c 100644 --- a/pjmedia/src/pjmedia/sdp_neg.c +++ b/pjmedia/src/pjmedia/sdp_neg.c @@ -77,7 +77,7 @@ pjmedia_sdp_neg_create_w_local_offer( pj_pool_t *pool, */ PJ_DEF(pj_status_t) pjmedia_sdp_neg_create_w_remote_offer(pj_pool_t *pool, - const pjmedia_sdp_session *local, + const pjmedia_sdp_session *initial, const pjmedia_sdp_session *remote, pjmedia_sdp_neg **p_neg) { @@ -85,29 +85,35 @@ pjmedia_sdp_neg_create_w_remote_offer(pj_pool_t *pool, pj_status_t status; /* Check arguments are valid. */ - PJ_ASSERT_RETURN(pool && local && remote && p_neg, PJ_EINVAL); + PJ_ASSERT_RETURN(pool && remote && p_neg, PJ_EINVAL); *p_neg = NULL; - /* Validate remote offer and local answer */ + /* Validate remote offer and initial answer */ status = pjmedia_sdp_validate(remote); if (status != PJ_SUCCESS) return status; - PJ_ASSERT_RETURN((status=pjmedia_sdp_validate(local))==PJ_SUCCESS, status); /* Create and initialize negotiator. */ neg = pj_pool_zalloc(pool, sizeof(pjmedia_sdp_neg)); PJ_ASSERT_RETURN(neg != NULL, PJ_ENOMEM); - neg->state = PJMEDIA_SDP_NEG_STATE_WAIT_NEGO; - neg->initial_sdp = pjmedia_sdp_session_clone(pool, local); - PJ_ASSERT_RETURN((status=pjmedia_sdp_validate(neg->initial_sdp))==PJ_SUCCESS, - status); - - neg->neg_local_sdp = pjmedia_sdp_session_clone(pool, local); neg->neg_remote_sdp = pjmedia_sdp_session_clone(pool, remote); - PJ_ASSERT_RETURN((status=pjmedia_sdp_validate(neg->neg_remote_sdp))==PJ_SUCCESS, - status); + + if (initial) { + PJ_ASSERT_RETURN((status=pjmedia_sdp_validate(initial))==PJ_SUCCESS, + status); + + neg->initial_sdp = pjmedia_sdp_session_clone(pool, initial); + neg->neg_local_sdp = pjmedia_sdp_session_clone(pool, initial); + + neg->state = PJMEDIA_SDP_NEG_STATE_WAIT_NEGO; + + } else { + + neg->state = PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER; + + } *p_neg = neg; return PJ_SUCCESS; @@ -126,8 +132,8 @@ pjmedia_sdp_neg_get_state( pjmedia_sdp_neg *neg ) PJ_DEF(pj_status_t) -pjmedia_sdp_neg_get_local( pjmedia_sdp_neg *neg, - const pjmedia_sdp_session **local) +pjmedia_sdp_neg_get_active_local( pjmedia_sdp_neg *neg, + const pjmedia_sdp_session **local) { PJ_ASSERT_RETURN(neg && local, PJ_EINVAL); PJ_ASSERT_RETURN(neg->active_local_sdp, PJMEDIA_SDPNEG_ENOACTIVE); @@ -138,8 +144,8 @@ pjmedia_sdp_neg_get_local( pjmedia_sdp_neg *neg, PJ_DEF(pj_status_t) -pjmedia_sdp_neg_get_remote( pjmedia_sdp_neg *neg, - const pjmedia_sdp_session **remote) +pjmedia_sdp_neg_get_active_remote( pjmedia_sdp_neg *neg, + const pjmedia_sdp_session **remote) { PJ_ASSERT_RETURN(neg && remote, PJ_EINVAL); PJ_ASSERT_RETURN(neg->active_remote_sdp, PJMEDIA_SDPNEG_ENOACTIVE); @@ -148,6 +154,28 @@ pjmedia_sdp_neg_get_remote( pjmedia_sdp_neg *neg, return PJ_SUCCESS; } +PJ_DEF(pj_status_t) +pjmedia_sdp_neg_get_neg_remote( pjmedia_sdp_neg *neg, + const pjmedia_sdp_session **remote) +{ + PJ_ASSERT_RETURN(neg && remote, PJ_EINVAL); + PJ_ASSERT_RETURN(neg->neg_remote_sdp, PJMEDIA_SDPNEG_ENONEG); + + *remote = neg->neg_remote_sdp; + return PJ_SUCCESS; +} + +PJ_DEF(pj_status_t) +pjmedia_sdp_neg_get_neg_local( pjmedia_sdp_neg *neg, + const pjmedia_sdp_session **local) +{ + PJ_ASSERT_RETURN(neg && local, PJ_EINVAL); + PJ_ASSERT_RETURN(neg->neg_local_sdp, PJMEDIA_SDPNEG_ENONEG); + + *local = neg->neg_local_sdp; + return PJ_SUCCESS; +} + /* * Modify local SDP and wait for remote answer. @@ -174,9 +202,9 @@ pjmedia_sdp_neg_modify_local_offer( pj_pool_t *pool, PJ_DEF(pj_status_t) -pjmedia_sdp_neg_tx_local_offer( pj_pool_t *pool, - pjmedia_sdp_neg *neg, - const pjmedia_sdp_session **offer) +pjmedia_sdp_neg_send_local_offer( pj_pool_t *pool, + pjmedia_sdp_neg *neg, + const pjmedia_sdp_session **offer) { /* Check arguments are valid. */ PJ_ASSERT_RETURN(neg && offer, PJ_EINVAL); @@ -210,47 +238,74 @@ pjmedia_sdp_neg_tx_local_offer( pj_pool_t *pool, PJ_DEF(pj_status_t) -pjmedia_sdp_neg_rx_remote_offer( pj_pool_t *pool, - pjmedia_sdp_neg *neg, - const pjmedia_sdp_session *remote) +pjmedia_sdp_neg_set_remote_answer( pj_pool_t *pool, + pjmedia_sdp_neg *neg, + const pjmedia_sdp_session *remote) { /* Check arguments are valid. */ PJ_ASSERT_RETURN(pool && neg && remote, PJ_EINVAL); - /* Can only do this in STATE_DONE. - * If we already provide local offer, then rx_remote_answer() should + /* Can only do this in STATE_LOCAL_OFFER. + * If we haven't provided local offer, then rx_remote_offer() should * be called instead of this function. */ - PJ_ASSERT_RETURN(neg->state == PJMEDIA_SDP_NEG_STATE_DONE, + PJ_ASSERT_RETURN(neg->state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER, PJMEDIA_SDPNEG_EINSTATE); /* We're ready to negotiate. */ neg->state = PJMEDIA_SDP_NEG_STATE_WAIT_NEGO; + neg->has_remote_answer = 1; neg->neg_remote_sdp = pjmedia_sdp_session_clone(pool, remote); - + return PJ_SUCCESS; } PJ_DEF(pj_status_t) -pjmedia_sdp_neg_rx_remote_answer( pj_pool_t *pool, +pjmedia_sdp_neg_set_remote_offer( pj_pool_t *pool, pjmedia_sdp_neg *neg, const pjmedia_sdp_session *remote) { /* Check arguments are valid. */ PJ_ASSERT_RETURN(pool && neg && remote, PJ_EINVAL); - /* Can only do this in STATE_LOCAL_OFFER. - * If we haven't provided local offer, then rx_remote_offer() should + /* Can only do this in STATE_DONE. + * If we already provide local offer, then rx_remote_answer() should * be called instead of this function. */ - PJ_ASSERT_RETURN(neg->state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER, + PJ_ASSERT_RETURN(neg->state == PJMEDIA_SDP_NEG_STATE_DONE, PJMEDIA_SDPNEG_EINSTATE); - /* We're ready to negotiate. */ - neg->state = PJMEDIA_SDP_NEG_STATE_WAIT_NEGO; - neg->has_remote_answer = 1; + /* State now is STATE_REMOTE_OFFER. */ + neg->state = PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER; neg->neg_remote_sdp = pjmedia_sdp_session_clone(pool, remote); - + + return PJ_SUCCESS; +} + +PJ_DEF(pj_status_t) +pjmedia_sdp_neg_set_local_answer( pj_pool_t *pool, + pjmedia_sdp_neg *neg, + const pjmedia_sdp_session *local) +{ + /* Check arguments are valid. */ + PJ_ASSERT_RETURN(pool && neg && local, PJ_EINVAL); + + /* Can only do this in STATE_REMOTE_OFFER. + * If we already provide local offer, then rx_remote_answer() should + * be called instead of this function. + */ + PJ_ASSERT_RETURN(neg->state == PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER, + PJMEDIA_SDPNEG_EINSTATE); + + /* State now is STATE_WAIT_NEGO. */ + neg->state = PJMEDIA_SDP_NEG_STATE_WAIT_NEGO; + if (local) + neg->neg_local_sdp = pjmedia_sdp_session_clone(pool, local); + else { + PJ_ASSERT_RETURN(neg->initial_sdp, PJMEDIA_SDPNEG_ENOINITIAL); + neg->neg_local_sdp = pjmedia_sdp_session_clone(pool, neg->initial_sdp); + } + return PJ_SUCCESS; } @@ -463,6 +518,7 @@ static pj_status_t process_answer(pj_pool_t *pool, pjmedia_sdp_session **p_active) { unsigned mi; + pj_bool_t has_active = PJ_FALSE; pj_status_t status; /* Check arguments. */ @@ -478,10 +534,14 @@ static pj_status_t process_answer(pj_pool_t *pool, allow_asym); if (status != PJ_SUCCESS) return status; + + if (offer->media[mi]->desc.port != 0) + has_active = PJ_TRUE; } *p_active = offer; - return PJ_SUCCESS; + + return has_active ? PJ_SUCCESS : PJMEDIA_SDPNEG_ENOMEDIA; } /* Try to match offer with answer. */ @@ -674,6 +734,7 @@ static pj_status_t create_answer( pj_pool_t *pool, pjmedia_sdp_session **p_answer) { pj_status_t status; + pj_bool_t has_active = PJ_FALSE; pjmedia_sdp_session *answer; char media_used[PJSDP_MAX_MEDIA]; unsigned i; @@ -748,10 +809,15 @@ static pj_status_t create_answer( pj_pool_t *pool, /* Add the media answer */ answer->media[answer->media_count++] = am; + + /* Check if this media is active.*/ + if (am->desc.port != 0) + has_active = PJ_TRUE; } *p_answer = answer; - return PJ_SUCCESS; + + return has_active ? PJ_SUCCESS : PJMEDIA_SDPNEG_ENOMEDIA; } /* The best bit: SDP negotiation function! */ @@ -784,7 +850,7 @@ PJ_DEF(pj_status_t) pjmedia_sdp_neg_negotiate( pj_pool_t *pool, } else { pjmedia_sdp_session *answer; - status = create_answer(pool, neg->initial_sdp, neg->neg_remote_sdp, + status = create_answer(pool, neg->neg_local_sdp, neg->neg_remote_sdp, &answer); if (status == PJ_SUCCESS) { pj_uint32_t active_ver; -- cgit v1.2.3