PJSIP iOS视频呼叫实现问题
我是一个完全的网络电话新手,我从来没有研究过这个东西是如何工作的,但现在我有一个项目,需要我对这个东西有知识 问题是,有人能指导我或告诉我该怎么做: 如何在iOS版本中实现视频通话 从上周开始,我就一直在研究这个库,它的示例包括源代码和虹吸,但是我仍然找不到启动视频通话或接收视频通话的正确方法。比如,我在打电话之前应该做什么,在接听电话之后应该做什么 所有的核心功能都来自互联网。 以下是我用来初始化Pjsua的内容:PJSIP iOS视频呼叫实现问题,ios,objective-c,video,pjsip,Ios,Objective C,Video,Pjsip,我是一个完全的网络电话新手,我从来没有研究过这个东西是如何工作的,但现在我有一个项目,需要我对这个东西有知识 问题是,有人能指导我或告诉我该怎么做: 如何在iOS版本中实现视频通话 从上周开始,我就一直在研究这个库,它的示例包括源代码和虹吸,但是我仍然找不到启动视频通话或接收视频通话的正确方法。比如,我在打电话之前应该做什么,在接听电话之后应该做什么 所有的核心功能都来自互联网。 以下是我用来初始化Pjsua的内容: // Init pjsua { // Init the config
// 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);
}
调用媒体状态下的静态无效(pjsua调用id调用id)
{
pjsua_call_info call_info;
无符号mi;
pj_bool_t has_error=pj_FALSE;
pjsua_call_get_info(call_id和call_info);
对于(mi=0;mimedia[mi].stream.vid.win\u in);
NSLog(@“媒体id:%d”,mi);
如果(ci->媒体状态!=PJSUA\U呼叫\U媒体\U活动)
返回;
[[XCPjsua sharedXCPjsua]显示窗口:ci->media[mi].stream.vid.win_in];
PJ_未使用参数(有错误);
}
最后,这是我显示视频窗口的方式:
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
}
void显示窗口(pjsua\u vid\u win\u id wid)
{
#如果PJSUA_有视频
NSLog(@“windows id:%d”,wid);
int i,最后;
i=(wid==PJSUA\u无效\u ID)?0:wid;
last=(wid==PJSUA\u无效\u ID)?PJSUA\u最大值\u VID\u WINS:wid+1;
如果(wid==PJSUA\u无效\u ID){
printf(“MyLogger:displayWindow失败\n”);
}否则{
printf(“MyLogger:displayWindow成功\n”);}
对于(;i
当我接到来电时,displayWindow(pjsua_vid_win_id wid)将被调用,但它总是在我的控制台中打印“MyLogger:displayWindow failed\n”,因此我相信我缺少了一些东西,但我不知道它是什么
请帮助。对于那些拥有传入视频的绿色窗口但没有视频帧的人,我在过去几天也经历了同样的情况。这是我的2分钱,以找出问题的可能原因 按照《PJSIP视频用户指南》,我假设设置
vid_in_auto_show=PJ_TRUE
足以自动显示传入的视频,而vid_out_auto_transmit=PJ_TRUE
则是我缺少的部分。根据用户指南:“将此设置为PJ_TRUE将导致在每个传出呼叫和在其提供的视频支持中指示视频支持的传入呼叫上自动启动视频传输”。设置vid\u out\u auto\u transmit=PJ\u TRUE
后,即使没有设置vid\u in\u auto\u show=PJ\u TRUE
,视频也会在绿色窗口出现在我的一侧后不久出现
在调用
pjsua\u acc\u add
之前,不要忘记确保vid\u cnt
、vid\u cap\u dev
和vid\u rend\u dev
一起正确设置,当您接到来电时,您希望显示一个视图控制器,并且它是从来电方法调用的。但是这个显示窗口的名称是什么?请简要解释。感谢您的评论,经过一个月的尝试和错误,我发现问题来自编解码器兼容性和我对view hierarchyHi Y.J.Leong的肤浅了解,我也遇到过类似的问题。遗憾的是,我之前没有发现这个问题。但是,我确实设法解决了这个问题,添加了最终视图,就像您在[parent addSubview:view]中所做的那样代码>失败,+[GLView superview]:为我将无法识别的选择器发送到类
。你有没有注意到类似的错误?谢谢。你能把视频通话的密码发给我吗。我被困在同一条路上@Y.J.LeongCan您可以发送给我视频通话的唯一方法定义。我找不到任何视频呼叫的代码。在iOS中未调用\u传入的\u call()。这是否意味着sip未连接?@iosdeveloper sip帐户是否已成功注册?谢谢您的评论。没有sip没有注册。我已经注册了,现在可以用了。谢谢。