summaryrefslogtreecommitdiff
path: root/pjmedia
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2006-02-07 12:34:58 +0000
committerBenny Prijono <bennylp@teluu.com>2006-02-07 12:34:58 +0000
commitda1de0865a23a7eb5cde2b4160979164dbc08a39 (patch)
tree743e536bd0159318ba904b471d574fdd9dd9f521 /pjmedia
parent9cded7c4883dc2eccfddf1b74b8175ac179d5703 (diff)
Added STATE_REMOTE_OFFER state in negotiator
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@140 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjmedia')
-rw-r--r--pjmedia/include/pjmedia/errno.h25
-rw-r--r--pjmedia/include/pjmedia/sdp_neg.h266
-rw-r--r--pjmedia/src/pjmedia/errno.c3
-rw-r--r--pjmedia/src/pjmedia/sdp.c3
-rw-r--r--pjmedia/src/pjmedia/sdp_neg.c140
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
@@ -149,29 +149,44 @@ PJ_DECL(pj_str_t) pjmedia_strerror( pj_status_t status, char *buffer,
#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.
+ *
+ * <pre>
+ * 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() +--------------+
+ *
+ * </pre>
*/
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;