我是VoIP的完整新手,我从来没有研究过这件事的工作原理,但是现在我有一个项目需要我对此有所了解。
所以这是什么,有人可以指导我或告诉我该怎么办:
如何在iOS版本中实现视频呼叫?
自上周以来,我一直在研究这个图书馆,示例带有源代码以及虹吸管我在打电话之前要做,接听电话后该怎么办。
所有核心函数均来自Internet。这是我用来初始化pjsua的内容:
// Init pjsua
{
// Init the config structure
pjsua_config cfg;
pjsua_config_default (&cfg);
cfg.cb.on_incoming_call = &on_incoming_call;
cfg.cb.on_call_media_state = &on_call_media_state;
cfg.cb.on_call_state = &on_call_state;
cfg.cb.on_reg_state2 = &on_reg_state2;
cfg.cb.on_call_media_event = &on_call_media_event;
// Init the logging config structure
pjsua_logging_config log_cfg;
pjsua_logging_config_default(&log_cfg);
log_cfg.console_level = 4;
// Init PJ Media
pjsua_media_config me_cfg;
pjsua_media_config_default(&me_cfg);
// Init the pjsua
status = pjsua_init(&cfg, &log_cfg, &me_cfg);
if (status != PJ_SUCCESS) error_exit("Error in pjsua_init()", status);
}
这是我如何配置我的帐户
的方式// Initialization is done, now start pjsua
status = pjsua_start();
if (status != PJ_SUCCESS) error_exit("Error starting pjsua", status);
// Register the account on local sip server
{
pjsua_acc_config cfg;
pjsua_acc_config_default(&cfg);
// Account ID
char sipId[MAX_SIP_ID_LENGTH];
sprintf(sipId, "sip:%s@%s", sipUser, sipDomain);
cfg.id = pj_str(sipId);
// Reg URI
char regUri[MAX_SIP_REG_URI_LENGTH];
sprintf(regUri, "sip:%s", sipDomain);
cfg.reg_uri = pj_str(regUri);
// Account cred info
cfg.cred_count = 1;
cfg.cred_info[0].scheme = pj_str("digest");
cfg.cred_info[0].realm = pj_str("*");
cfg.cred_info[0].username = pj_str(sipUser);
cfg.cred_info[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
cfg.cred_info[0].data = pj_str(password);
//Normal Video Setup For Account
cfg.vid_in_auto_show = PJ_TRUE;
cfg.vid_out_auto_transmit = PJ_TRUE;
cfg.vid_wnd_flags = PJMEDIA_VID_DEV_WND_BORDER | PJMEDIA_VID_DEV_WND_RESIZABLE;
cfg.vid_cap_dev = PJMEDIA_VID_DEFAULT_CAPTURE_DEV;
cfg.vid_rend_dev = PJMEDIA_VID_DEFAULT_RENDER_DEV;
cfg.reg_retry_interval = 300;
cfg.reg_first_retry_interval = 30;
status = pjsua_acc_add(&cfg, PJ_TRUE, &_acc_id);
if (status != PJ_SUCCESS) error_exit("Error adding account", status);
pjsua_acc_set_online_status(_acc_id, PJ_TRUE);
pjsua_call_setting_default(&_call_setting);
_call_setting.aud_cnt = 1;
_call_setting.vid_cnt = 1;
}
这是我打电话的方式
pj_status_t status;
pj_str_t uri = pj_str(destUri);
status = pjsua_call_make_call(_acc_id, &uri, &(_call_setting), NULL, NULL, NULL);
if (status != PJ_SUCCESS) error_exit("Error making call", status);
这是我处理来电
的方式 /* Callback called by the library upon receiving incoming call */
static void on_incoming_call(pjsua_acc_id acc_id, pjsua_call_id call_id,
pjsip_rx_data *rdata)
{
pjsua_call_info ci;
pjsua_call_setting opt;
pjsua_call_setting_default(&opt);
pjsua_vid_preview_param p_param;
pjsua_vid_preview_param_default(&p_param);
p_param.show = PJ_TRUE;
opt.aud_cnt = 1; //number of simultaneous audio call
opt.vid_cnt = 1; // number of simultaneous video call
PJ_UNUSED_ARG(acc_id);
PJ_UNUSED_ARG(rdata);
pjsua_call_get_info(call_id, &ci);
PJ_LOG(3,(THIS_FILE, "Incoming call from %.*s!!",
(int)ci.remote_info.slen,
ci.remote_info.ptr));
pjsua_call_answer2(call_id, &opt, 200, NULL, NULL);
/* Automatically answer incoming calls with 200/OK */
}
这是我处理媒体状态
的方式 static void on_call_media_state(pjsua_call_id call_id)
{
pjsua_call_info call_info;
unsigned mi;
pj_bool_t has_error = PJ_FALSE;
pjsua_call_get_info(call_id, &call_info);
for (mi=0; mi<call_info.media_cnt; ++mi) {
printf("MyLogger: looping ");
on_call_generic_media_state(&call_info, mi, &has_error);
switch (call_info.media[mi].type) {
case PJMEDIA_TYPE_AUDIO:
printf("MyLogger: case audio ");
on_call_audio_state(&call_info, mi, &has_error);
break;
case PJMEDIA_TYPE_VIDEO:
printf("MyLogger: case video ");
on_call_video_state(&call_info, mi, &has_error);
break;
default:
/* Make gcc happy about enum not handled by switch/case */
printf("MyLogger: default case ");
break;
}
}
static void on_call_video_state(pjsua_call_info *ci, unsigned mi,
pj_bool_t *has_error)
{
NSLog(@"windows id : %d",ci->media[mi].stream.vid.win_in);
NSLog(@"media id : %d",mi);
if (ci->media_status != PJSUA_CALL_MEDIA_ACTIVE)
return;
[[XCPjsua sharedXCPjsua] displayWindow:ci->media[mi].stream.vid.win_in];
PJ_UNUSED_ARG(has_error);
}
最后这是我显示视频窗口的方式:
void displayWindow(pjsua_vid_win_id wid)
{
#if PJSUA_HAS_VIDEO
NSLog(@"windows id : %d",wid);
int i, last;
i = (wid == PJSUA_INVALID_ID) ? 0 : wid;
last = (wid == PJSUA_INVALID_ID) ? PJSUA_MAX_VID_WINS : wid+1;
if(wid == PJSUA_INVALID_ID){
printf("MyLogger: displayWindow failedn");
}else{
printf("MyLogger: displayWindow successn");}
for (;i < last; ++i) {
pjsua_vid_win_info wi;
pj_status_t myStatus;
myStatus = pjsua_vid_win_get_info(i, &wi);
if(myStatus != PJ_SUCCESS) pjsua_perror(THIS_FILE, THIS_FILE, myStatus);
if (myStatus == PJ_SUCCESS) {
UIView *parent = mainViewController.view;
UIView *view = (__bridge UIView *)wi.hwnd.info.ios.window;
if (view) {
dispatch_async(dispatch_get_main_queue(), ^{
/* Add the video window as subview */
if (![view isDescendantOfView:parent]){
[parent addSubview:view];
}
if (!wi.is_native) {
/* Resize it to fit width */
view.bounds = CGRectMake(0, 0, parent.bounds.size.width,
(parent.bounds.size.height *
1.0*parent.bounds.size.width/
view.bounds.size.width));
/* Center it horizontally */
view.center = CGPointMake(parent.bounds.size.width/2.0,
view.bounds.size.height/2.0);
} else {
/* Preview window, move it to the bottom */
view.center = CGPointMake(parent.bounds.size.width/2.0,
parent.bounds.size.height-
view.bounds.size.height/2.0);
}
});
}
}
}
#endif
}
当我接到传入电话时,displaywindow(pjsua_vid_win_id wid)将被调用,但它总是在控制台中打印" mylogger:displayWindow失败 n",所以我相信我缺少一些东西,但是我不知道这是什么线索是。
请帮助。
对于那些在传入视频中拥有 green窗口的人,但没有视频框架,我在过去几天里经历了相同的情况。这是我的2美分,出于可能的原因。
PJSIP Video User's Guide
之后,我假设设置vid_in_auto_show = PJ_TRUE
足以自动展示传入的视频,而vid_out_auto_transmit = PJ_TRUE
则是我缺少的作品。根据用户指南:"将其设置为pj_true将导致视频传输自动在每个传出的呼叫上自动启动,并在指示视频支持的传入呼叫上" "。设置vid_out_auto_transmit = PJ_TRUE
之后,即使没有设置vid_in_auto_show = PJ_TRUE
,视频也会在我身边出现绿色窗口后不久出现。
,不要忘记确保vid_cnt
,vid_cap_dev
和vid_rend_dev
在调用pjsua_acc_add
之前正确设置在一起。