Report disconnection event immediately when hanging up a call (#2600)
This commit is contained in:
parent
fe963266b1
commit
2eea0ace2b
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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. */
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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-->");
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue