Report disconnection event immediately when hanging up a call (#2600)

This commit is contained in:
sauwming 2020-12-04 10:29:45 +08:00 committed by GitHub
parent fe963266b1
commit 2eea0ace2b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 336 additions and 119 deletions

View File

@ -205,8 +205,11 @@ static void on_call_state(pjsua_call_id call_id, pjsip_event *e)
find_next_call();
}
/* Dump media state upon disconnected */
if (1) {
/* Dump media state upon disconnected.
* Moved to on_stream_destroyed() since media has been deactivated
* upon disconnection.
*/
if (0) {
PJ_LOG(5,(THIS_FILE,
"Call %d disconnected, dumping media stats..",
call_id));
@ -271,6 +274,21 @@ static void on_call_state(pjsua_call_id call_id, pjsip_event *e)
}
}
/*
* Handler when audio stream is destroyed.
*/
static void on_stream_destroyed(pjsua_call_id call_id,
pjmedia_stream *strm,
unsigned stream_idx)
{
if (1) {
PJ_LOG(5,(THIS_FILE,
"Call %d stream %d destroyed, dumping media stats..",
call_id, stream_idx));
log_call_dump(call_id);
}
}
/**
* Handler when there is incoming call.
*/
@ -1317,6 +1335,7 @@ int stdout_refresh_proc(void *arg)
return 0;
}
static pj_status_t app_init(void)
{
pjsua_transport_id transport_id = -1;
@ -1351,6 +1370,7 @@ static pj_status_t app_init(void)
/* Initialize application callbacks */
app_config.cfg.cb.on_call_state = &on_call_state;
app_config.cfg.cb.on_stream_destroyed = &on_stream_destroyed;
app_config.cfg.cb.on_call_media_state = &on_call_media_state;
app_config.cfg.cb.on_incoming_call = &on_incoming_call;
app_config.cfg.cb.on_dtmf_digit2 = &call_on_dtmf_callback2;

View File

@ -5277,9 +5277,11 @@ pjsua_call_send_dtmf_param_default(pjsua_call_send_dtmf_param *param);
PJ_DECL(unsigned) pjsua_call_get_max_count(void);
/**
* Get number of currently active calls.
* Get the number of current calls. The number includes active calls
* (pjsua_call_is_active(call_id) == PJ_TRUE), as well as calls that
* are no longer active but still in the process of hanging up.
*
* @return Number of currently active calls.
* @return Number of current calls.
*/
PJ_DECL(unsigned) pjsua_call_get_count(void);
@ -5557,6 +5559,19 @@ pjsua_call_answer_with_sdp(pjsua_call_id call_id,
* while #pjsua_call_answer() only works with incoming calls on EARLY
* state.
*
* After calling this function, media will be deinitialized (call media
* callbacks, if any, will still be received) and then, on_call_state()
* will be immediately called with state DISCONNECTED. No further
* call callbacks will be received after this. The call hangup process
* itself (sending BYE, waiting for the response, and resource cleanup)
* will continue in the background and the call slot can be reused only
* after this process is completed. If application has limited call slots
* and would like to check if there are any free slots remaining, it can
* query the number of free slots using the APIs:
* pjsua_call_get_max_count()-pjsua_call_get_count()
*
* Note that on_call_tsx_state() will not be called when using this API.
*
* @param call_id Call identification.
* @param code Optional status code to be sent when we're rejecting
* incoming call. If the value is zero, "603/Decline"

View File

@ -205,6 +205,12 @@ struct pjsua_call
created yet. This temporary
variable is used to handle such
case, see ticket #1916. */
pj_timer_entry hangup_timer; /**< Hangup retry timer. */
unsigned hangup_retry; /**< Number of hangup retries. */
unsigned hangup_code; /**< Hangup code. */
pj_str_t hangup_reason; /**< Hangup reason. */
pjsua_msg_data *hangup_msg_data;/**< Hangup message data. */
};

View File

@ -534,7 +534,9 @@ void pjsua_aud_stop_stream(pjsua_call_media *call_med)
call_med->rtp_tx_ts = stat.rtp_tx_last_ts;
}
if (pjsua_var.ua_cfg.cb.on_stream_destroyed) {
if (!call_med->call->hanging_up &&
pjsua_var.ua_cfg.cb.on_stream_destroyed)
{
pjsua_var.ua_cfg.cb.on_stream_destroyed(call_med->call->index,
strm, call_med->idx);
}
@ -558,15 +560,19 @@ void pjsua_aud_stop_stream(pjsua_call_media *call_med)
static void dtmf_callback(pjmedia_stream *strm, void *user_data,
int digit)
{
pjsua_call_id call_id;
PJ_UNUSED_ARG(strm);
call_id = (pjsua_call_id)(pj_ssize_t)user_data;
if (pjsua_var.calls[call_id].hanging_up)
return;
pj_log_push_indent();
if (pjsua_var.ua_cfg.cb.on_dtmf_digit2) {
pjsua_call_id call_id;
pjsua_dtmf_info info;
call_id = (pjsua_call_id)(pj_ssize_t)user_data;
info.method = PJSUA_DTMF_METHOD_RFC2833;
info.digit = digit;
info.duration = PJSUA_UNKNOWN_DTMF_DURATION;
@ -576,9 +582,6 @@ static void dtmf_callback(pjmedia_stream *strm, void *user_data,
* callback, please see ticket #460:
* http://trac.pjsip.org/repos/ticket/460#comment:4
*/
pjsua_call_id call_id;
call_id = (pjsua_call_id)(pj_ssize_t)user_data;
(*pjsua_var.ua_cfg.cb.on_dtmf_digit)(call_id, digit);
}
@ -596,10 +599,13 @@ static void dtmf_event_callback(pjmedia_stream *strm, void *user_data,
PJ_UNUSED_ARG(strm);
call_id = (pjsua_call_id)(pj_ssize_t)user_data;
if (pjsua_var.calls[call_id].hanging_up)
return;
pj_log_push_indent();
if (pjsua_var.ua_cfg.cb.on_dtmf_event) {
call_id = (pjsua_call_id)(pj_ssize_t)user_data;
evt.method = PJSUA_DTMF_METHOD_RFC2833;
evt.timestamp = event->timestamp;
evt.digit = event->digit;
@ -668,7 +674,7 @@ pj_status_t pjsua_aud_channel_update(pjsua_call_media *call_med,
si->ka_cfg = pjsua_var.acc[call->acc_id].cfg.stream_ka_cfg;
#endif
if (pjsua_var.ua_cfg.cb.on_stream_precreate) {
if (!call->hanging_up && pjsua_var.ua_cfg.cb.on_stream_precreate) {
pjsua_on_stream_precreate_param prm;
prm.stream_idx = strm_idx;
prm.stream_info.type = PJMEDIA_TYPE_AUDIO;
@ -707,12 +713,13 @@ pj_status_t pjsua_aud_channel_update(pjsua_call_media *call_med,
/* If DTMF callback is installed by application, install our
* callback to the session.
*/
if (pjsua_var.ua_cfg.cb.on_dtmf_event) {
if (!call->hanging_up && pjsua_var.ua_cfg.cb.on_dtmf_event) {
pjmedia_stream_set_dtmf_event_callback(call_med->strm.a.stream,
&dtmf_event_callback,
(void*)(pj_ssize_t)(call->index));
} else if (pjsua_var.ua_cfg.cb.on_dtmf_digit ||
pjsua_var.ua_cfg.cb.on_dtmf_digit2)
} else if (!call->hanging_up &&
(pjsua_var.ua_cfg.cb.on_dtmf_digit ||
pjsua_var.ua_cfg.cb.on_dtmf_digit2))
{
pjmedia_stream_set_dtmf_callback(call_med->strm.a.stream,
&dtmf_callback,
@ -729,7 +736,7 @@ pj_status_t pjsua_aud_channel_update(pjsua_call_media *call_med,
* Note: application may modify media_port to point to different
* media port
*/
if (pjsua_var.ua_cfg.cb.on_stream_created2) {
if (!call->hanging_up && pjsua_var.ua_cfg.cb.on_stream_created2) {
pjsua_on_stream_created_param prm;
prm.stream = call_med->strm.a.stream;
@ -741,7 +748,8 @@ pj_status_t pjsua_aud_channel_update(pjsua_call_media *call_med,
call_med->strm.a.destroy_port = prm.destroy_port;
call_med->strm.a.media_port = prm.port;
} else if (pjsua_var.ua_cfg.cb.on_stream_created) {
} else if (!call->hanging_up && pjsua_var.ua_cfg.cb.on_stream_created)
{
(*pjsua_var.ua_cfg.cb.on_stream_created)(call->index,
call_med->strm.a.stream,
strm_idx,

View File

@ -39,6 +39,12 @@
*/
#define RESTART_ICE_ON_REINVITE 1
/* Retry interval of trying to hangup a call. */
#define CALL_HANGUP_RETRY_INTERVAL 5000
/* Max number of hangup retries. */
#define CALL_HANGUP_MAX_RETRY 4
/*
* The INFO method.
*/
@ -126,6 +132,9 @@ static void xfer_server_on_evsub_state( pjsip_evsub *sub, pjsip_event *event);
/* Timer callback to send re-INVITE/UPDATE to lock codec or ICE update */
static void reinv_timer_cb(pj_timer_heap_t *th, pj_timer_entry *entry);
/* Timer callback to hangup the call */
static void hangup_timer_cb(pj_timer_heap_t *th, pj_timer_entry *entry);
/* Check and send reinvite for lock codec and ICE update */
static pj_status_t process_pending_reinvite(pjsua_call *call);
@ -556,6 +565,7 @@ on_make_call_med_tp_complete(pjsua_call_id call_id,
on_error:
if (inv == NULL && call_id != -1 && !cb_called &&
!call->hanging_up &&
pjsua_var.ua_cfg.cb.on_call_state)
{
/* Use user event rather than NULL to avoid crash in
@ -1027,7 +1037,7 @@ static pj_status_t process_incoming_call_replace(pjsua_call *call,
replaced_call = (pjsua_call*) replaced_dlg->mod_data[pjsua_var.mod.id];
/* Notify application */
if (pjsua_var.ua_cfg.cb.on_call_replaced)
if (!replaced_call->hanging_up && pjsua_var.ua_cfg.cb.on_call_replaced)
pjsua_var.ua_cfg.cb.on_call_replaced(replaced_call->index,
call->index);
@ -1496,13 +1506,17 @@ pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata)
pjsua_call_cleanup_flag(&call->opt);
/* Notify application */
if (pjsua_var.ua_cfg.cb.on_call_replace_request) {
if (!replaced_call->hanging_up &&
pjsua_var.ua_cfg.cb.on_call_replace_request)
{
pjsua_var.ua_cfg.cb.on_call_replace_request(replaced_call->index,
rdata,
&st_code, &st_text);
}
if (pjsua_var.ua_cfg.cb.on_call_replace_request2) {
if (!replaced_call->hanging_up &&
pjsua_var.ua_cfg.cb.on_call_replace_request2)
{
pjsua_var.ua_cfg.cb.on_call_replace_request2(replaced_call->index,
rdata,
&st_code, &st_text,
@ -2044,7 +2058,8 @@ PJ_DEF(pj_bool_t) pjsua_call_is_active(pjsua_call_id call_id)
{
PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls,
PJ_EINVAL);
return pjsua_var.calls[call_id].inv != NULL &&
return !pjsua_var.calls[call_id].hanging_up &&
pjsua_var.calls[call_id].inv != NULL &&
pjsua_var.calls[call_id].inv->state != PJSIP_INV_STATE_DISCONNECTED;
}
@ -2204,7 +2219,9 @@ PJ_DEF(pj_status_t) pjsua_call_get_info( pjsua_call_id call_id,
pj_memcpy(&info->setting, &call->opt, sizeof(call->opt));
/* state, state_text */
if (call->inv) {
if (call->hanging_up) {
info->state = PJSIP_INV_STATE_DISCONNECTED;
} else if (call->inv) {
info->state = call->inv->state;
if (call->inv->role == PJSIP_ROLE_UAS &&
info->state == PJSIP_INV_STATE_NULL)
@ -2719,6 +2736,124 @@ pjsua_call_answer_with_sdp(pjsua_call_id call_id,
}
static pj_status_t call_inv_end_session(pjsua_call *call,
unsigned code,
const pj_str_t *reason,
const pjsua_msg_data *msg_data)
{
pjsip_tx_data *tdata;
pj_status_t status;
if (code==0) {
if (call->inv->state == PJSIP_INV_STATE_CONFIRMED)
code = PJSIP_SC_OK;
else if (call->inv->role == PJSIP_ROLE_UAS)
code = PJSIP_SC_DECLINE;
else
code = PJSIP_SC_REQUEST_TERMINATED;
}
/* Stop hangup timer, if it is active. */
if (call->hangup_timer.id) {
pjsua_cancel_timer(&call->hangup_timer);
call->hangup_timer.id = PJ_FALSE;
}
status = pjsip_inv_end_session(call->inv, code, reason, &tdata);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE,
"Failed to create end session message",
status);
goto on_return;
}
/* pjsip_inv_end_session may return PJ_SUCCESS with NULL
* as p_tdata when INVITE transaction has not been answered
* with any provisional responses.
*/
if (tdata == NULL) {
goto on_return;
}
/* Add additional headers etc */
pjsua_process_msg_data( tdata, msg_data);
/* Send the message */
status = pjsip_inv_send_msg(call->inv, tdata);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE,
"Failed to send end session message",
status);
goto on_return;
}
on_return:
if (status != PJ_SUCCESS) {
pj_time_val delay;
/* Schedule a retry */
if (call->hangup_retry >= CALL_HANGUP_MAX_RETRY) {
/* Forcefully terminate the invite session. */
pjsip_inv_terminate(call->inv, call->hangup_code, PJ_TRUE);
return PJ_SUCCESS;
}
if (call->hangup_retry == 0) {
pj_timer_entry_init(&call->hangup_timer, PJ_FALSE,
(void*)call, &hangup_timer_cb);
call->hangup_code = code;
if (reason) {
pj_strdup(call->inv->pool_prov, &call->hangup_reason,
reason);
}
if (msg_data) {
call->hangup_msg_data = pjsua_msg_data_clone(
call->inv->pool_prov,
msg_data);
}
}
delay.sec = 0;
delay.msec = CALL_HANGUP_RETRY_INTERVAL;
pj_time_val_normalize(&delay);
call->hangup_timer.id = PJ_TRUE;
pjsua_schedule_timer(&call->hangup_timer, &delay);
call->hangup_retry++;
PJ_LOG(4, (THIS_FILE, "Will retry call %d hangup in %d msec",
call->index, CALL_HANGUP_RETRY_INTERVAL));
}
return PJ_SUCCESS;
}
/* Timer callback to hangup call */
static void hangup_timer_cb(pj_timer_heap_t *th, pj_timer_entry *entry)
{
pjsua_call* call = (pjsua_call *)entry->user_data;
pjsip_dialog *dlg;
pj_status_t status;
PJ_UNUSED_ARG(th);
pj_log_push_indent();
status = acquire_call("hangup_timer_cb()", call->index, &call, &dlg);
if (status != PJ_SUCCESS) {
pj_log_pop_indent();
return;
}
call->hangup_timer.id = PJ_FALSE;
call_inv_end_session(call, call->hangup_code, &call->hangup_reason,
call->hangup_msg_data);
pjsip_dlg_dec_lock(dlg);
pj_log_pop_indent();
}
/*
* Hangup call by using method that is appropriate according to the
* call state.
@ -2731,8 +2866,6 @@ PJ_DEF(pj_status_t) pjsua_call_hangup(pjsua_call_id call_id,
pjsua_call *call;
pjsip_dialog *dlg = NULL;
pj_status_t status;
pjsip_tx_data *tdata;
if (call_id<0 || call_id>=(int)pjsua_var.ua_cfg.max_calls) {
PJ_LOG(1,(THIS_FILE, "pjsua_call_hangup(): invalid call id %d",
@ -2749,77 +2882,76 @@ PJ_DEF(pj_status_t) pjsua_call_hangup(pjsua_call_id call_id,
if (status != PJ_SUCCESS)
goto on_return;
call->hanging_up = PJ_TRUE;
if (!call->hanging_up) {
pjsip_event user_event;
/* If media transport creation is not yet completed, we will hangup
* the call in the media transport creation callback instead.
*/
if ((call->med_ch_cb && !call->inv) ||
((call->inv != NULL) && (call->inv->state == PJSIP_INV_STATE_NULL)))
{
PJ_LOG(4,(THIS_FILE, "Pending call %d hangup upon completion "
"of media transport", call_id));
pj_gettimeofday(&call->dis_time);
if (call->res_time.sec == 0)
pj_gettimeofday(&call->res_time);
if (call->inv && call->inv->role == PJSIP_ROLE_UAS)
call->async_call.call_var.inc_call.hangup = PJ_TRUE;
else
call->async_call.call_var.out_call.hangup = PJ_TRUE;
if (code==0) {
if (call->inv && call->inv->state == PJSIP_INV_STATE_CONFIRMED)
code = PJSIP_SC_OK;
else if (call->inv && call->inv->role == PJSIP_ROLE_UAS)
code = PJSIP_SC_DECLINE;
else
code = PJSIP_SC_REQUEST_TERMINATED;
}
call->last_code = code;
pj_strncpy(&call->last_text,
pjsip_get_status_text(call->last_code),
sizeof(call->last_text_buf_));
if (code == 0)
call->last_code = PJSIP_SC_REQUEST_TERMINATED;
else
call->last_code = (pjsip_status_code)code;
if (reason) {
pj_strncpy(&call->last_text, reason,
sizeof(call->last_text_buf_));
}
/* Stop reinvite timer, if it is active. */
if (call->reinv_timer.id) {
pjsua_cancel_timer(&call->reinv_timer);
call->reinv_timer.id = PJ_FALSE;
}
/* If media transport creation is not yet completed, we will continue
* from the media transport creation callback instead.
*/
if ((call->med_ch_cb && !call->inv) ||
((call->inv != NULL) &&
(call->inv->state == PJSIP_INV_STATE_NULL)))
{
PJ_LOG(4,(THIS_FILE, "Will continue call %d hangup upon "
"completion of media transport", call_id));
if (call->inv && call->inv->role == PJSIP_ROLE_UAS)
call->async_call.call_var.inc_call.hangup = PJ_TRUE;
else
call->async_call.call_var.out_call.hangup = PJ_TRUE;
if (reason) {
pj_strncpy(&call->last_text, reason,
sizeof(call->last_text_buf_));
}
call->hanging_up = PJ_TRUE;
} else {
/* Destroy media session. */
pjsua_media_channel_deinit(call_id);
call->hanging_up = PJ_TRUE;
pjsua_check_snd_dev_idle();
}
/* Call callback which will report DISCONNECTED state.
* Use user event rather than NULL to avoid crash in
* unsuspecting app.
*/
PJSIP_EVENT_INIT_USER(user_event, 0, 0, 0, 0);
if (pjsua_var.ua_cfg.cb.on_call_state) {
(*pjsua_var.ua_cfg.cb.on_call_state)(call->index,
&user_event);
}
goto on_return;
}
if (code==0) {
if (call->inv->state == PJSIP_INV_STATE_CONFIRMED)
code = PJSIP_SC_OK;
else if (call->inv->role == PJSIP_ROLE_UAS)
code = PJSIP_SC_DECLINE;
else
code = PJSIP_SC_REQUEST_TERMINATED;
}
status = pjsip_inv_end_session(call->inv, code, reason, &tdata);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE,
"Failed to create end session message",
status);
call->hanging_up = PJ_FALSE;
goto on_return;
}
/* pjsip_inv_end_session may return PJ_SUCCESS with NULL
* as p_tdata when INVITE transaction has not been answered
* with any provisional responses.
*/
if (tdata == NULL)
goto on_return;
/* Add additional headers etc */
pjsua_process_msg_data( tdata, msg_data);
/* Send the message */
status = pjsip_inv_send_msg(call->inv, tdata);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE,
"Failed to send end session message",
status);
call->hanging_up = PJ_FALSE;
goto on_return;
}
/* Stop reinvite timer, if it is active */
if (call->reinv_timer.id) {
pjsua_cancel_timer(&call->reinv_timer);
call->reinv_timer.id = PJ_FALSE;
}
if (call->inv)
call_inv_end_session(call, code, reason, msg_data);
on_return:
if (dlg) pjsip_dlg_dec_lock(dlg);
@ -4290,6 +4422,16 @@ static void pjsua_call_on_state_changed(pjsip_inv_session *inv,
}
}
/* Destroy media session when invite session is disconnected. */
if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {
PJSUA_LOCK();
if (!call->hanging_up)
pjsua_media_channel_deinit(call->index);
PJSUA_UNLOCK();
}
/* Release locks before calling callbacks, to avoid deadlock. */
while (PJSUA_LOCK_IS_LOCKED()) {
num_locks++;
@ -4299,14 +4441,14 @@ static void pjsua_call_on_state_changed(pjsip_inv_session *inv,
/* Ticket #1627: Invoke on_call_tsx_state() when call is disconnected. */
if (inv->state == PJSIP_INV_STATE_DISCONNECTED &&
e->type == PJSIP_EVENT_TSX_STATE &&
call->inv &&
!call->hanging_up && call->inv &&
pjsua_var.ua_cfg.cb.on_call_tsx_state)
{
(*pjsua_var.ua_cfg.cb.on_call_tsx_state)(call->index,
e->body.tsx_state.tsx, e);
}
if (pjsua_var.ua_cfg.cb.on_call_state)
if (!call->hanging_up && pjsua_var.ua_cfg.cb.on_call_state)
(*pjsua_var.ua_cfg.cb.on_call_state)(call->index, e);
/* Re-acquire the locks. */
@ -4315,13 +4457,11 @@ static void pjsua_call_on_state_changed(pjsip_inv_session *inv,
/* call->inv may be NULL now */
/* Destroy media session when invite session is disconnected. */
/* Finally, free call when invite session is disconnected. */
if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {
PJSUA_LOCK();
pjsua_media_channel_deinit(call->index);
/* Free call */
call->inv = NULL;
@ -4534,7 +4674,7 @@ static void pjsua_call_on_media_update(pjsip_inv_session *inv,
pjsua_call_schedule_reinvite_check(call, 0);
/* Call application callback, if any */
if (pjsua_var.ua_cfg.cb.on_call_media_state)
if (!call->hanging_up && pjsua_var.ua_cfg.cb.on_call_media_state)
pjsua_var.ua_cfg.cb.on_call_media_state(call->index);
on_return:
@ -4659,6 +4799,8 @@ static void pjsua_call_on_rx_offer(pjsip_inv_session *inv,
pj_bool_t async = PJ_FALSE;
call = (pjsua_call*) inv->dlg->mod_data[pjsua_var.mod.id];
if (call->hanging_up)
return;
/* Supply candidate answer */
PJ_LOG(4,(THIS_FILE, "Call %d: received updated media offer",
@ -4833,9 +4975,11 @@ static void pjsua_call_on_create_offer(pjsip_inv_session *inv,
pj_log_push_indent();
call = (pjsua_call*) inv->dlg->mod_data[pjsua_var.mod.id];
if (pjsua_call_media_is_changing(call)) {
if (call->hanging_up || pjsua_call_media_is_changing(call)) {
*offer = NULL;
PJ_LOG(1,(THIS_FILE, "Unable to create offer" ERR_MEDIA_CHANGING));
PJ_LOG(1,(THIS_FILE, "Unable to create offer%s",
call->hanging_up? ", call hanging up":
ERR_MEDIA_CHANGING));
goto on_return;
}
@ -4952,7 +5096,9 @@ static void xfer_client_on_evsub_state( pjsip_evsub *sub, pjsip_event *event)
/* Since no subscription is desired, assume that call has been
* transferred successfully.
*/
if (call && pjsua_var.ua_cfg.cb.on_call_transfer_status) {
if (call && !call->hanging_up &&
pjsua_var.ua_cfg.cb.on_call_transfer_status)
{
const pj_str_t ACCEPTED = { "Accepted", 8 };
pj_bool_t cont = PJ_FALSE;
(*pjsua_var.ua_cfg.cb.on_call_transfer_status)(call->index,
@ -4973,7 +5119,9 @@ static void xfer_client_on_evsub_state( pjsip_evsub *sub, pjsip_event *event)
/* Notify application about call transfer progress.
* Initially notify with 100/Accepted status.
*/
if (call && pjsua_var.ua_cfg.cb.on_call_transfer_status) {
if (call && !call->hanging_up &&
pjsua_var.ua_cfg.cb.on_call_transfer_status)
{
const pj_str_t ACCEPTED = { "Accepted", 8 };
pj_bool_t cont = PJ_FALSE;
(*pjsua_var.ua_cfg.cb.on_call_transfer_status)(call->index,
@ -5010,7 +5158,9 @@ static void xfer_client_on_evsub_state( pjsip_evsub *sub, pjsip_event *event)
}
if (!call || !event || !pjsua_var.ua_cfg.cb.on_call_transfer_status) {
if (!call || call->hanging_up || !event ||
!pjsua_var.ua_cfg.cb.on_call_transfer_status)
{
/* Application is not interested with call progress status */
goto on_return;
}
@ -5153,6 +5303,10 @@ static void on_call_transferred( pjsip_inv_session *inv,
pj_log_push_indent();
existing_call = (pjsua_call*) inv->dlg->mod_data[pjsua_var.mod.id];
if (existing_call->hanging_up) {
pjsip_dlg_respond( inv->dlg, rdata, 487, NULL, NULL, NULL);
goto on_return;
}
/* Find the Refer-To header */
refer_to = (pjsip_generic_string_hdr*)
@ -5386,7 +5540,7 @@ static void pjsua_call_on_tsx_state_changed(pjsip_inv_session *inv,
if (call == NULL)
goto on_return;
if (call->inv == NULL) {
if (call->inv == NULL || call->hanging_up) {
/* Call has been disconnected. */
goto on_return;
}
@ -5774,14 +5928,16 @@ static pjsip_redirect_op pjsua_call_on_redirected(pjsip_inv_session *inv,
pj_log_push_indent();
if (pjsua_var.ua_cfg.cb.on_call_redirected) {
if (!call->hanging_up && pjsua_var.ua_cfg.cb.on_call_redirected) {
op = (*pjsua_var.ua_cfg.cb.on_call_redirected)(call->index,
target, e);
} else {
PJ_LOG(4,(THIS_FILE, "Unhandled redirection for call %d "
"(callback not implemented by application). Disconnecting "
"call.",
call->index));
if (!call->hanging_up) {
PJ_LOG(4,(THIS_FILE, "Unhandled redirection for call %d "
"(callback not implemented by application). "
"Disconnecting call.",
call->index));
}
op = PJSIP_REDIRECT_STOP;
}

View File

@ -907,13 +907,14 @@ void print_call(const char *title,
char *buf, pj_size_t size)
{
int len;
pjsip_inv_session *inv = pjsua_var.calls[call_id].inv;
pjsua_call *call = &pjsua_var.calls[call_id];
pjsip_inv_session *inv = call->inv;
pjsip_dialog *dlg;
char userinfo[PJSIP_MAX_URL_SIZE];
/* Dump invite sesion info. */
dlg = (inv? inv->dlg: pjsua_var.calls[call_id].async_call.dlg);
dlg = (inv? inv->dlg: call->async_call.dlg);
len = pjsip_hdr_print_on(dlg->remote.info, userinfo, sizeof(userinfo));
if (len < 0)
pj_ansi_strcpy(userinfo, "<--uri too long-->");
@ -922,8 +923,9 @@ void print_call(const char *title,
len = pj_ansi_snprintf(buf, size, "%s[%s] %s",
title,
pjsip_inv_state_name(inv? inv->state:
PJSIP_INV_STATE_DISCONNECTED),
pjsip_inv_state_name((call->hanging_up || !inv)?
PJSIP_INV_STATE_DISCONNECTED:
inv->state),
userinfo);
if (len < 1 || len >= (int)size) {
pj_ansi_strcpy(buf, "<--uri too long-->");

View File

@ -808,7 +808,8 @@ static void ice_failed_nego_cb(void *user_data)
return;
}
pjsua_var.ua_cfg.cb.on_call_media_state(call_id);
if (!call->hanging_up)
pjsua_var.ua_cfg.cb.on_call_media_state(call_id);
if (dlg)
pjsip_dlg_dec_lock(dlg);
@ -843,7 +844,9 @@ static void on_ice_complete(pjmedia_transport *tp,
} else {
call_med->state = PJSUA_CALL_MEDIA_ERROR;
call_med->dir = PJMEDIA_DIR_NONE;
if (call && pjsua_var.ua_cfg.cb.on_call_media_state) {
if (call && !call->hanging_up &&
pjsua_var.ua_cfg.cb.on_call_media_state)
{
/* Defer the callback to a timer */
pjsua_schedule_timer2(&ice_failed_nego_cb,
(void*)(pj_ssize_t)call->index, 1);
@ -860,7 +863,9 @@ static void on_ice_complete(pjmedia_transport *tp,
"ICE keep alive failure for transport %d:%d",
call->index, call_med->idx));
}
if (pjsua_var.ua_cfg.cb.on_call_media_transport_state) {
if (!call->hanging_up &&
pjsua_var.ua_cfg.cb.on_call_media_transport_state)
{
pjsua_med_tp_state_info info;
pj_bzero(&info, sizeof(info));
@ -1544,7 +1549,6 @@ pj_status_t call_media_on_event(pjmedia_event *event,
char ev_name[5];
pj_status_t status = PJ_SUCCESS;
pj_assert(call && call_med);
pjmedia_fourcc_name(event->type, ev_name);
PJ_LOG(5,(THIS_FILE, "Call %d: Media %d: Received media event, type=%s, "
"src=%p, epub=%p",
@ -1660,6 +1664,9 @@ pj_status_t call_media_on_event(pjmedia_event *event,
pj_mutex_unlock(pjsua_var.timer_mutex);
if (call) {
if (call->hanging_up)
return status;
eve->call_id = call->index;
eve->med_idx = call_med->idx;
} else {
@ -1678,7 +1685,8 @@ pj_status_t call_media_on_event(pjmedia_event *event,
void pjsua_set_media_tp_state(pjsua_call_media *call_med,
pjsua_med_tp_st tp_st)
{
if (pjsua_var.ua_cfg.cb.on_call_media_transport_state &&
if (!call_med->call->hanging_up &&
pjsua_var.ua_cfg.cb.on_call_media_transport_state &&
call_med->tp_st != tp_st)
{
pjsua_med_tp_state_info info;
@ -1713,7 +1721,9 @@ static void on_srtp_nego_complete(pjmedia_transport *tp,
if (result != PJ_SUCCESS) {
call_med->state = PJSUA_CALL_MEDIA_ERROR;
call_med->dir = PJMEDIA_DIR_NONE;
if (call && pjsua_var.ua_cfg.cb.on_call_media_state) {
if (call && !call->hanging_up &&
pjsua_var.ua_cfg.cb.on_call_media_state)
{
/* Defer the callback to a timer */
pjsua_schedule_timer2(&ice_failed_nego_cb,
(void*)(pj_ssize_t)call->index, 1);
@ -2910,7 +2920,7 @@ pj_status_t pjsua_media_channel_create_sdp(pjsua_call_id call_id,
call->rem_offerer = (rem_sdp != NULL);
/* Notify application */
if (pjsua_var.ua_cfg.cb.on_call_sdp_created) {
if (!call->hanging_up && pjsua_var.ua_cfg.cb.on_call_sdp_created) {
(*pjsua_var.ua_cfg.cb.on_call_sdp_created)(call_id, sdp,
pool, rem_sdp);
}

View File

@ -1100,7 +1100,7 @@ pj_status_t pjsua_vid_channel_update(pjsua_call_media *call_med,
}
}
if (pjsua_var.ua_cfg.cb.on_stream_precreate) {
if (!call->hanging_up && pjsua_var.ua_cfg.cb.on_stream_precreate) {
pjsua_on_stream_precreate_param prm;
prm.stream_idx = call_med->idx;
prm.stream_info.type = PJMEDIA_TYPE_VIDEO;
@ -1869,7 +1869,7 @@ static pj_status_t call_reoffer_sdp(pjsua_call_id call_id,
}
/* Notify application */
if (pjsua_var.ua_cfg.cb.on_call_sdp_created) {
if (!call->hanging_up && pjsua_var.ua_cfg.cb.on_call_sdp_created) {
(*pjsua_var.ua_cfg.cb.on_call_sdp_created)(call_id, sdp,
call->inv->pool_prov,
NULL);