C PJSip传出呼叫不工作

C PJSip传出呼叫不工作,c,pjsip,C,Pjsip,我正在开发一个iOS应用程序,它的功能是使用PJSUA打电话。 同时,我的同事正在使用PJSUA 2为Android制作相同的应用程序。当我们从安卓系统打电话到iOS或从安卓系统打电话到安卓系统时,一切正常。但当我们试图从iOS打电话到Android或从iOS打电话到iOS时,我们会遇到一个错误: 18:51:46.959 pjsua_media.c .....Call 0: updating media.. 18:51:46.959 pjsua_media.c .......Media

我正在开发一个iOS应用程序,它的功能是使用PJSUA打电话。 同时,我的同事正在使用PJSUA 2为Android制作相同的应用程序。当我们从安卓系统打电话到iOS或从安卓系统打电话到安卓系统时,一切正常。但当我们试图从iOS打电话到Android或从iOS打电话到iOS时,我们会遇到一个错误:

18:51:46.959  pjsua_media.c  .....Call 0: updating media..
18:51:46.959  pjsua_media.c  .......Media stream call00:0 is destroyed
18:51:46.959  pjsua_media.c  ......pjmedia_transport_media_start() failed for call_id 0 media 0: SRTP crypto-suite name not match the offerer tag (PJMEDIA_SRTP_ECRYPTONOTMATCH)
18:51:46.959  pjsua_media.c  .......Media stream call00:0 is destroyed
18:51:46.960  pjsua_media.c  ......Error updating media call00:0: SRTP crypto-suite name not match the offerer tag (PJMEDIA_SRTP_ECRYPTONOTMATCH)
18:51:46.960   pjsua_core.c  .....TX 362 bytes Request msg ACK/cseq=19029 (tdta0x1200c1600) to TLS 95.213.169.231:1605:
ACK sip:s2@95.213.169.231:1605;transport=tls SIP/2.0
这是我的班级,与PJSUA合作:

#import <Foundation/Foundation.h>
#import "SIPConnection.h"
#import <pjlib.h>
#import <pjsua.h>
#import <pj/log.h>
#import <pjmedia-codec.h>
#import <pjmedia.h>

@interface SIPConnection ()

@end

@implementation SIPConnection

pjsua_acc_id acc_id = -1;
pjsua_call_id current_call_id = -1;
bool registration_status_is_ok = false;
bool is_making_call = false;

-(void) registerAccount {
    registerAccount();
}

-(void) makeCall {
    is_making_call = true;
    registerAccount();
}

void registerAccount() {

    pjsua_create();

    pjsua_config ua_cfg;
    pjsua_logging_config log_cfg;
    pjsua_media_config media_cfg;

    char* user_agent_string = "XChat";
    pj_str_t user_agent = pj_str(user_agent_string);
    ua_cfg.user_agent = user_agent;
    pjsua_config_default(&ua_cfg);
    pjsua_logging_config_default(&log_cfg);
    pjsua_media_config_default(&media_cfg);

    ua_cfg.cb.on_reg_state = &sip_reg_state_changed;
    ua_cfg.cb.on_call_state = &sip_call_state_changed;
    ua_cfg.cb.on_call_media_state = &sip_call_media_state_changed;
    ua_cfg.cb.on_incoming_call = &sip_incoming_call;

    media_cfg.ec_options = 3;
    media_cfg.ec_tail_len = 1000;

    pjsua_init(&ua_cfg, &log_cfg, &media_cfg);

    pjsua_transport_config transport_cfg;
    pjsua_transport_config_default(&transport_cfg);
    transport_cfg.port = 1605;
    pjsua_transport_id trasport_id;

    pjsua_transport_create(PJSIP_TRANSPORT_TLS, &transport_cfg, &trasport_id);

    pjsua_acc_config acc_cfg;
    pjsua_acc_config_default(&acc_cfg);

    acc_cfg.register_on_acc_add = YES;
    acc_cfg.priority = 100;
    acc_cfg.reg_retry_interval = 3;
    acc_cfg.reg_retry_random_interval = 3;
    acc_cfg.publish_enabled = NO;
    acc_cfg.unreg_timeout = 1500;
    acc_cfg.reg_first_retry_interval = 5;
    acc_cfg.reg_delay_before_refresh = 0;
    char* reg_uri_string = "sip:95.213.169.231:1605;transport=TLS";
    char* acc_uri_string = "sip:s2@95.213.169.231:1605";
    pj_str_t reg_uri = pj_str(reg_uri_string);
    pj_str_t acc_uri = pj_str(acc_uri_string);
    acc_cfg.reg_uri = reg_uri;
    acc_cfg.cred_info[0].scheme=pj_str("digest");
    acc_cfg.cred_info[0].data_type=0;
    acc_cfg.cred_info[0].username=pj_str("s2");
    acc_cfg.cred_info[0].realm=pj_str("*");
    acc_cfg.cred_info[0].data=pj_str("LHillKkF4Aflc3rR");
    acc_cfg.cred_count = 1;
    acc_cfg.use_srtp = PJMEDIA_SRTP_MANDATORY;
    acc_cfg.srtp_secure_signaling = 1;
    acc_cfg.allow_sdp_nat_rewrite = 1;
    acc_cfg.allow_contact_rewrite = 1;
    acc_cfg.id = acc_uri;



    pjsua_acc_add(&acc_cfg, YES, &acc_id);

    pjsua_start();

}

static void sip_reg_state_changed(pjsua_acc_id acc_id) {
    pjsua_acc_info acc_info;
    pj_status_t status = pjsua_acc_get_info(acc_id, &acc_info);
    if (status != PJ_SUCCESS) {
        NSLog(@"Couldn't get account status");
        registration_status_is_ok = false;
        return;
    }
    if (acc_info.status == 200) {
        NSLog(@"Account is registered!");
        registration_status_is_ok = true;
        make_call();
    }
}

static void sip_call_state_changed(pjsua_call_id call_id, pjsip_event* event) {

}

static void sip_call_media_state_changed(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);



    current_call_id = call_id;

    mi=0;

    //for (mi=0; mi<call_info.media_cnt; ++mi) {
        on_call_generic_media_state(&call_info, mi, &has_error);

        switch (call_info.media[mi].type) {
                case PJMEDIA_TYPE_AUDIO:
                on_call_audio_state(&call_info, mi, &has_error);
                break;
           }
    //}
}

static void on_call_audio_state(pjsua_call_info *ci, unsigned mi, pj_bool_t *has_error)
{
    PJ_UNUSED_ARG(has_error);
    /* Stop ringback */
    //ring_stop(ci->id);

    /* Connect ports appropriately when media status is ACTIVE or REMOTE HOLD,
          457  * otherwise we should NOT connect the ports.
          458  */

    if (ci->media[mi].status == PJSUA_CALL_MEDIA_ACTIVE || ci->media[mi].status == PJSUA_CALL_MEDIA_REMOTE_HOLD)
    {
            pj_bool_t connect_sound = PJ_TRUE;
            pj_bool_t disconnect_mic = PJ_FALSE;
            pjsua_conf_port_id call_conf_slot;

            call_conf_slot = ci->media[mi].stream.aud.conf_slot;

        if (connect_sound) {
            pj_status_t res = pjsua_conf_connect(call_conf_slot, 0);
            if (!disconnect_mic)
            {
                res = pjsua_conf_connect(0, call_conf_slot);
            }
        }
    }
}

static void on_call_generic_media_state(pjsua_call_info *ci, unsigned mi, pj_bool_t *has_error)
{
    const char *status_name[] = {
        "None",
        "Active",
        "Local hold",
        "Remote hold",
        "Error"

    };

    PJ_UNUSED_ARG(has_error);

    pj_assert(ci->media[mi].status <= PJ_ARRAY_SIZE(status_name));
    pj_assert(PJSUA_CALL_MEDIA_ERROR == 4);
}



static void sip_incoming_call(pjsua_acc_id acc_id, pjsua_call_id call_id, pjsip_rx_data *rdata)
{
    pjsua_call_info call_info;
    pjsua_call_get_info(call_id, &call_info);

    pjsua_call_answer(call_id, 200, NULL, NULL);
}

static void make_call()
{
    if ((registration_status_is_ok) && (is_making_call))
    {
        pjsua_call_setting call_stg;
        pjsua_call_setting_default(&call_stg);
        call_stg.aud_cnt = 1;
        call_stg.vid_cnt = 0;

       // pjsua_call_id call_id;

        pj_str_t dst_uri = pj_str("sip:s3@95.213.169.231:1605;transport=TLS");

        pjsua_call_make_call(acc_id, &dst_uri, &call_stg, NULL, NULL, NULL);

    }
}

static void end_call()
{
    /*if (current_call_id != -1)
    {
        pjsua_call_dump(current_call_id, YES, NULL, 8, NULL);
    }*/
    if (acc_id != -1)
    {
        pjsua_acc_del(acc_id);
    }
    pjsua_destroy();
}

- (void)endCall
{
    end_call();
}

@end
#导入
#导入“SIPConnection.h”
#进口
#进口
#进口
#进口
#进口
@接口连接()
@结束
@SIPConnection的实现
pjsua_acc_id acc_id=-1;
pjsua_call_id current_call_id=-1;
bool注册状态为ok=false;
bool正在发出呼叫=false;
-(作废)注册帐户{
registerAccount();
}
-(无效)呼叫{
正在打电话=真;
registerAccount();
}
作废注册表帐户(){
pjsua_create();
pjsua_配置ua_cfg;
pjsua_日志记录_配置日志_cfg;
pjsua_media_config media_cfg;
char*user\u agent\u string=“XChat”;
pj_str_t user_agent=pj_str(user_agent_字符串);
ua_cfg.user_agent=用户_agent;
pjsua_config_default(&ua_cfg);
pjsua\u日志记录\u配置\u默认值(&log\u cfg);
pjsua_media_config_default(&media_cfg);
ua_cfg.cb.on_reg_state=&sip_reg_state_已更改;
ua_cfg.cb.on_call_state=&sip_call_state_change;
ua_cfg.cb.on_call_media_state=&sip_call_media_state_change;
ua_cfg.cb.on_传入_呼叫=&sip_传入_呼叫;
媒体_cfg.ec_选项=3;
媒体长度=1000;
pjsua_init(&ua_cfg,&log_cfg,&media_cfg);
pjsua_传输_配置传输_cfg;
pjsua_传输_配置_默认值(&transport_cfg);
运输港=1605;
pjsua_交通运输_id trasport_id;
pjsua_transport_create(PJSIP_transport_TLS、和transport_cfg、和trasport_id);
pjsua_acc_config acc_cfg;
pjsua_acc_config_default(&acc_cfg);
acc\u cfg.register\u on\u acc\u add=是;
acc_cfg.priority=100;
acc_cfg.reg_重试_间隔=3;
acc_cfg.reg_重试_随机_间隔=3;
acc_cfg.publish_enabled=否;
acc_cfg.unr_超时=1500;
acc_cfg.reg_first_retry_interval=5;
acc_cfg.reg_刷新前的延迟=0;
char*reg\u uri\u string=“sip:95.213.169.231:1605;传输=TLS”;
char*acc\u uri\u string=“sip:s2@95.213.169.231:1605";
pj_str_t reg_uri=pj_str(reg_uri_字符串);
pj_str_t acc_uri=pj_str(acc_uri_字符串);
acc_cfg.reg_uri=reg_uri;
acc_cfg.cred_info[0]。scheme=pj_str(“摘要”);
acc_cfg.cred_info[0]。数据类型=0;
acc_cfg.cred_info[0]。用户名=pj_str(“s2”);
acc_cfg.cred_info[0]。realm=pj_str(“*”);
acc_cfg.cred_info[0]。数据=pj_str(“LHillKkF4Aflc3rR”);
acc_cfg.cred_计数=1;
acc_cfg.use_srtp=PJMEDIA_srtp_必填;
acc_cfg.srtp_secure_信令=1;
acc_cfg.allow_sdp_nat_rewrite=1;
acc_cfg.allow_contact_rewrite=1;
acc_cfg.id=acc_uri;
pjsua_acc_add(&acc_cfg,YES,&acc_id);
pjsua_start();
}
静态无效sip注册状态更改(pjsua acc id acc id){
pjsua_acc_info acc_info;
pj_status_t status=pjsua_acc_get_info(acc_id和acc_info);
如果(状态!=PJ_成功){
NSLog(@“无法获取帐户状态”);
注册\状态\为\确定=错误;
返回;
}
如果(acc_信息状态==200){
NSLog(@“帐户已注册!”);
注册\状态\为\正常=真;
打电话();
}
}
静态无效sip调用状态更改(pjsua调用id调用id、pjsip事件*事件){
}
静态无效sip_调用_媒体_状态_更改(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;
//对于(mi=0;miid);
/*当介质状态为“活动”或“远程保持”时,正确连接端口,
457*否则我们不应该连接端口。
458  */
如果(ci->media[mi]。状态==PJSUA_CALL_media_ACTIVE | ci->media[mi]。状态==PJSUA_CALL_media_REMOTE_HOLD)
{
pj_bool_t connect_sound=pj_TRUE;
pj_bool_t disconnect_mic=pj_FALSE;
pjsua_conf_port_id call_conf_slot;
调用\u conf\u slot=ci->media[mi].stream.aud.conf\u slot;
如果(连接声音){
pj_status_t res=pjsua_conf_connect(调用conf_插槽,0);
如果(!断开麦克风)
{
res=pjsua_conf_connect(0,调用_conf_插槽);
}
}
}
}
调用时静态无效\u通用\u媒体\u状态(pjsua\u调用\u信息*ci、未签名mi、pj\u bool\u t*有\u错误)
{
常量字符*状态_名称[]={
“没有”,
“活动”,
“本地持有”,
“远程持有”,
“错误”
};
PJ_未使用参数(有错误);

pj_assert(ci->media[mi]。状态似乎您在拨打电话时也需要发送callID,

pjsua_call_id call_id;

pj_str_t dst_uri = pj_str("sip:s3@95.213.169.231:1605;transport=TLS");

pjsua_call_make_call(acc_id, &dst_uri, &call_stg, NULL, NULL, &call_id);

你确定吗?你想要SRTP传输吗?因为你提到acc_cfg.use_SRTP=PJMEDIA_SRTP_是强制性的;它显示SRTP加密套件名称与报价人标签不匹配(例外)在SRTP传输中。检查SRTP凭据并检查IOS和android是否都支持SRTP传输,当android不支持SRTP时,这将是一个问题。请检查并在下面给出建议