我是VOIP的新手,我以前从未研究过这件事是如何工作的,但现在我有一个项目要求我对这件事有所了解。
所以这就是事情,有人可以指导我或告诉我应该怎么做:
如何在iOS版本中实现视频通话?
我上周以来一直在研究这个库,它带有源代码和虹吸的示例,但我仍然找不到正确的方式来发起视频通话或接收视频通话。就像应该是什么在打电话之前我会这样做,接听电话后该怎么办。
所有核心功能均来自互联网。 以下是我用来初始化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 failed\n");
}else{
printf("MyLogger: displayWindow success\n");}
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 failed \ n”,所以我相信我有一些缺失,但我不知道它是什么是
请帮忙。
答案 0 :(得分:0)
对于那些拥有输入视频的绿色窗口但没有视频帧的人,我在过去几天遇到过相同的情况。这是我的2美分可能导致问题的原因。
在PJSIP Video User's Guide
之后,我假设设置vid_in_auto_show = PJ_TRUE
足以自动显示传入的视频,而vid_out_auto_transmit = PJ_TRUE
原来是我的遗失部分。根据用户指南:&#34;将此设置为PJ_TRUE将导致视频传输在每个拨出电话和来电中自动启动,表示其报价中的视频支持&#34; 。设置vid_out_auto_transmit = PJ_TRUE
后,即使没有设置vid_in_auto_show = PJ_TRUE
,视频也会在绿色窗口显示在我身边后不久出现。
在忘记vid_cnt
之前,不要忘记确保vid_cap_dev
,vid_rend_dev
和pjsua_acc_add
一起正确设置。