PJSIP 학습노트-PJSUA층이 호출하는 주요 절차
8649 단어 네트워크 통신
pjsua_call_make_콜에서 호출을 시작하면 이 호출을 시작하는 절차는 어떻게 됩니까?먼저 이 함수를 살펴보자.
/*
* Make outgoing call to the specified URI using the specified account.
*/
PJ_DEF(pj_status_t) pjsua_call_make_call(pjsua_acc_id acc_id,
const pj_str_t *dest_uri,
const pjsua_call_setting *opt,
void *user_data,
const pjsua_msg_data *msg_data,
pjsua_call_id *p_call_id)
{
pj_pool_t *tmp_pool = NULL;
pjsip_dialog *dlg = NULL;
pjsua_acc *acc;
pjsua_call *call;
int call_id = -1;
pj_str_t contact;
pj_status_t status;
/* Check that account is valid */
PJ_ASSERT_RETURN(acc_id>=0 || acc_idslen, dest_uri->ptr));
pj_log_push_indent();
PJSUA_LOCK();
//
/* Create sound port if none is instantiated, to check if sound device
* can be used. But only do this with the conference bridge, as with
* audio switchboard (i.e. APS-Direct), we can only open the sound
* device once the correct format has been known
*/
if (!pjsua_var.is_mswitch && pjsua_var.snd_port==NULL &&
pjsua_var.null_snd==NULL && !pjsua_var.no_snd)
{
status = pjsua_set_snd_dev(pjsua_var.cap_dev, pjsua_var.play_dev);
if (status != PJ_SUCCESS)
goto on_error;
}
// SIP
acc = &pjsua_var.acc[acc_id];
if (!acc->valid) {
pjsua_perror(THIS_FILE, "Unable to make call because account "
"is not valid", PJ_EINVALIDOP);
status = PJ_EINVALIDOP;
goto on_error;
}
//
/* Find free call slot. */
call_id = alloc_call_id();
if (call_id == PJSUA_INVALID_ID) {
pjsua_perror(THIS_FILE, "Error making call", PJ_ETOOMANY);
status = PJ_ETOOMANY;
goto on_error;
}
//
/* Clear call descriptor */
reset_call(call_id);
call = &pjsua_var.calls[call_id];
/* Associate session with account */
call->acc_id = acc_id;
call->call_hold_type = acc->cfg.call_hold_type;
//
/* Apply call setting */
status = apply_call_setting(call, opt, NULL);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Failed to apply call setting", status);
goto on_error;
}
/* Create temporary pool */
tmp_pool = pjsua_pool_create("tmpcall10", 512, 256);
/* Verify that destination URI is valid before calling
* pjsua_acc_create_uac_contact, or otherwise there
* a misleading "Invalid Contact URI" error will be printed
* when pjsua_acc_create_uac_contact() fails.
*/
if (1) {
pjsip_uri *uri;
pj_str_t dup;
// SIP
pj_strdup_with_null(tmp_pool, &dup, dest_uri);
uri = pjsip_parse_uri(tmp_pool, dup.ptr, dup.slen, 0);
if (uri == NULL) {
pjsua_perror(THIS_FILE, "Unable to make call",
PJSIP_EINVALIDREQURI);
status = PJSIP_EINVALIDREQURI;
goto on_error;
}
}
/* Mark call start time. */
pj_gettimeofday(&call->start_time);
/* Reset first response time */
call->res_time.sec = 0;
// Contact
/* Create suitable Contact header unless a Contact header has been
* set in the account.
*/
if (acc->contact.slen) {
contact = acc->contact;
} else {
status = pjsua_acc_create_uac_contact(tmp_pool, &contact,
acc_id, dest_uri);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Unable to generate Contact header",
status);
goto on_error;
}
}
// SIP (Dialog)
/* Create outgoing dialog: */
status = pjsip_dlg_create_uac( pjsip_ua_instance(),
&acc->cfg.id, &contact,
dest_uri, dest_uri, &dlg);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Dialog creation failed", status);
goto on_error;
}
/* Increment the dialog's lock otherwise when invite session creation
* fails the dialog will be destroyed prematurely.
*/
pjsip_dlg_inc_lock(dlg);
// Via
if (acc->cfg.allow_via_rewrite && acc->via_addr.host.slen > 0)
pjsip_dlg_set_via_sent_by(dlg, &acc->via_addr, acc->via_tp);
// , ?
/* Calculate call's secure level */
call->secure_level = get_secure_level(acc_id, dest_uri);
// , ?
/* Attach user data */
call->user_data = user_data;
// , ?
/* Store variables required for the callback after the async
* media transport creation is completed.
*/
if (msg_data) {
call->async_call.call_var.out_call.msg_data = pjsua_msg_data_clone(
dlg->pool, msg_data);
}
//
call->async_call.dlg = dlg;
/* Temporarily increment dialog session. Without this, dialog will be
* prematurely destroyed if dec_lock() is called on the dialog before
* the invite session is created.
*/
pjsip_dlg_inc_session(dlg, &pjsua_var.mod);
//
/* Init media channel */
status = pjsua_media_channel_init(call->index, PJSIP_ROLE_UAC,
call->secure_level, dlg->pool,
NULL, NULL, PJ_TRUE,
&on_make_call_med_tp_complete);
//
if (status == PJ_SUCCESS) {
status = on_make_call_med_tp_complete(call->index, NULL);
if (status != PJ_SUCCESS)
goto on_error;
} else if (status != PJ_EPENDING) {
pjsua_perror(THIS_FILE, "Error initializing media channel", status);
pjsip_dlg_dec_session(dlg, &pjsua_var.mod);
goto on_error;
}
/* Done. */
if (p_call_id)
*p_call_id = call_id;
pjsip_dlg_dec_lock(dlg);
pj_pool_release(tmp_pool);
PJSUA_UNLOCK();
pj_log_pop_indent();
return PJ_SUCCESS;
on_error:
if (dlg) {
/* This may destroy the dialog */
pjsip_dlg_dec_lock(dlg);
}
if (call_id != -1) {
pjsua_media_channel_deinit(call_id);
reset_call(call_id);
}
pjsua_check_snd_dev_idle();
if (tmp_pool)
pj_pool_release(tmp_pool);
PJSUA_UNLOCK();
pj_log_pop_indent();
return status;
}
먼저 호출 표지를 어떻게 분배하는지 살펴보자.
4
/* Allocate one call id */
static pjsua_call_id alloc_call_id(void)
{
pjsua_call_id cid;
#if 1
/* New algorithm: round-robin */
if (pjsua_var.next_call_id >= (int)pjsua_var.ua_cfg.max_calls ||
pjsua_var.next_call_id < 0)
{
pjsua_var.next_call_id = 0;
}
// next_call_id max_calls calls
for (cid=pjsua_var.next_call_id;
cid
위의 함수를 보면 이곳의 분배 호출 표지는calls 데이터에서 빈 단원(호출 데이터를 저장하는 데 사용)을 찾을 뿐이다. 이 호출 표지는 SIP 프로토콜에 있는CALL ID의 개념이 아니다.reset_콜 함수는 호출 매개 변수를 0 값으로 설정하는 것입니다.
*
* Reset call descriptor.
*/
static void reset_call(pjsua_call_id id)
{
pjsua_call *call = &pjsua_var.calls[id];
unsigned i;
pj_bzero(call, sizeof(*call));
call->index = id;
call->last_text.ptr = call->last_text_buf_;
for (i=0; imedia); ++i) {
pjsua_call_media *call_med = &call->media[i];
call_med->ssrc = pj_rand();
call_med->strm.a.conf_slot = PJSUA_INVALID_ID;
call_med->strm.v.cap_win_id = PJSUA_INVALID_ID;
call_med->strm.v.rdr_win_id = PJSUA_INVALID_ID;
call_med->call = call;
call_med->idx = i;
call_med->tp_auto_del = PJ_TRUE;
}
pjsua_call_setting_default(&call->opt);
pj_timer_entry_init(&call->reinv_timer, PJ_FALSE,
(void*)(pj_size_t)id, &reinv_timer_cb);
}
호출 매개 변수를 설정하려면:
static pj_status_t apply_call_setting(pjsua_call *call,
const pjsua_call_setting *opt,
const pjmedia_sdp_session *rem_sdp)
{
pj_assert(call);
if (!opt)
return PJ_SUCCESS;
#if !PJMEDIA_HAS_VIDEO
pj_assert(opt->vid_cnt == 0);
#endif
call->opt = *opt;
// ,
// SDP, UAS(User Agent Server), UAC
/* If call is established, reinit media channel */
if (call->inv && call->inv->state == PJSIP_INV_STATE_CONFIRMED) {
pjsip_role_e role = rem_sdp? PJSIP_ROLE_UAS : PJSIP_ROLE_UAC;
pj_status_t status;
//
status = pjsua_media_channel_init(call->index, role,
call->secure_level,
call->inv->pool_prov,
rem_sdp, NULL,
PJ_FALSE, NULL);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Error re-initializing media channel",
status);
return status;
}
}
return PJ_SUCCESS;
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
TCP 및 UDP 편집 프로세스 및 코드socket - 클라이언트 연결을 감청하는 데 사용할 소켓을 만듭니다 bind - 감청 소켓을 서버 IP 주소 및 포트 번호와 연결합니다 listen - 감청 시작 accept - 클라이언트 연결을 가져오고 클라이언...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.