PJSIP iOS视频通话实现问题



我是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_cntvid_cap_devvid_rend_dev在调用pjsua_acc_add之前正确设置在一起。

最新更新