summaryrefslogtreecommitdiff
path: root/pjsip
diff options
context:
space:
mode:
authorLiong Sauw Ming <ming@teluu.com>2011-10-24 09:28:13 +0000
committerLiong Sauw Ming <ming@teluu.com>2011-10-24 09:28:13 +0000
commit2068f13bc42cf3a47374aa2765f82724a5782028 (patch)
tree29fbeaa152ab51e59b650c0d7cd83a38111e1ecc /pjsip
parent1c72a42676e7aa0c2ae0734549050f738f3bdf02 (diff)
Re #1395: Backport of PJSIP 1.x branch into PJSIP 2.0 trunk
* Backport of r3557:r3832 TODO: ticket #1268 (Option for automatic/manual sending of RTCP SDES/BYE for the stream) for video stream. git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@3841 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjsip')
-rw-r--r--pjsip/include/pjsip-ua/sip_inv.h1
-rw-r--r--pjsip/include/pjsip/sip_config.h10
-rw-r--r--pjsip/include/pjsip/sip_endpoint.h4
-rw-r--r--pjsip/include/pjsua-lib/pjsua.h168
-rw-r--r--pjsip/include/pjsua-lib/pjsua_internal.h11
-rw-r--r--pjsip/src/pjsip-simple/evsub_msg.c2
-rw-r--r--pjsip/src/pjsip-simple/pidf.c7
-rw-r--r--pjsip/src/pjsip-ua/sip_100rel.c70
-rw-r--r--pjsip/src/pjsip-ua/sip_inv.c25
-rw-r--r--pjsip/src/pjsip/sip_multipart.c5
-rw-r--r--pjsip/src/pjsip/sip_transaction.c28
-rw-r--r--pjsip/src/pjsip/sip_util.c17
-rw-r--r--pjsip/src/pjsua-lib/pjsua_acc.c56
-rw-r--r--pjsip/src/pjsua-lib/pjsua_call.c73
-rw-r--r--pjsip/src/pjsua-lib/pjsua_core.c35
-rw-r--r--pjsip/src/pjsua-lib/pjsua_media.c55
-rw-r--r--pjsip/src/pjsua-lib/pjsua_pres.c44
17 files changed, 499 insertions, 112 deletions
diff --git a/pjsip/include/pjsip-ua/sip_inv.h b/pjsip/include/pjsip-ua/sip_inv.h
index 4fe44758..f3bceb28 100644
--- a/pjsip/include/pjsip-ua/sip_inv.h
+++ b/pjsip/include/pjsip-ua/sip_inv.h
@@ -367,6 +367,7 @@ struct pjsip_inv_session
pjsip_status_code cause; /**< Disconnect cause. */
pj_str_t cause_text; /**< Cause text. */
pj_bool_t notify; /**< Internal. */
+ unsigned cb_called; /**< Cb has been called */
pjsip_dialog *dlg; /**< Underlying dialog. */
pjsip_role_e role; /**< Invite role. */
unsigned options; /**< Options in use. */
diff --git a/pjsip/include/pjsip/sip_config.h b/pjsip/include/pjsip/sip_config.h
index 78c324b8..6398e774 100644
--- a/pjsip/include/pjsip/sip_config.h
+++ b/pjsip/include/pjsip/sip_config.h
@@ -668,6 +668,16 @@ PJ_INLINE(pjsip_cfg_t*) pjsip_cfg(void)
# define PJSIP_POOL_TSX_INC 256
#endif
+/**
+ * Delay for non-100 1xx retransmission, in seconds.
+ * Set to 0 to disable this feature.
+ *
+ * Default: 60 seconds
+ */
+#ifndef PJSIP_TSX_1XX_RETRANS_DELAY
+# define PJSIP_TSX_1XX_RETRANS_DELAY 60
+#endif
+
#define PJSIP_MAX_TSX_KEY_LEN (PJSIP_MAX_URL_SIZE*2)
/* User agent. */
diff --git a/pjsip/include/pjsip/sip_endpoint.h b/pjsip/include/pjsip/sip_endpoint.h
index 3f3dbb39..e957271c 100644
--- a/pjsip/include/pjsip/sip_endpoint.h
+++ b/pjsip/include/pjsip/sip_endpoint.h
@@ -56,8 +56,8 @@ PJ_BEGIN_DECL
* existing modules (such as when incoming request has unsupported method).
* - and so on..
*
- * Theoritically application can have multiple instances of SIP endpoint,
- * although it's not clear why application may want to do it.
+ * Application should only instantiate one SIP endpoint instance for every
+ * process.
*
* @{
*/
diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h
index 636d0955..cedb1d97 100644
--- a/pjsip/include/pjsua-lib/pjsua.h
+++ b/pjsip/include/pjsua-lib/pjsua.h
@@ -539,6 +539,22 @@ typedef pj_status_t
/**
+ * This enumeration specifies the options for custom media transport creation.
+ */
+typedef enum pjsua_create_media_transport_flag
+{
+ /**
+ * This flag indicates that the media transport must also close its
+ * "member" or "child" transport when pjmedia_transport_close() is
+ * called. If this flag is not specified, then the media transport
+ * must not call pjmedia_transport_close() of its member transport.
+ */
+ PJSUA_MED_TP_CLOSE_MEMBER = 1
+
+} pjsua_create_media_transport_flag;
+
+
+/**
* This structure describes application callback to receive various event
* notification from PJSUA-API. All of these callbacks are OPTIONAL,
* although definitely application would want to implement some of
@@ -706,6 +722,18 @@ typedef struct pjsua_callback
/**
+ * Notify application when registration or unregistration has been
+ * initiated. Note that this only notifies the initial registration
+ * and unregistration. Once registration session is active, subsequent
+ * refresh will not cause this callback to be called.
+ *
+ * @param acc_id The account ID.
+ * @param renew Non-zero for registration and zero for
+ * unregistration.
+ */
+ void (*on_reg_started)(pjsua_acc_id acc_id, pj_bool_t renew);
+
+ /**
* Notify application when registration status has changed.
* Application may then query the account info to get the
* registration details.
@@ -1074,6 +1102,32 @@ typedef struct pjsua_callback
unsigned med_idx,
pjmedia_event *event);
+ /**
+ * This callback can be used by application to implement custom media
+ * transport adapter for the call, or to replace the media transport
+ * with something completely new altogether.
+ *
+ * This callback is called when a new call is created. The library has
+ * created a media transport for the call, and it is provided as the
+ * \a base_tp argument of this callback. Upon returning, the callback
+ * must return an instance of media transport to be used by the call.
+ *
+ * @param call_id Call ID
+ * @param media_idx The media index in the SDP for which this media
+ * transport will be used.
+ * @param base_tp The media transport which otherwise will be
+ * used by the call has this callback not been
+ * implemented.
+ * @param flags Bitmask from pjsua_create_media_transport_flag.
+ *
+ * @return The callback must return an instance of media
+ * transport to be used by the call.
+ */
+ pjmedia_transport* (*on_create_media_transport)(pjsua_call_id call_id,
+ unsigned media_idx,
+ pjmedia_transport *base_tp,
+ unsigned flags);
+
} pjsua_callback;
@@ -1110,6 +1164,34 @@ typedef enum pjsua_sip_timer_use
/**
+ * This constants controls the use of 100rel extension.
+ */
+typedef enum pjsua_100rel_use
+{
+ /**
+ * Not used. For UAC, support for 100rel will be indicated in Supported
+ * header so that peer can opt to use it if it wants to. As UAS, this
+ * option will NOT cause 100rel to be used even if UAC indicates that
+ * it supports this feature.
+ */
+ PJSUA_100REL_NOT_USED,
+
+ /**
+ * Mandatory. UAC will place 100rel in Require header, and UAS will
+ * reject incoming calls unless it has 100rel in Supported header.
+ */
+ PJSUA_100REL_MANDATORY,
+
+ /**
+ * Optional. Similar to PJSUA_100REL_NOT_USED, except that as UAS, this
+ * option will cause 100rel to be used if UAC indicates that it supports it.
+ */
+ PJSUA_100REL_OPTIONAL
+
+} pjsua_100rel_use;
+
+
+/**
* This structure describes the settings to control the API and
* user agent behavior, and can be specified when calling #pjsua_init().
* Before setting the values, application must call #pjsua_config_default()
@@ -1245,13 +1327,13 @@ typedef struct pjsua_config
int nat_type_in_sdp;
/**
- * Specify whether support for reliable provisional response (100rel and
- * PRACK) should be required by default. Note that this setting can be
+ * Specify how the support for reliable provisional response (100rel/
+ * PRACK) should be used by default. Note that this setting can be
* further customized in account configuration (#pjsua_acc_config).
*
- * Default: PJ_FALSE
+ * Default: PJSUA_100REL_NOT_USED
*/
- pj_bool_t require_100rel;
+ pjsua_100rel_use require_100rel;
/**
* Specify the usage of Session Timers for all sessions. See the
@@ -1366,6 +1448,35 @@ typedef struct pjsua_config
/**
+ * Flags to be given to pjsua_destroy2()
+ */
+typedef enum pjsua_destroy_flag
+{
+ /**
+ * Allow sending outgoing messages (such as unregistration, event
+ * unpublication, BYEs, unsubscription, etc.), but do not wait for
+ * responses. This is useful to perform "best effort" clean up
+ * without delaying the shutdown process waiting for responses.
+ */
+ PJSUA_DESTROY_NO_RX_MSG = 1,
+
+ /**
+ * If this flag is set, do not send any outgoing messages at all.
+ * This flag is useful if application knows that the network which
+ * the messages are to be sent on is currently down.
+ */
+ PJSUA_DESTROY_NO_TX_MSG = 2,
+
+ /**
+ * Do not send or receive messages during destroy. This flag is
+ * shorthand for PJSUA_DESTROY_NO_RX_MSG + PJSUA_DESTROY_NO_TX_MSG.
+ */
+ PJSUA_DESTROY_NO_NETWORK = PJSUA_DESTROY_NO_RX_MSG |
+ PJSUA_DESTROY_NO_TX_MSG
+
+} pjsua_destroy_flag;
+
+/**
* Use this function to initialize pjsua config.
*
* @param cfg pjsua config to be initialized.
@@ -1513,6 +1624,8 @@ PJ_DECL(pj_status_t) pjsua_start(void);
* Application.may safely call this function more than once if it doesn't
* keep track of it's state.
*
+ * @see pjsua_destroy2()
+ *
* @return PJ_SUCCESS on success, or the appropriate error code.
*/
PJ_DECL(pj_status_t) pjsua_destroy(void);
@@ -1527,6 +1640,16 @@ PJ_DECL(pjsua_state) pjsua_get_state(void);
/**
+ * Variant of destroy with additional flags.
+ *
+ * @param flags Combination of pjsua_destroy_flag enumeration.
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pjsua_destroy2(unsigned flags);
+
+
+/**
* Poll pjsua for events, and if necessary block the caller thread for
* the specified maximum interval (in miliseconds).
*
@@ -2395,12 +2518,14 @@ typedef struct pjsua_acc_config
pj_str_t contact_uri_params;
/**
- * Specify whether support for reliable provisional response (100rel and
- * PRACK) should be required for all sessions of this account.
+ * Specify how support for reliable provisional response (100rel/
+ * PRACK) should be used for all sessions in this account. See the
+ * documentation of pjsua_100rel_use enumeration for more info.
*
- * Default: PJ_FALSE
+ * Default: The default value is taken from the value of
+ * require_100rel in pjsua_config.
*/
- pj_bool_t require_100rel;
+ pjsua_100rel_use require_100rel;
/**
* Specify the usage of Session Timers for all sessions. See the
@@ -2676,13 +2801,28 @@ typedef struct pjsua_acc_config
/**
* Specify interval of auto registration retry upon registration failure
* (including caused by transport problem), in second. Set to 0 to
- * disable auto re-registration.
+ * disable auto re-registration. Note that if the registration retry
+ * occurs because of transport failure, the first retry will be done
+ * after \a reg_first_retry_interval seconds instead. Also note that
+ * the interval will be randomized slightly by approximately +/- ten
+ * seconds to avoid all clients re-registering at the same time.
+ *
+ * See also \a reg_first_retry_interval setting.
*
* Default: #PJSUA_REG_RETRY_INTERVAL
*/
unsigned reg_retry_interval;
/**
+ * This specifies the interval for the first registration retry. The
+ * registration retry is explained in \a reg_retry_interval. Note that
+ * the value here will also be randomized by +/- ten seconds.
+ *
+ * Default: 0
+ */
+ unsigned reg_first_retry_interval;
+
+ /**
* Specify whether calls of the configured account should be dropped
* after registration failure and an attempt of re-registration has
* also failed.
@@ -2721,6 +2861,16 @@ typedef struct pjsua_acc_config
* Default: PJSUA_CALL_HOLD_TYPE_DEFAULT
*/
pjsua_call_hold_type call_hold_type;
+
+
+ /**
+ * Specify whether the account should register as soon as it is
+ * added to the UA. Application can set this to PJ_FALSE and control
+ * the registration manually with pjsua_acc_set_registration().
+ *
+ * Default: PJ_TRUE
+ */
+ pj_bool_t register_on_acc_add;
} pjsua_acc_config;
diff --git a/pjsip/include/pjsua-lib/pjsua_internal.h b/pjsip/include/pjsua-lib/pjsua_internal.h
index b15a102e..db566ed5 100644
--- a/pjsip/include/pjsua-lib/pjsua_internal.h
+++ b/pjsip/include/pjsua-lib/pjsua_internal.h
@@ -43,6 +43,7 @@ struct pjsua_call_media
pjmedia_type type; /**< Media type. */
unsigned idx; /**< This media index in parent call. */
pjsua_call_media_status state; /**< Media state. */
+ pjsua_call_media_status prev_state;/**< Previous media state. */
pjmedia_dir dir; /**< Media direction. */
/** The stream */
@@ -78,6 +79,7 @@ struct pjsua_call_media
pjmedia_transport *tp_orig; /**< Original media transport */
pj_bool_t tp_auto_del; /**< May delete media transport */
pjsua_med_tp_st tp_st; /**< Media transport state */
+ pj_bool_t use_custom_med_tp;/**< Use custom media transport? */
pj_sockaddr rtp_addr; /**< Current RTP source address
(used to update ICE default
address) */
@@ -130,6 +132,7 @@ struct pjsua_call
int secure_level;/**< Signaling security level. */
pjsua_call_hold_type call_hold_type; /**< How to do call hold. */
pj_bool_t local_hold;/**< Flag for call-hold by local. */
+ void *hold_msg; /**< Outgoing hold tx_data. */
unsigned med_cnt; /**< Number of media in SDP. */
pjsua_call_media media[PJSUA_MAX_CALL_MEDIA]; /**< Array of media */
@@ -580,7 +583,7 @@ void pjsua_pres_update_acc(int acc_id, pj_bool_t force);
/*
* Shutdown presence.
*/
-void pjsua_pres_shutdown(void);
+void pjsua_pres_shutdown(unsigned flags);
/**
* Init presence for aoocunt.
@@ -595,12 +598,12 @@ pj_status_t pjsua_pres_init_publish_acc(int acc_id);
/**
* Send un-PUBLISH
*/
-void pjsua_pres_unpublish(pjsua_acc *acc);
+void pjsua_pres_unpublish(pjsua_acc *acc, unsigned flags);
/**
* Terminate server subscription for the account
*/
-void pjsua_pres_delete_acc(int acc_id);
+void pjsua_pres_delete_acc(int acc_id, unsigned flags);
/**
* Init IM module handler to handle incoming MESSAGE outside dialog.
@@ -635,7 +638,7 @@ pj_status_t pjsua_media_subsys_start(void);
/**
* Destroy pjsua media subsystem.
*/
-pj_status_t pjsua_media_subsys_destroy(void);
+pj_status_t pjsua_media_subsys_destroy(unsigned flags);
/**
* Private: check if we can accept the message.
diff --git a/pjsip/src/pjsip-simple/evsub_msg.c b/pjsip/src/pjsip-simple/evsub_msg.c
index 77e4b489..df2dd550 100644
--- a/pjsip/src/pjsip-simple/evsub_msg.c
+++ b/pjsip/src/pjsip-simple/evsub_msg.c
@@ -295,7 +295,7 @@ static pjsip_hdr* parse_hdr_sub_state( pjsip_parse_ctx *ctx )
*/
PJ_DEF(void) pjsip_evsub_init_parser(void)
{
- pjsip_register_hdr_parser( "Event", NULL,
+ pjsip_register_hdr_parser( "Event", "o",
&parse_hdr_event);
pjsip_register_hdr_parser( "Subscription-State", NULL,
diff --git a/pjsip/src/pjsip-simple/pidf.c b/pjsip/src/pjsip-simple/pidf.c
index 4787d9a8..b90725d4 100644
--- a/pjsip/src/pjsip-simple/pidf.c
+++ b/pjsip/src/pjsip-simple/pidf.c
@@ -324,15 +324,16 @@ PJ_DEF(void) pjpidf_status_construct(pj_pool_t *pool, pjpidf_status *st)
PJ_DEF(pj_bool_t) pjpidf_status_is_basic_open(const pjpidf_status *st)
{
pj_xml_node *node = pj_xml_find_node((pj_xml_node*)st, &BASIC);
- pj_assert(node != NULL);
+ if (!node)
+ return PJ_FALSE;
return pj_stricmp(&node->content, &OPEN)==0;
}
PJ_DEF(void) pjpidf_status_set_basic_open(pjpidf_status *st, pj_bool_t open)
{
pj_xml_node *node = pj_xml_find_node(st, &BASIC);
- pj_assert(node != NULL);
- node->content = open ? OPEN : CLOSED;
+ if (node)
+ node->content = open ? OPEN : CLOSED;
}
PJ_DEF(pjpidf_pres*) pjpidf_create(pj_pool_t *pool, const pj_str_t *entity)
diff --git a/pjsip/src/pjsip-ua/sip_100rel.c b/pjsip/src/pjsip-ua/sip_100rel.c
index 5d49731e..d2bb1d42 100644
--- a/pjsip/src/pjsip-ua/sip_100rel.c
+++ b/pjsip/src/pjsip-ua/sip_100rel.c
@@ -105,8 +105,10 @@ typedef struct uas_state_t
/* UAC state */
typedef struct uac_state_t
{
- pj_int32_t cseq;
- pj_uint32_t rseq; /* Initialized to -1 */
+ pj_str_t tag; /* To tag */
+ pj_int32_t cseq;
+ pj_uint32_t rseq; /* Initialized to -1 */
+ struct uac_state_t *next; /* next call leg */
} uac_state_t;
@@ -115,7 +117,7 @@ struct dlg_data
{
pjsip_inv_session *inv;
uas_state_t *uas_state;
- uac_state_t *uac_state;
+ uac_state_t *uac_state_list;
};
@@ -231,6 +233,8 @@ PJ_DEF(pj_status_t) pjsip_100rel_create_prack( pjsip_inv_session *inv,
pjsip_tx_data **p_tdata)
{
dlg_data *dd;
+ uac_state_t *uac_state = NULL;
+ const pj_str_t *to_tag = &rdata->msg_info.to->tag;
pjsip_transaction *tsx;
pjsip_msg *msg;
pjsip_generic_string_hdr *rseq_hdr;
@@ -261,41 +265,51 @@ PJ_DEF(pj_status_t) pjsip_100rel_create_prack( pjsip_inv_session *inv,
pjsip_msg_find_hdr_by_name(msg, &RSEQ, NULL);
if (rseq_hdr == NULL) {
PJ_LOG(4,(dd->inv->dlg->obj_name,
- "Ignoring provisional response with no RSeq header"));
+ "Ignoring 100rel response with no RSeq header"));
return PJSIP_EMISSINGHDR;
}
rseq = (pj_uint32_t) pj_strtoul(&rseq_hdr->hvalue);
+ /* Find UAC state for the specified call leg */
+ uac_state = dd->uac_state_list;
+ while (uac_state) {
+ if (pj_strcmp(&uac_state->tag, to_tag)==0)
+ break;
+ uac_state = uac_state->next;
+ }
+
/* Create new UAC state if we don't have one */
- if (dd->uac_state == NULL) {
- dd->uac_state = PJ_POOL_ZALLOC_T(dd->inv->dlg->pool,
- uac_state_t);
- dd->uac_state->cseq = rdata->msg_info.cseq->cseq;
- dd->uac_state->rseq = rseq - 1;
+ if (uac_state == NULL) {
+ uac_state = PJ_POOL_ZALLOC_T(dd->inv->dlg->pool, uac_state_t);
+ uac_state->cseq = rdata->msg_info.cseq->cseq;
+ uac_state->rseq = rseq - 1;
+ pj_strdup(dd->inv->dlg->pool, &uac_state->tag, to_tag);
+ uac_state->next = dd->uac_state_list;
+ dd->uac_state_list = uac_state;
}
- /* If this is from new INVITE transaction, reset UAC state */
- if (rdata->msg_info.cseq->cseq != dd->uac_state->cseq) {
- dd->uac_state->cseq = rdata->msg_info.cseq->cseq;
- dd->uac_state->rseq = rseq - 1;
+ /* If this is from new INVITE transaction, reset UAC state. */
+ if (rdata->msg_info.cseq->cseq != uac_state->cseq) {
+ uac_state->cseq = rdata->msg_info.cseq->cseq;
+ uac_state->rseq = rseq - 1;
}
/* Ignore provisional response retransmission */
- if (rseq <= dd->uac_state->rseq) {
+ if (rseq <= uac_state->rseq) {
/* This should have been handled before */
return PJ_EIGNORED;
/* Ignore provisional response with out-of-order RSeq */
- } else if (rseq != dd->uac_state->rseq + 1) {
+ } else if (rseq != uac_state->rseq + 1) {
PJ_LOG(4,(dd->inv->dlg->obj_name,
- "Ignoring provisional response because RSeq jump "
+ "Ignoring 100rel response because RSeq jump "
"(expecting %u, got %u)",
- dd->uac_state->rseq+1, rseq));
+ uac_state->rseq+1, rseq));
return PJ_EIGNORED;
}
/* Update our RSeq */
- dd->uac_state->rseq = rseq;
+ uac_state->rseq = rseq;
/* Create PRACK */
status = pjsip_dlg_create_request(dd->inv->dlg, &pjsip_prack_method,
@@ -303,6 +317,26 @@ PJ_DEF(pj_status_t) pjsip_100rel_create_prack( pjsip_inv_session *inv,
if (status != PJ_SUCCESS)
return status;
+ /* If this response is a forked response from a different call-leg,
+ * update the req URI (https://trac.pjsip.org/repos/ticket/1364)
+ */
+ if (pj_strcmp(&uac_state->tag, &dd->inv->dlg->remote.info->tag)) {
+ const pjsip_contact_hdr *mhdr;
+
+ mhdr = (const pjsip_contact_hdr*)
+ pjsip_msg_find_hdr(rdata->msg_info.msg,
+ PJSIP_H_CONTACT, NULL);
+ if (!mhdr || !mhdr->uri) {
+ PJ_LOG(4,(dd->inv->dlg->obj_name,
+ "Ignoring 100rel response with no or "
+ "invalid Contact header"));
+ pjsip_tx_data_dec_ref(tdata);
+ return PJ_EIGNORED;
+ }
+ tdata->msg->line.req.uri = (pjsip_uri*)
+ pjsip_uri_clone(tdata->pool, mhdr->uri);
+ }
+
/* Create RAck header */
rack.ptr = rack_buf;
rack.slen = pj_ansi_snprintf(rack.ptr, sizeof(rack_buf),
diff --git a/pjsip/src/pjsip-ua/sip_inv.c b/pjsip/src/pjsip-ua/sip_inv.c
index eca737eb..46153c9f 100644
--- a/pjsip/src/pjsip-ua/sip_inv.c
+++ b/pjsip/src/pjsip-ua/sip_inv.c
@@ -195,8 +195,18 @@ void inv_set_state(pjsip_inv_session *inv, pjsip_inv_state state,
pjsip_event *e)
{
pjsip_inv_state prev_state = inv->state;
+ pj_bool_t dont_notify = PJ_FALSE;
pj_status_t status;
+ /* Prevent STATE_CALLING from being reported more than once because
+ * of authentication
+ * https://trac.pjsip.org/repos/ticket/1318
+ */
+ if (state==PJSIP_INV_STATE_CALLING &&
+ (inv->cb_called & (1 << PJSIP_INV_STATE_CALLING)) != 0)
+ {
+ dont_notify = PJ_TRUE;
+ }
/* If state is confirmed, check that SDP negotiation is done,
* otherwise disconnect the session.
@@ -224,8 +234,11 @@ void inv_set_state(pjsip_inv_session *inv, pjsip_inv_state state,
pj_assert(inv->state != PJSIP_INV_STATE_DISCONNECTED ||
inv->cause != 0);
+ /* Mark the callback as called for this state */
+ inv->cb_called |= (1 << state);
+
/* Call on_state_changed() callback. */
- if (mod_inv.cb.on_state_changed && inv->notify)
+ if (mod_inv.cb.on_state_changed && inv->notify && !dont_notify)
(*mod_inv.cb.on_state_changed)(inv, e);
/* Only decrement when previous state is not already DISCONNECTED */
@@ -4116,6 +4129,16 @@ static void inv_on_state_confirmed( pjsip_inv_session *inv, pjsip_event *e)
/* Not Acceptable */
const pjsip_hdr *accept;
+ /* The incoming SDP is unacceptable. If the SDP negotiator
+ * state has just been changed, i.e: DONE -> REMOTE_OFFER,
+ * revert it back.
+ */
+ if (pjmedia_sdp_neg_get_state(inv->neg) ==
+ PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER)
+ {
+ pjmedia_sdp_neg_cancel_offer(inv->neg);
+ }
+
status = pjsip_dlg_create_response(inv->dlg, rdata,
488, NULL, &tdata);
if (status != PJ_SUCCESS)
diff --git a/pjsip/src/pjsip/sip_multipart.c b/pjsip/src/pjsip/sip_multipart.c
index c4ae647e..45c7fcaa 100644
--- a/pjsip/src/pjsip/sip_multipart.c
+++ b/pjsip/src/pjsip/sip_multipart.c
@@ -81,10 +81,13 @@ static int multipart_print_body(struct pjsip_msg_body *msg_body,
/* Print optional headers */
hdr = part->hdr.next;
while (hdr != &part->hdr) {
- int printed = pjsip_hdr_print_on((pjsip_hdr*)hdr, p, SIZE_LEFT());
+ int printed = pjsip_hdr_print_on((pjsip_hdr*)hdr, p,
+ SIZE_LEFT()-2);
if (printed < 0)
return -1;
p += printed;
+ *p++ = '\r';
+ *p++ = '\n';
hdr = hdr->next;
}
diff --git a/pjsip/src/pjsip/sip_transaction.c b/pjsip/src/pjsip/sip_transaction.c
index bdc7b26f..c127162b 100644
--- a/pjsip/src/pjsip/sip_transaction.c
+++ b/pjsip/src/pjsip/sip_transaction.c
@@ -146,13 +146,6 @@ static pj_time_val timeout_timer_val = { (64*PJSIP_T1_TIMEOUT)/1000,
#define TIMER_INACTIVE 0
#define TIMER_ACTIVE 1
-/* Delay for 1xx retransmission (should be 60 seconds).
- * Specify 0 to disable this feature
- */
-#ifndef PJSIP_TSX_1XX_RETRANS_DELAY
-# define PJSIP_TSX_1XX_RETRANS_DELAY 60
-#endif
-
/* Prototypes. */
static void lock_tsx(pjsip_transaction *tsx, struct tsx_lock_data *lck);
@@ -2118,7 +2111,6 @@ PJ_DEF(pj_status_t) pjsip_tsx_retransmit_no_state(pjsip_transaction *tsx,
*/
static void tsx_resched_retransmission( pjsip_transaction *tsx )
{
- pj_time_val timeout;
pj_uint32_t msec_time;
pj_assert((tsx->transport_flag & TSX_HAS_PENDING_TRANSPORT) == 0);
@@ -2151,11 +2143,15 @@ static void tsx_resched_retransmission( pjsip_transaction *tsx )
}
}
- timeout.sec = msec_time / 1000;
- timeout.msec = msec_time % 1000;
- tsx->retransmit_timer.id = TIMER_ACTIVE;
- pjsip_endpt_schedule_timer( tsx->endpt, &tsx->retransmit_timer,
- &timeout);
+ if (msec_time != 0) {
+ pj_time_val timeout;
+
+ timeout.sec = msec_time / 1000;
+ timeout.msec = msec_time % 1000;
+ tsx->retransmit_timer.id = TIMER_ACTIVE;
+ pjsip_endpt_schedule_timer( tsx->endpt, &tsx->retransmit_timer,
+ &timeout);
+ }
}
/*
@@ -2987,6 +2983,12 @@ static pj_status_t tsx_on_state_proceeding_uac(pjsip_transaction *tsx,
timeout.sec = timeout.msec = 0;
}
lock_timer(tsx);
+ /* In the short period above timer may have been inserted
+ * by set_timeout() (by CANCEL). Cancel it if necessary. See:
+ * https://trac.pjsip.org/repos/ticket/1374
+ */
+ if (tsx->timeout_timer.id)
+ pjsip_endpt_cancel_timer( tsx->endpt, &tsx->timeout_timer );
tsx->timeout_timer.id = TIMER_ACTIVE;
pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, &timeout);
unlock_timer(tsx);
diff --git a/pjsip/src/pjsip/sip_util.c b/pjsip/src/pjsip/sip_util.c
index bdf8fe6a..4f82a1a6 100644
--- a/pjsip/src/pjsip/sip_util.c
+++ b/pjsip/src/pjsip/sip_util.c
@@ -813,6 +813,8 @@ static pj_status_t get_dest_info(const pjsip_uri *target_uri,
if (PJSIP_URI_SCHEME_IS_SIPS(target_uri)) {
pjsip_uri *uri = (pjsip_uri*) target_uri;
const pjsip_sip_uri *url=(const pjsip_sip_uri*)pjsip_uri_get_uri(uri);
+ unsigned flag;
+
dest_info->flag |= (PJSIP_TRANSPORT_SECURE | PJSIP_TRANSPORT_RELIABLE);
if (url->maddr_param.slen)
pj_strdup(pool, &dest_info->addr.host, &url->maddr_param);
@@ -821,6 +823,18 @@ static pj_status_t get_dest_info(const pjsip_uri *target_uri,
dest_info->addr.port = url->port;
dest_info->type =
pjsip_transport_get_type_from_name(&url->transport_param);
+ /* Double-check that the transport parameter match.
+ * Sample case: sips:host;transport=tcp
+ * See https://trac.pjsip.org/repos/ticket/1319
+ */
+ flag = pjsip_transport_get_flag_from_type(dest_info->type);
+ if ((flag & dest_info->flag) != dest_info->flag) {
+ pjsip_transport_type_e t;
+
+ t = pjsip_transport_get_type_from_flag(dest_info->flag);
+ if (t != PJSIP_TRANSPORT_UNSPECIFIED)
+ dest_info->type = t;
+ }
} else if (PJSIP_URI_SCHEME_IS_SIP(target_uri)) {
pjsip_uri *uri = (pjsip_uri*) target_uri;
@@ -1390,6 +1404,9 @@ static void send_raw_resolver_callback( pj_status_t status,
pj_assert(addr->count != 0);
+ /* Avoid tdata destroyed by pjsip_tpmgr_send_raw(). */
+ pjsip_tx_data_add_ref(sraw_data->tdata);
+
data_len = sraw_data->tdata->buf.cur - sraw_data->tdata->buf.start;
status = pjsip_tpmgr_send_raw(pjsip_endpt_get_tpmgr(sraw_data->endpt),
addr->entry[0].type,
diff --git a/pjsip/src/pjsua-lib/pjsua_acc.c b/pjsip/src/pjsua-lib/pjsua_acc.c
index 9bcd1ddd..226f5d1f 100644
--- a/pjsip/src/pjsua-lib/pjsua_acc.c
+++ b/pjsip/src/pjsua-lib/pjsua_acc.c
@@ -470,9 +470,10 @@ PJ_DEF(pj_status_t) pjsua_acc_add( const pjsua_acc_config *cfg,
(int)cfg->id.slen, cfg->id.ptr, id));
/* If accounts has registration enabled, start registration */
- if (pjsua_var.acc[id].cfg.reg_uri.slen)
- pjsua_acc_set_registration(id, PJ_TRUE);
- else {
+ if (pjsua_var.acc[id].cfg.reg_uri.slen) {
+ if (pjsua_var.acc[id].cfg.register_on_acc_add)
+ pjsua_acc_set_registration(id, PJ_TRUE);
+ } else {
/* Otherwise subscribe to MWI, if it's enabled */
if (pjsua_var.acc[id].cfg.mwi_enabled)
pjsua_start_mwi(&pjsua_var.acc[id]);
@@ -603,7 +604,7 @@ PJ_DEF(pj_status_t) pjsua_acc_del(pjsua_acc_id acc_id)
}
/* Delete server presence subscription */
- pjsua_pres_delete_acc(acc_id);
+ pjsua_pres_delete_acc(acc_id, 0);
/* Release account pool */
if (pjsua_var.acc[acc_id].pool) {
@@ -833,7 +834,7 @@ PJ_DEF(pj_status_t) pjsua_acc_modify( pjsua_acc_id acc_id,
if (acc->cfg.publish_enabled != cfg->publish_enabled) {
acc->cfg.publish_enabled = cfg->publish_enabled;
if (!acc->cfg.publish_enabled)
- pjsua_pres_unpublish(acc);
+ pjsua_pres_unpublish(acc, 0);
else
update_reg = PJ_TRUE;
}
@@ -992,6 +993,7 @@ PJ_DEF(pj_status_t) pjsua_acc_modify( pjsua_acc_id acc_id,
acc->cfg.unreg_timeout = cfg->unreg_timeout;
acc->cfg.allow_contact_rewrite = cfg->allow_contact_rewrite;
acc->cfg.reg_retry_interval = cfg->reg_retry_interval;
+ acc->cfg.reg_first_retry_interval = cfg->reg_first_retry_interval;
acc->cfg.drop_calls_on_reg_fail = cfg->drop_calls_on_reg_fail;
if (acc->cfg.reg_delay_before_refresh != cfg->reg_delay_before_refresh) {
acc->cfg.reg_delay_before_refresh = cfg->reg_delay_before_refresh;
@@ -1393,7 +1395,7 @@ static pj_bool_t acc_check_nat_addr(pjsua_acc *acc,
tp->type_name,
(int)acc->cfg.contact_uri_params.slen,
acc->cfg.contact_uri_params.ptr,
- ob,
+ (acc->cfg.use_rfc5626? ob: ""),
(int)acc->cfg.contact_params.slen,
acc->cfg.contact_params.ptr);
if (len < 1) {
@@ -1691,11 +1693,14 @@ static void regc_cb(struct pjsip_regc_cbparam *param)
pjsua_acc *acc = (pjsua_acc*) param->token;
- if (param->regc != acc->regc)
+ PJSUA_LOCK();
+
+ if (param->regc != acc->regc) {
+ PJSUA_UNLOCK();
return;
+ }
pj_log_push_indent();
- PJSUA_LOCK();
/*
* Print registration status.
@@ -2054,7 +2059,7 @@ PJ_DEF(pj_status_t) pjsua_acc_set_registration( pjsua_acc_id acc_id,
goto on_return;
}
- pjsua_pres_unpublish(&pjsua_var.acc[acc_id]);
+ pjsua_pres_unpublish(&pjsua_var.acc[acc_id], 0);
status = pjsip_regc_unregister(pjsua_var.acc[acc_id].regc, &tdata);
}
@@ -2070,6 +2075,10 @@ PJ_DEF(pj_status_t) pjsua_acc_set_registration( pjsua_acc_id acc_id,
pjsip_regc_get_info(pjsua_var.acc[acc_id].regc, &reg_info);
pjsua_var.acc[acc_id].auto_rereg.reg_tp = reg_info.transport;
+
+ if (pjsua_var.ua_cfg.cb.on_reg_started) {
+ (*pjsua_var.ua_cfg.cb.on_reg_started)(acc_id, renew);
+ }
}
if (status != PJ_SUCCESS) {
@@ -2529,10 +2538,11 @@ PJ_DEF(pj_status_t) pjsua_acc_create_uac_contact( pj_pool_t *pool,
/* Create the contact header */
contact->ptr = (char*)pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
contact->slen = pj_ansi_snprintf(contact->ptr, PJSIP_MAX_URL_SIZE,
- "%.*s%s<%s:%.*s%s%s%.*s%s:%d%s%.*s%s>%.*s",
+ "%s%.*s%s<%s:%.*s%s%s%.*s%s:%d%s%.*s%s>%.*s",
+ (acc->display.slen?"\"" : ""),
(int)acc->display.slen,
acc->display.ptr,
- (acc->display.slen?" " : ""),
+ (acc->display.slen?"\" " : ""),
(secure ? PJSUA_SECURE_SCHEME : "sip"),
(int)acc->user_part.slen,
acc->user_part.ptr,
@@ -2545,7 +2555,7 @@ PJ_DEF(pj_status_t) pjsua_acc_create_uac_contact( pj_pool_t *pool,
transport_param,
(int)acc->cfg.contact_uri_params.slen,
acc->cfg.contact_uri_params.ptr,
- ob,
+ (acc->cfg.use_rfc5626? ob: ""),
(int)acc->cfg.contact_params.slen,
acc->cfg.contact_params.ptr);
@@ -2687,10 +2697,11 @@ PJ_DEF(pj_status_t) pjsua_acc_create_uas_contact( pj_pool_t *pool,
/* Create the contact header */
contact->ptr = (char*) pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
contact->slen = pj_ansi_snprintf(contact->ptr, PJSIP_MAX_URL_SIZE,
- "%.*s%s<%s:%.*s%s%s%.*s%s:%d%s%.*s>%.*s",
+ "%s%.*s%s<%s:%.*s%s%s%.*s%s:%d%s%.*s>%.*s",
+ (acc->display.slen?"\"" : ""),
(int)acc->display.slen,
acc->display.ptr,
- (acc->display.slen?" " : ""),
+ (acc->display.slen?"\" " : ""),
(secure ? PJSUA_SECURE_SCHEME : "sip"),
(int)acc->user_part.slen,
acc->user_part.ptr,
@@ -2807,8 +2818,23 @@ static void schedule_reregistration(pjsua_acc *acc)
acc->auto_rereg.timer.user_data = acc;
/* Reregistration attempt. The first attempt will be done immediately. */
- delay.sec = acc->auto_rereg.attempt_cnt? acc->cfg.reg_retry_interval : 0;
+ delay.sec = acc->auto_rereg.attempt_cnt? acc->cfg.reg_retry_interval :
+ acc->cfg.reg_first_retry_interval;
delay.msec = 0;
+
+ /* Randomize interval by +/- 10 secs */
+ if (delay.sec >= 10) {
+ delay.msec = -10000 + (pj_rand() % 20000);
+ } else {
+ delay.sec = 0;
+ delay.msec = (pj_rand() % 10000);
+ }
+ pj_time_val_normalize(&delay);
+
+ PJ_LOG(4,(THIS_FILE,
+ "Scheduling re-registration retry for acc %d in %u seconds..",
+ acc->index, delay.sec));
+
pjsua_schedule_timer(&acc->auto_rereg.timer, &delay);
}
diff --git a/pjsip/src/pjsua-lib/pjsua_call.c b/pjsip/src/pjsua-lib/pjsua_call.c
index ad96a4d6..02a78b93 100644
--- a/pjsip/src/pjsua-lib/pjsua_call.c
+++ b/pjsip/src/pjsua-lib/pjsua_call.c
@@ -971,7 +971,7 @@ pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata)
/* Verify that we can handle the request. */
options |= PJSIP_INV_SUPPORT_100REL;
options |= PJSIP_INV_SUPPORT_TIMER;
- if (pjsua_var.acc[acc_id].cfg.require_100rel)
+ if (pjsua_var.acc[acc_id].cfg.require_100rel == PJSUA_100REL_MANDATORY)
options |= PJSIP_INV_REQUIRE_100REL;
if (pjsua_var.media_cfg.enable_ice)
options |= PJSIP_INV_SUPPORT_ICE;
@@ -1047,6 +1047,19 @@ pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata)
options &= ~(PJSIP_INV_SUPPORT_TIMER);
}
+ /* If 100rel is optional and UAC supports it, use it. */
+ if ((options & PJSIP_INV_REQUIRE_100REL)==0 &&
+ pjsua_var.acc[acc_id].cfg.require_100rel == PJSUA_100REL_OPTIONAL)
+ {
+ const pj_str_t token = { "100rel", 6};
+ pjsip_dialog_cap_status cap_status;
+
+ cap_status = pjsip_dlg_remote_has_cap(dlg, PJSIP_H_SUPPORTED, NULL,
+ &token);
+ if (cap_status == PJSIP_DIALOG_CAP_SUPPORTED)
+ options |= PJSIP_INV_REQUIRE_100REL;
+ }
+
/* Create invite session: */
status = pjsip_inv_create_uas( dlg, rdata, NULL, options, &inv);
if (status != PJ_SUCCESS) {
@@ -1288,6 +1301,7 @@ pj_status_t acquire_call(const char *title,
pj_time_val time_start, timeout;
pj_gettimeofday(&time_start);
+ timeout.sec = 0;
timeout.msec = PJSUA_ACQUIRE_CALL_TIMEOUT;
pj_time_val_normalize(&timeout);
@@ -1356,20 +1370,24 @@ pj_status_t acquire_call(const char *title,
PJ_DEF(pjsua_conf_port_id) pjsua_call_get_conf_port(pjsua_call_id call_id)
{
pjsua_call *call;
- pjsua_conf_port_id port_id;
- pjsip_dialog *dlg;
- pj_status_t status;
+ pjsua_conf_port_id port_id = PJSUA_INVALID_ID;
PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls,
PJ_EINVAL);
- status = acquire_call("pjsua_call_get_conf_port()", call_id, &call, &dlg);
- if (status != PJ_SUCCESS)
- return PJSUA_INVALID_ID;
+ /* Use PJSUA_LOCK() instead of acquire_call():
+ * https://trac.pjsip.org/repos/ticket/1371
+ */
+ PJSUA_LOCK();
+ if (!pjsua_call_is_active(call_id))
+ goto on_return;
+
+ call = &pjsua_var.calls[call_id];
port_id = call->media[call->audio_idx].strm.a.conf_slot;
- pjsip_dlg_dec_lock(dlg);
+on_return:
+ PJSUA_UNLOCK();
return port_id;
}
@@ -1383,18 +1401,23 @@ PJ_DEF(pj_status_t) pjsua_call_get_info( pjsua_call_id call_id,
pjsua_call_info *info)
{
pjsua_call *call;
- pjsip_dialog *dlg;
unsigned mi;
- pj_status_t status;
PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls,
PJ_EINVAL);
pj_bzero(info, sizeof(*info));
- status = acquire_call("pjsua_call_get_info()", call_id, &call, &dlg);
- if (status != PJ_SUCCESS) {
- return status;
+ /* Use PJSUA_LOCK() instead of acquire_call():
+ * https://trac.pjsip.org/repos/ticket/1371
+ */
+ PJSUA_LOCK();
+
+ call = &pjsua_var.calls[call_id];
+
+ if (!call->inv) {
+ PJSUA_UNLOCK();
+ return PJSIP_ESESSIONTERMINATED;
}
/* id and role */
@@ -1520,7 +1543,7 @@ PJ_DEF(pj_status_t) pjsua_call_get_info( pjsua_call_id call_id,
PJ_TIME_VAL_SUB(info->total_duration, call->start_time);
}
- pjsip_dlg_dec_lock(dlg);
+ PJSUA_UNLOCK();
return PJ_SUCCESS;
}
@@ -1961,10 +1984,14 @@ PJ_DEF(pj_status_t) pjsua_call_set_hold(pjsua_call_id call_id,
/* Add additional headers etc */
pjsua_process_msg_data( tdata, msg_data);
+ /* Record the tx_data to keep track the operation */
+ call->hold_msg = (void*) tdata;
+
/* Send the request */
status = pjsip_inv_send_msg( call->inv, tdata);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Unable to send re-INVITE", status);
+ call->hold_msg = NULL;
goto on_return;
}
@@ -2531,14 +2558,15 @@ PJ_DEF(void) pjsua_call_hangup_all(void)
PJ_LOG(4,(THIS_FILE, "Hangup all calls.."));
pj_log_push_indent();
- PJSUA_LOCK();
+ // This may deadlock, see https://trac.pjsip.org/repos/ticket/1305
+ //PJSUA_LOCK();
for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) {
if (pjsua_var.calls[i].inv)
pjsua_call_hangup(i, 0, NULL, NULL);
}
- PJSUA_UNLOCK();
+ //PJSUA_UNLOCK();
pj_log_pop_indent();
}
@@ -3971,9 +3999,22 @@ static void pjsua_call_on_tsx_state_changed(pjsip_inv_session *inv,
&tsx->status_text);
}
}
+ } else if (tsx->role == PJSIP_ROLE_UAC &&
+ tsx->last_tx == (pjsip_tx_data*)call->hold_msg &&
+ tsx->state >= PJSIP_TSX_STATE_COMPLETED)
+ {
+ /* Monitor the status of call hold request */
+ call->hold_msg = NULL;
+ if (tsx->status_code/100 != 2) {
+ /* Outgoing call hold failed */
+ call->local_hold = PJ_FALSE;
+ PJ_LOG(3,(THIS_FILE, "Error putting call %d on hold (reason=%d)",
+ call->index, tsx->status_code));
+ }
}
on_return:
+
PJSUA_UNLOCK();
pj_log_pop_indent();
}
diff --git a/pjsip/src/pjsua-lib/pjsua_core.c b/pjsip/src/pjsua-lib/pjsua_core.c
index 31133b2c..52054226 100644
--- a/pjsip/src/pjsua-lib/pjsua_core.c
+++ b/pjsip/src/pjsua-lib/pjsua_core.c
@@ -234,6 +234,7 @@ PJ_DEF(void) pjsua_acc_config_default(pjsua_acc_config *cfg)
pj_list_init(&cfg->reg_hdr_list);
pj_list_init(&cfg->sub_hdr_list);
cfg->call_hold_type = PJSUA_CALL_HOLD_TYPE_DEFAULT;
+ cfg->register_on_acc_add = PJ_TRUE;
}
PJ_DEF(void) pjsua_buddy_config_default(pjsua_buddy_config *cfg)
@@ -1340,7 +1341,7 @@ pj_status_t resolve_stun_server(pj_bool_t wait)
/*
* Destroy pjsua.
*/
-PJ_DEF(pj_status_t) pjsua_destroy(void)
+PJ_DEF(pj_status_t) pjsua_destroy2(unsigned flags)
{
int i; /* Must be signed */
@@ -1365,12 +1366,14 @@ PJ_DEF(pj_status_t) pjsua_destroy(void)
if (pjsua_var.endpt) {
unsigned max_wait;
- PJ_LOG(4,(THIS_FILE, "Shutting down..."));
+ PJ_LOG(4,(THIS_FILE, "Shutting down, flags=%d...", flags));
pj_log_push_indent();
/* Terminate all calls. */
- pjsua_call_hangup_all();
+ if ((flags & PJSUA_DESTROY_NO_TX_MSG) == 0) {
+ pjsua_call_hangup_all();
+ }
/* Set all accounts to offline */
for (i=0; i<(int)PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
@@ -1381,10 +1384,10 @@ PJ_DEF(pj_status_t) pjsua_destroy(void)
}
/* Terminate all presence subscriptions. */
- pjsua_pres_shutdown();
+ pjsua_pres_shutdown(flags);
/* Destroy media (to shutdown media transports etc) */
- pjsua_media_subsys_destroy();
+ pjsua_media_subsys_destroy(flags);
/* Wait for sometime until all publish client sessions are done
* (ticket #364)
@@ -1398,6 +1401,11 @@ PJ_DEF(pj_status_t) pjsua_destroy(void)
max_wait = pjsua_var.acc[i].cfg.unpublish_max_wait_time_msec;
}
+ /* No waiting if RX is disabled */
+ if (flags & PJSUA_DESTROY_NO_RX_MSG) {
+ max_wait = 0;
+ }
+
/* Second stage, wait for unpublications to complete */
for (i=0; i<(int)(max_wait/50); ++i) {
unsigned j;
@@ -1427,7 +1435,8 @@ PJ_DEF(pj_status_t) pjsua_destroy(void)
if (!pjsua_var.acc[i].valid)
continue;
- if (pjsua_var.acc[i].regc) {
+ if (pjsua_var.acc[i].regc && (flags & PJSUA_DESTROY_NO_TX_MSG)==0)
+ {
pjsua_acc_set_registration(i, PJ_FALSE);
}
}
@@ -1452,6 +1461,11 @@ PJ_DEF(pj_status_t) pjsua_destroy(void)
max_wait = pjsua_var.acc[i].cfg.unreg_timeout;
}
+ /* No waiting if RX is disabled */
+ if (flags & PJSUA_DESTROY_NO_RX_MSG) {
+ max_wait = 0;
+ }
+
/* Second stage, wait for unregistrations to complete */
for (i=0; i<(int)(max_wait/50); ++i) {
unsigned j;
@@ -1472,8 +1486,9 @@ PJ_DEF(pj_status_t) pjsua_destroy(void)
/* Wait for some time to allow unregistration and ICE/TURN
* transports shutdown to complete:
*/
- if (i < 20)
+ if (i < 20 && (flags & PJSUA_DESTROY_NO_RX_MSG) == 0) {
busy_sleep(1000 - i*50);
+ }
PJ_LOG(4,(THIS_FILE, "Destroying..."));
@@ -1560,6 +1575,12 @@ PJ_DEF(pjsua_state) pjsua_get_state(void)
return pjsua_var.state;
}
+PJ_DEF(pj_status_t) pjsua_destroy(void)
+{
+ return pjsua_destroy2(0);
+}
+
+
/**
* Application is recommended to call this function after all initialization
* is done, so that the library can do additional checking set up
diff --git a/pjsip/src/pjsua-lib/pjsua_media.c b/pjsip/src/pjsua-lib/pjsua_media.c
index e7743659..60aebbeb 100644
--- a/pjsip/src/pjsua-lib/pjsua_media.c
+++ b/pjsip/src/pjsua-lib/pjsua_media.c
@@ -396,7 +396,7 @@ pj_status_t pjsua_media_subsys_start(void)
/*
* Destroy pjsua media subsystem.
*/
-pj_status_t pjsua_media_subsys_destroy(void)
+pj_status_t pjsua_media_subsys_destroy(unsigned flags)
{
unsigned i;
@@ -441,6 +441,10 @@ pj_status_t pjsua_media_subsys_destroy(void)
pjsua_media_channel_deinit(i);
}
if (call_med->tp && call_med->tp_auto_del) {
+ /* TODO: check if we're not allowed to send to network in the
+ * "flags", and if so do not do TURN allocation...
+ */
+ PJ_UNUSED_ARG(flags);
pjmedia_transport_close(call_med->tp);
}
call_med->tp = NULL;
@@ -1294,11 +1298,18 @@ static pj_status_t call_media_init_cb(pjsua_call_media *call_med,
if (call_med->tp_st == PJSUA_MED_TP_CREATING)
set_media_tp_state(call_med, PJSUA_MED_TP_IDLE);
+ if (!call_med->tp_orig &&
+ pjsua_var.ua_cfg.cb.on_create_media_transport)
+ {
+ call_med->use_custom_med_tp = PJ_TRUE;
+ } else
+ call_med->use_custom_med_tp = PJ_FALSE;
+
#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
/* This function may be called when SRTP transport already exists
* (e.g: in re-invite, update), don't need to destroy/re-create.
*/
- if (!call_med->tp_orig || call_med->tp == call_med->tp_orig) {
+ if (!call_med->tp_orig) {
pjmedia_srtp_setting srtp_opt;
pjmedia_transport *srtp = NULL;
@@ -1314,7 +1325,7 @@ static pj_status_t call_media_init_cb(pjsua_call_media *call_med,
/* Always create SRTP adapter */
pjmedia_srtp_setting_default(&srtp_opt);
srtp_opt.close_member_tp = PJ_TRUE;
- /* If media session has been ever established, let's use remote's
+ /* If media session has been ever established, let's use remote's
* preference in SRTP usage policy, especially when it is stricter.
*/
if (call_med->rem_srtp_use > acc->cfg.use_srtp)
@@ -1519,9 +1530,25 @@ static pj_status_t media_channel_init_cb(pjsua_call_id call_id,
call->async_call.dlg->pool);
}
- status = pjmedia_transport_media_create(
- call_med->tp, tmp_pool,
- 0, call->async_call.rem_sdp, mi);
+ if (call_med->use_custom_med_tp) {
+ unsigned custom_med_tp_flags = 0;
+
+ /* Use custom media transport returned by the application */
+ call_med->tp =
+ (*pjsua_var.ua_cfg.cb.on_create_media_transport)
+ (call_id, mi, call_med->tp,
+ custom_med_tp_flags);
+ if (!call_med->tp) {
+ status =
+ PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_NOT_ACCEPTABLE);
+ }
+ }
+
+ if (call_med->tp) {
+ status = pjmedia_transport_media_create(
+ call_med->tp, tmp_pool,
+ 0, call->async_call.rem_sdp, mi);
+ }
if (status != PJ_SUCCESS) {
call->med_ch_info.status = status;
call->med_ch_info.med_idx = mi;
@@ -2104,6 +2131,7 @@ static void stop_media_session(pjsua_call_id call_id)
PJ_LOG(4,(THIS_FILE, "Media session call%02d:%d is destroyed",
call_id, mi));
+ call_med->prev_state = call_med->state;
call_med->state = PJSUA_CALL_MEDIA_NONE;
}
@@ -2133,12 +2161,19 @@ pj_status_t pjsua_media_channel_deinit(pjsua_call_id call_id)
PJ_LOG(4,(THIS_FILE, "Call %d: deinitializing media..", call_id));
pj_log_push_indent();
+ for (mi=0; mi<call->med_cnt; ++mi) {
+ pjsua_call_media *call_med = &call->media[mi];
+
+ if (call_med->type == PJMEDIA_TYPE_AUDIO && call_med->strm.a.stream)
+ pjmedia_stream_send_rtcp_bye(call_med->strm.a.stream);
+ }
+
stop_media_session(call_id);
for (mi=0; mi<call->med_cnt; ++mi) {
pjsua_call_media *call_med = &call->media[mi];
- if (call_med->tp_st > PJSUA_MED_TP_IDLE) {
+ if (call_med->tp_st > PJSUA_MED_TP_IDLE) {
pjmedia_transport_media_stop(call_med->tp);
set_media_tp_state(call_med, PJSUA_MED_TP_IDLE);
}
@@ -2153,6 +2188,7 @@ pj_status_t pjsua_media_channel_deinit(pjsua_call_id call_id)
pjmedia_transport_close(call_med->tp);
call_med->tp = call_med->tp_orig = NULL;
}
+ call_med->tp_orig = NULL;
}
check_snd_dev_idle();
@@ -2206,6 +2242,8 @@ static pj_status_t audio_channel_update(pjsua_call_media *call_med,
if (status != PJ_SUCCESS)
goto on_return;
+ si->rtcp_sdes_bye_disabled = PJ_TRUE;
+
/* Check if no media is active */
if (si->dir == PJMEDIA_DIR_NONE) {
/* Call media state */
@@ -2296,6 +2334,9 @@ static pj_status_t audio_channel_update(pjsua_call_media *call_med,
goto on_return;
}
+ if (call_med->prev_state == PJSUA_CALL_MEDIA_NONE)
+ pjmedia_stream_send_rtcp_sdes(call_med->strm.a.stream);
+
/* If DTMF callback is installed by application, install our
* callback to the session.
*/
diff --git a/pjsip/src/pjsua-lib/pjsua_pres.c b/pjsip/src/pjsua-lib/pjsua_pres.c
index 88ea317f..c78e8b5c 100644
--- a/pjsip/src/pjsua-lib/pjsua_pres.c
+++ b/pjsip/src/pjsua-lib/pjsua_pres.c
@@ -1320,13 +1320,17 @@ pj_status_t pjsua_pres_init_acc(int acc_id)
/* Unpublish presence publication */
-void pjsua_pres_unpublish(pjsua_acc *acc)
+void pjsua_pres_unpublish(pjsua_acc *acc, unsigned flags)
{
if (acc->publish_sess) {
pjsua_acc_config *acc_cfg = &acc->cfg;
acc->online_status = PJ_FALSE;
- send_publish(acc->index, PJ_FALSE);
+
+ if ((flags & PJSUA_DESTROY_NO_TX_MSG) == 0) {
+ send_publish(acc->index, PJ_FALSE);
+ }
+
/* By ticket #364, don't destroy the session yet (let the callback
destroy it)
if (acc->publish_sess) {
@@ -1339,7 +1343,7 @@ void pjsua_pres_unpublish(pjsua_acc *acc)
}
/* Terminate server subscription for the account */
-void pjsua_pres_delete_acc(int acc_id)
+void pjsua_pres_delete_acc(int acc_id, unsigned flags)
{
pjsua_acc *acc = &pjsua_var.acc[acc_id];
pjsua_srv_pres *uapres;
@@ -1361,11 +1365,15 @@ void pjsua_pres_delete_acc(int acc_id)
pres_status.info[0].basic_open = pjsua_var.acc[acc_id].online_status;
pjsip_pres_set_status(uapres->sub, &pres_status);
- if (pjsip_pres_notify(uapres->sub,
- PJSIP_EVSUB_STATE_TERMINATED, NULL,
- &reason, &tdata)==PJ_SUCCESS)
- {
- pjsip_pres_send_request(uapres->sub, tdata);
+ if ((flags & PJSUA_DESTROY_NO_TX_MSG) == 0) {
+ if (pjsip_pres_notify(uapres->sub,
+ PJSIP_EVSUB_STATE_TERMINATED, NULL,
+ &reason, &tdata)==PJ_SUCCESS)
+ {
+ pjsip_pres_send_request(uapres->sub, tdata);
+ }
+ } else {
+ pjsip_pres_terminate(uapres->sub, PJ_FALSE);
}
uapres = next;
@@ -1376,7 +1384,7 @@ void pjsua_pres_delete_acc(int acc_id)
pj_list_init(&acc->pres_srv_list);
/* Terminate presence publication, if any */
- pjsua_pres_unpublish(acc);
+ pjsua_pres_unpublish(acc, flags);
}
@@ -2251,6 +2259,10 @@ static void pres_timer_cb(pj_timer_heap_t *th,
for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
pjsua_acc *acc = &pjsua_var.acc[i];
+ /* Acc may not be ready yet, otherwise assertion will happen */
+ if (!pjsua_acc_is_valid(i))
+ continue;
+
/* Retry PUBLISH */
if (acc->cfg.publish_enabled && acc->publish_sess==NULL)
pjsua_pres_init_publish_acc(acc->index);
@@ -2324,7 +2336,7 @@ pj_status_t pjsua_pres_start(void)
/*
* Shutdown presence.
*/
-void pjsua_pres_shutdown(void)
+void pjsua_pres_shutdown(unsigned flags)
{
unsigned i;
@@ -2339,18 +2351,20 @@ void pjsua_pres_shutdown(void)
for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
if (!pjsua_var.acc[i].valid)
continue;
- pjsua_pres_delete_acc(i);
+ pjsua_pres_delete_acc(i, flags);
}
for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.buddy); ++i) {
pjsua_var.buddy[i].monitor = 0;
}
- refresh_client_subscriptions();
+ if ((flags & PJSUA_DESTROY_NO_TX_MSG) == 0) {
+ refresh_client_subscriptions();
- for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
- if (pjsua_var.acc[i].valid)
- pjsua_pres_update_acc(i, PJ_FALSE);
+ for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
+ if (pjsua_var.acc[i].valid)
+ pjsua_pres_update_acc(i, PJ_FALSE);
+ }
}
pj_log_pop_indent();