PJSUA在使用c注册SIP时出错

5 投票
1 回答
3850 浏览
提问于 2025-05-10 23:54

我正在用C语言写一个软电话客户端,使用的是PJSUA库。首先,我试了一个在pjsip官网上提供的示例代码。现在我在注册到我的Asterisk服务器时遇到了一个错误,但我不知道为什么会这样。我可以成功拨打电话,但因为没有注册,所以无法接听电话。

我试过一个用Python写的注册示例,结果运行得很好。

当然,我已经在sip.conf和extensions.conf文件中配置了我的Asterisk,以便它能够注册这个客户端,这一点在用Python示例程序注册时也能看到。

所以,我很感谢你们花时间帮我找出我的错误。

这是我的C代码:

#define PJ_IS_LITTLE_ENDIAN 1
#define PJ_IS_BIG_ENDIAN 0 
#include <pjsua-lib/pjsua.h>
#include <pjlib.h> 
#include <pjlib-util.h> 
#include <pjnath.h> 
#include <pjsip.h> 
#include <pjsip_ua.h> 
#include <pjsip_simple.h> 
#include <pjmedia.h> 
#include <pjmedia-codec.h> 
#define THIS_FILE "App"
#define SIP_USER "demo-user2"
#define SIP_DOMAIN "192.168.2.59"
#define SIP_PASSWD "123456"

static void on_incoming_call( pjsua_acc_id acc_id, pjsua_call_id call_id, pjsip_rx_data *rdata );
static void on_call_state( pjsua_call_id call_id, pjsip_event *e );
static void on_call_media_state( pjsua_call_id call_id );
static void error_exit( const char *title, pj_status_t status );

int main( int argc, char *argv[] ) {
    pjsua_acc_id acc_id;
    pj_status_t status;

    /* Create pjsua */  
    status = pjsua_create();
    if ( status != PJ_SUCCESS ) {
        error_exit( "Error in pjsua_create()", status );
    }

    /* If argument is specified, it's got to be a valid SIP URL */
    if ( argc > 1 ) {
        status = pjsua_verify_url( argv[1] );
        if ( status != PJ_SUCCESS ) {  
            error_exit( "Invalid URL in argv", status );
        }
    }   

    /* Init pjsua */
    pjsua_config cfg;
    pjsua_logging_config log_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;

    pjsua_logging_config_default( &log_cfg );
    log_cfg.console_level = 4;
    status = pjsua_init( &cfg, &log_cfg, NULL );
    if ( status != PJ_SUCCESS ) {
         error_exit( "Error in pjsua_init()", status );
    }

    /* Add UDP transport */
    {
        pjsua_transport_config cfg;

        pjsua_transport_config_default( &cfg );
        cfg.port = 5060;
        status = pjsua_transport_create( PJSIP_TRANSPORT_UDP, &cfg, NULL );
        if ( status != PJ_SUCCESS ) { 
            error_exit( "Error creating transport", status );
        }
    }

    /* Start pjsua */
    status = pjsua_start();
    if ( status != PJ_SUCCESS ) {
        error_exit( "Error starting pjsua", status );
    }

    /* Register to SIP server */
    {
        pjsua_acc_config cfg;
        pjsua_acc_config_default( &cfg );
        cfg.id = pj_str( "sip:" SIP_USER "@" SIP_DOMAIN );
        cfg.reg_uri = pj_str("sip:" SIP_DOMAIN );
        cfg.cred_count = 1;
        cfg.cred_info[0].realm = pj_str( SIP_DOMAIN );
        cfg.cred_info[0].scheme = pj_str( "*" );
        cfg.cred_info[0].username = pj_str( SIP_USER );
        cfg.cred_info[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
        cfg.cred_info[0].data = pj_str( SIP_PASSWD );
        status = pjsua_acc_add( &cfg, PJ_TRUE, &acc_id );
        if ( status != PJ_SUCCESS ){
            error_exit( "Error adding account", status );
        }
    }

    /* if URL is specified, make call to the url */
    if ( argc > 1 ) {
        pj_str_t uri = pj_str( argv[1] );
        status = pjsua_call_make_call( acc_id, &uri, 0, NULL, NULL, NULL );
        if (status != PJ_SUCCESS) {
            error_exit("Error making call", status);
        }
    }

    /* Wait until user press "q" to quit. */
    while ( 1 ) {
        char option[10];

        puts( "Press 'h' to hangup all calls, 'q' to quit" );
        if ( fgets( option, sizeof(option), stdin ) == NULL ) {
            puts( "EOF while reading stdin, will quit now.." );
            break;
        }

        if ( option[0] == 'q' ) {
            break;
        }

        if ( option[0] == 'h' ) {
            pjsua_call_hangup_all();
        }
    }

    /* Destroy pjsua */
    pjsua_destroy();

    return 0;
}

static void on_incoming_call( pjsua_acc_id acc_id, pjsua_call_id call_id, pjsip_rx_data *rdata ) {
    pjsua_call_info ci;
    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 ) );

    /* Automatically answer incoming calls with 200/OK */
    pjsua_call_answer( call_id, 200, NULL, NULL );
}

static void on_call_state( pjsua_call_id call_id, pjsip_event *e ) {
    pjsua_call_info ci;

    PJ_UNUSED_ARG( e );

    pjsua_call_get_info( call_id, &ci );
    PJ_LOG( 3,( THIS_FILE, "Call %d state=%.*s", call_id, (int) ci.state_text.slen, ci.state_text.ptr ) );
}

static void on_call_media_state( pjsua_call_id call_id ) {
    pjsua_call_info ci;
    pjsua_call_get_info( call_id, &ci );

    if ( ci.media_status == PJSUA_CALL_MEDIA_ACTIVE ) {
        pjsua_conf_connect( ci.conf_slot, 0 );
        pjsua_conf_connect( 0, ci.conf_slot );
    }
}

static void error_exit( const char *title, pj_status_t status ) {
    pjsua_perror( THIS_FILE, title, status );
    pjsua_destroy();
    exit( 1 );
}

这是我程序的输出:

19:11:53.627 os_core_unix.c !pjlib 2.4.5-svn for POSIX initialized
19:11:53.631 sip_endpoint.c  .Creating endpoint instance...
19:11:53.632          pjlib  .select() I/O Queue created (0x1ca0f30)
19:11:53.632 sip_endpoint.c  .Module "mod-msg-print" registered
19:11:53.633 sip_transport.  .Transport manager created.
19:11:53.633   pjsua_core.c  .PJSUA state changed: NULL --> CREATED
19:11:53.633 sip_endpoint.c  .Module "mod-pjsua-log" registered
19:11:53.633 sip_endpoint.c  .Module "mod-tsx-layer" registered
19:11:53.633 sip_endpoint.c  .Module "mod-stateful-util" registered
19:11:53.633 sip_endpoint.c  .Module "mod-ua" registered
19:11:53.633 sip_endpoint.c  .Module "mod-100rel" registered
19:11:53.634 sip_endpoint.c  .Module "mod-pjsua" registered
19:11:53.634 sip_endpoint.c  .Module "mod-invite" registered
19:11:53.803     alsa_dev.c  ..ALSA driver found 11 devices
19:11:53.804     alsa_dev.c  ..ALSA initialized
19:11:53.805          pjlib  ..select() I/O Queue created (0x1ccb8ac)
19:11:53.837 sip_endpoint.c  .Module "mod-evsub" registered
19:11:53.838 sip_endpoint.c  .Module "mod-presence" registered
19:11:53.838 sip_endpoint.c  .Module "mod-mwi" registered
19:11:53.839 sip_endpoint.c  .Module "mod-refer" registered
19:11:53.839 sip_endpoint.c  .Module "mod-pjsua-pres" registered
19:11:53.839 sip_endpoint.c  .Module "mod-pjsua-im" registered
19:11:53.840 sip_endpoint.c  .Module "mod-pjsua-options" registered
19:11:53.840   pjsua_core.c  .1 SIP worker threads created
19:11:53.841   pjsua_core.c  .pjsua version 2.4.5-svn for Linux-4.1.7/armv7l/glibc-2.13 initialized
19:11:53.841   pjsua_core.c  .PJSUA state changed: CREATED --> INIT
19:11:53.842   pjsua_core.c  SIP UDP socket reachable at 192.168.2.83:5060
19:11:53.843   udp0x1cde4c8  SIP UDP transport started, published address is 192.168.2.83:5060
19:11:53.843   pjsua_core.c  PJSUA state changed: INIT --> STARTING
19:11:53.843 sip_endpoint.c  .Module "mod-unsolicited-mwi" registered
19:11:53.844   pjsua_core.c  .PJSUA state changed: STARTING --> RUNNING
19:11:53.844    pjsua_acc.c  Adding account: id=sip:demo-user2@192.168.2.59
19:11:53.845    pjsua_acc.c  .Account sip:demo-user2@192.168.2.59 added with id 0
19:11:53.845    pjsua_acc.c  .Acc 0: setting registration..
19:11:53.846   pjsua_core.c  ...TX 499 bytes Request msg REGISTER/cseq=2433 (tdta0x1ce2858) to UDP 192.168.2.59:5060:
REGISTER sip:192.168.2.59 SIP/2.0
Via: SIP/2.0/UDP 192.168.2.83:5060;rport;branch=z9hG4bKPjkPDfnXzyPfl.tr1YUGuqWnb0xXPaMNGc
Max-Forwards: 70
From: <sip:demo-user2@192.168.2.59>;tag=z51e618QFYLeBsmdY9nVhzIvmajoODP-
To: <sip:demo-user2@192.168.2.59>
Call-ID: VViAieGUFSZ6qg9pOOuU2xaarZkBACiy
CSeq: 2433 REGISTER
Contact: <sip:demo-user2@192.168.2.83:5060;ob>
Expires: 300
Allow: PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, INFO, SUBSCRIBE, NOTIFY, REFER, MESSAGE, OPTIONS
Content-Length:  0


--end msg--
19:11:53.847    pjsua_acc.c  ..Acc 0: Registration sent
Press 'h' to hangup all calls, 'q' to quit
19:11:53.851   pjsua_core.c  .RX 578 bytes Response msg 401/REGISTER/cseq=2433 (rdata0x1cdfafc) from UDP 192.168.2.59:5060:
SIP/2.0 401 Unauthorized
Via: SIP/2.0/UDP 192.168.2.83:5060;branch=z9hG4bKPjkPDfnXzyPfl.tr1YUGuqWnb0xXPaMNGc;received=192.168.2.83;rport=5060
From: <sip:demo-user2@192.168.2.59>;tag=z51e618QFYLeBsmdY9nVhzIvmajoODP-
To: <sip:demo-user2@192.168.2.59>;tag=as19db99ad
Call-ID: VViAieGUFSZ6qg9pOOuU2xaarZkBACiy
CSeq: 2433 REGISTER
Server: Asterisk PBX 13.6.0
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY, INFO, PUBLISH, MESSAGE
Supported: replaces, timer
WWW-Authenticate: Digest algorithm=MD5, realm="asterisk", nonce="5b64ff92"
Content-Length: 0


--end msg--
19:11:53.851 sip_auth_clien  ...Unable to set auth for tdta0x1ce2858: can not find credential for asterisk/Digest
19:11:53.851    pjsua_acc.c  ....SIP registration error: No suitable credential (PJSIP_ENOCREDENTIAL) [status=171101]

相关文章:

  • 暂无相关问题
暂无标签

1 个回答

8

来自 PJSIP的常见问题解答

我无法登录/注册到我的服务器。它提示有认证错误。

这很可能是因为配置中的凭证(用户名和密码)不正确。解决方法取决于PJSIP报告的错误信息。

对于 PJSIP_ENOCREDENTIAL 错误:

这个错误是因为你在凭证中指定的“领域”(realm)和服务器在401/407响应中挑战的领域不匹配。如果你使用的是PJSIP版本0.7-trunk或0.7.1及以上版本,你可以把领域设置为通配符("*"),这样PJSIP就会对服务器挑战的任何领域做出响应。如果你使用的是旧版本的PJSIP,你需要确保凭证中的领域和挑战中的领域一致。通常情况下,领域会等于域名,但不一定是这样。例如,Asterisk总是把领域设置为“asterisk”。

更新

realmscheme 设置为以下内容

    cfg.cred_info[0].realm = pj_str((char *)"*");
    cfg.cred_info[0].scheme = pj_str((char *)"digest");

撰写回答