zoukankan      html  css  js  c++  java
  • SIP UA/UAC/UAS/GB28181-Server/GB28181-Client 五合一

    感谢网友larkguo整理的sip ua示例,完善,对味 !小改一下就能实现/uac/uas/gb28181-server/gb28181-client

    https://github.com/larkguo/SIP_UA/blob/master/ua.c

    1. 功能改造

    1. 启动参数太长,可以把参数放到配置文件

    gb28181.client.ini

    ; Test config file for ini_example.c and INIReaderTest.cpp
    
    [UA]
    ;SIP
    role        = UAC
    server_id   = 34020000002000000001
    server_ip   = 172.16.23.89
    server_port = 5060
    user_id     = 34020000001320000111
    user_ch     = 34020000001320000111
    passwd      = 12345678
    user_port   = 5060
    expiry      = 3600
    heartbeat   = 60
    transport   = UDP

    gb28181.server.ini

    ; Test config file for ini_example.c and INIReaderTest.cpp
    
    [UA]
    ;;;;;;;;;;;;;;;;;; Local Platform ;;;;;;;;;;;;;;;;;;;;
    ;SIP
    role        = UAS
    server_id   = 34020000002000000001
    passwd      = 12345678
    server_port = 5060
    transport   = UDP
    
    ;RTP
    rtp_port_fix = close
    rtp_port_fix_port = 6000
    rtp_port_start = 15000
    rtp_port_end = 15100
    
    ;RESTFUL
    restful_port = 10000
    
    ;RTMP
    rtmp_port = 1935;
    http_flv_port = 8081;
    
    ;;;;;;;;;;;;;;;;;; Upper Level Platform ;;;;;;;;;;;;;;;;
    upper_level_platform = close
    upper_server_id   = 34020000002000000002
    upper_server_ip   = 172.16.23.125
    upper_passwd      = 12345678
    upper_server_port = 5060
    upper_expiry      = 3600
    upper_heartbeat   = 30
    upper_transport   = UDP

    2. larkguo 的ua示例是个SIP网络代理终端(sip user agent),代理终端一般应用在背靠背的网络的环境(ua1~proxy~ua2)。

    因为网络代理既包含了服务端,又包含了客户端,所以只需要屏蔽一行代码(去掉代理模式),就能改造成CS环境(uac~uas)的应用。

    //eXosip_set_user_agent(g_core.context, UA_VERSION);

    简单的gb28181系统也可以是CS结构,如果需要级联,国标服务器需要配置成SIP代理模式。

    为了省事,我的语音对讲,国标客户端,国标服务器全部配成同样的代理模式,一个程序解决三个功能。

    而且通过这个SIP代理小程序很容易配置成1个服务器+n个客户端的服务单元

    然后将n个服务单元级联或者互联(树状或者网状拓扑)可以组成大规模国标监控系统

    3. 加一个参数role来区分ua/uac/uas/gb28181-client/gb28181-server

    ua.c

    /*
    SIP User Agent Sample -- by larkguo@gmail.com
    
    Intercom/GB28181-Server/GB28181-Client Agent Sample -- by zhoudd
    
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    
    1.Architecture:
        UA ==command==> eXosip2
        UA <==notify==  eXosip2
    
    2.Requires:
        libosip2-5.0.0
        libeXosip2-5.0.0
    
    3.Compile:(assumed that osip2 & eXosip2 are installed in /usr/local)
        gcc -I/usr/local/include -L/usr/local/lib ua.c -o ua -leXosip2 
        -losip2 -losipparser2 -lpthread
    
    4.Run:
        export LD_LIBRARY_PATH+=/usr/local/lib:
        ./ua -r sip:DOMAIN-OR-IP -R sip:X.X.X.X:5060 -f sip:FROM-USER@DOMAIN 
        -t sip:TO-USER@DOMAIN -U AUTH-USER -P AUTH-PASSWORD
    
    5.Register:
        UAC/UAS        PROXY
        1  -REGISTER->
            <-401-
            -REGISTER(auth)->
            <-200-
    
    6.Call:
        UAC  (PROXY)    UAS
        2  -INVITE->
            <-407-
            -INVITE(auth)->
            <-180-
            <-200-        3
            -ACK->
        4  -reINVITE->
            <-200-
            -ACK->
        5  -BYE->
            <-200-
    */
    
    #include <stdio.h>
    #include <stdbool.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <errno.h>
    #include <string.h>
    #include <signal.h>
    #include <pthread.h>
    #include <time.h>
    #include <sys/time.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <netdb.h>
    #include <ifaddrs.h>
    #include <osip2/osip_mt.h>
    #include <eXosip2/eXosip.h>
    #include "HTTPDigest.h"
    #include "ini.h"
    #include "util.h"
    
    #define    UA_CMD_REGISTER        ('1')
    #define    UA_CMD_CALL_START    ('2')
    #define    UA_CMD_CALL_ANSWER    ('3')
    #define    UA_CMD_CALL_KEEP    ('4')
    #define    UA_CMD_CALL_STOP    ('5')
    #define    UA_CMD_UNREGISTER    ('6')
    #define    UA_CMD_HELP            ('h')
    #define    UA_CMD_QUIT            ('q')
    
    #ifdef UAS_DISABLE_LOG
        #define uaslog(msg, ...) (void)0
    #else
        #define uaslog(msg, ...) printf("[%s] ", get_time());printf(msg, ##__VA_ARGS__);printf("
    ")
    #endif
    
    #ifdef UA_DISABLE_LOG
        #define ualog(a,b...) (void)0
    #else
        #define ualog(a,b...) fprintf(stderr,b);fprintf(stderr,"
    >")
    #endif
    
    #define null_if_empty(s) (((s)!=NULL&&(s)[0]!='')?(s):NULL)
    #define UA_VERSION "SipUAv0.1"
    #define UAS_VERSION "SipUASv0.1"
    #define    BUFFER_LEN (1024)
    #define DEVICE_DESCRIPTOR_LEN 64
    
    #define THREAD_GROUP     (4)
    
    /*rtp send/recv thread group*/
    enum{SEND, RECV, SOURCE, DESTROY};
    
    typedef struct
    {
        const char *role;
        const char *server_id;
        const char *user_id;
        const char* passwd;
        const char *server_ip;
        int server_port;
        const char *user_ip;
        int user_port;   
        const char* transport;    
        const char* rtp_port_fix;
        int rtp_port_fix_port;
        int rtp_port_start;
        int rtp_port_end;
        int heartbeat;
        int expiry;
    } config_ua_t;
    
    /*task bridge*/
    typedef struct task
    {  
        /*user*/ 
    }task_t;
    
    typedef struct ua_core{
        /* config */
        int expiry;
        int localport;
        int calltimeout;
        char *proxy;
        char *outboundproxy;
        char *username;
        char *password;
        char *realm;
        char *nonce;
        char *from;
        char *to;
        char *contact;
        char *localip;
        char *firewallip;
        char *transport;
        char *role;
        /* dynamic */
        struct eXosip_t *context;
        pthread_t ua_notifythread;
        int running;
        int regid;
        int callid;
        int dialogid;
        int transactionid;
        int cmd;
        /*media channel task*/  
        config_ua_t *config_ua;
        //task_t **task;
        uint32_t rtp_port;
        uint32_t media_index;
        int media_proto;
        int media_req_mode;
        pthread_mutex_t lock;
    } uacore;
    
    static uacore g_core;
    
    /*UA Functions*/
    static void ua_cmd_usage(void);
    static int ua_add_outboundproxy(osip_message_t *msg, const char *outboundproxy);
    static int ua_cmd_register(uacore *core);
    static int ua_cmd_unregister(uacore *core);
    static int ua_cmd_callstart(uacore *core, char *sdp);
    static int ua_cmd_callring(uacore *core);
    static int ua_cmd_callanswer(uacore *core, char *sdp);
    static int ua_cmd_callkeep(uacore *core);
    static int ua_cmd_callstop(uacore *core);
    static int ua_notify_callack(uacore *core, eXosip_event_t *je);
    static int ua_notify_callkeep(uacore *core, eXosip_event_t *je);
    static int ua_notify_keepalive(uacore *core, eXosip_event_t *je);
    static void *ua_notify_thread(void *arg);
    static int ua_printf_msg(eXosip_event_t* je, int ch);
    /*GB28181 UAS Functions*/
    static void uas_cmd_usage(void);
    static void ua_register401_unauthorized_response(uacore *core, eXosip_event_t *je);
    static void ua_auth_calc_response(uacore *core, char *username, char *uri, char *method, HASHHEX response);
    static void ua_register_success_response(uacore *core, eXosip_event_t *je);
    static void ua_register_failed_response(uacore *core, eXosip_event_t *je);
    /*GB28181 UAC Functions*/
    static int ua_device_info_response(char* SN, char* DeviceID, char* rsp_xml_body);
    static int ua_device_boot_response(char* SN, char* DeviceID, char* rsp_xml_body);
    static int ua_device_status_response(char* SN, char* DeviceID, char* rsp_xml_body);
    static int ua_catalog_response(char* SN, char* DeviceID, char* rsp_xml_body);
    static int get_str( const char* data, const char* s_mark, bool with_s_make, const char* e_mark, bool with_e_make, char* dest );
    /*Util Functions*/
    static void usage(void);
    static int init(uacore *core);
    static void stop(int signum);
    static int quit(uacore *core);
    
    static void
    usage(void){
    #define short_options "r:f:t:k:U:P:X:Y:T:b:e:p:c:l:F:R:hv"
        printf("Usage: " UA_VERSION " [required] [optional]
    "
            "
    	[required]
    "
            "	-r --proxy	sip:proxyhost[:port]
    "
            "	-f --fromuser	sip:fromuser@host[:port]
    "
            "
    	[optional]
    "
            "	-t --touser	sip:touser@host[:port]
    "
            "	-U --username	authentication username
    "
            "	-P --password	authentication password
    "
            "	-X --realm	authentication realm
    "
            "	-Y --nonce	authentication nonce
    "
            "	-T --transport	UDP|TCP|TLS|DTLS(default UDP)
    "
            "	-b --role	UA|UAS|UAC(default UA)
    "
            "	-e --expiry	number(default 3600)
    "
            "	-p --port	number(default 5060)
    "
            "	-c --contact	sip:user@host[:port]
    "
            "	-l --localip	X.X.X.X(force local IP address)
    "
            "	-k --keep	call keep timeout(default 1800)
    "
            "	-F --firewallip	X.X.X.X
    "
            "	-R --route	outboundproxy or SBC or P-CSCF(sip:outboundproxyhost[:port])
    "
            "
    	[help]
    "
            "	-v --version
    "
            "	-h --help
    "
            "
    	[uas example]
    "
            "	ua -r sip:192.168.1.X:5060 -f sip:1001@domain.com"
            " -U 1001 -P 1001 -p 5080
    "
            "
    	[uac example]
    "
            "	ua -r sip:domain.com -R sip:192.168.1.X:5060 -f sip:1002@domain.com"
            " -t sip:1001@domain.com -U 1002 -P 1002
    "
            "
    	[ims uac example]
    "
            "	ua -r sip:domain.com -R sip:192.168.1.X:5060 -f sip:1002@domain.com"
            " -t sip:1001@domain.com -U 1001@domain.com -P 1002
    
    "
            );
    }
    
    static void
    ua_cmd_usage(void){
        printf("please select:
    "
            "	1: register
    "
            "	2: call start
    "
            "	3: call answer
    "
            "	4: call keep
    "
            "	5: call stop
    "
            "	6: unregister
    "
            "	h: help
    "
            "	q: quit
    ");
    }
    
    static void
    uas_cmd_usage(void){
        printf("please select:
    "
            "	2: call start
    "
            "	5: call stop
    "
            "	h: help
    "
            "	q: quit
    ");
    }
    
    static int 
    init(uacore *core){
        core->proxy = (char*)calloc(1, sizeof(char)*DEVICE_DESCRIPTOR_LEN);
        core->from = (char*)calloc(1, sizeof(char)*DEVICE_DESCRIPTOR_LEN);
        core->to = (char*)calloc(1, sizeof(char)*DEVICE_DESCRIPTOR_LEN);
        core->contact = (char*)calloc(1, sizeof(char)*DEVICE_DESCRIPTOR_LEN);
        core->localip = (char*)calloc(1, sizeof(char)*DEVICE_DESCRIPTOR_LEN);
        core->username = (char*)calloc(1, sizeof(char)*DEVICE_DESCRIPTOR_LEN);
        core->password = (char*)calloc(1, sizeof(char)*DEVICE_DESCRIPTOR_LEN);
        core->realm = (char*)calloc(1, sizeof(char)*DEVICE_DESCRIPTOR_LEN);
        core->nonce = (char*)calloc(1, sizeof(char)*DEVICE_DESCRIPTOR_LEN);
        core->outboundproxy = (char*)calloc(1, sizeof(char)*DEVICE_DESCRIPTOR_LEN);
        core->firewallip = (char*)calloc(1, sizeof(char)*DEVICE_DESCRIPTOR_LEN);
        core->transport = (char*)calloc(1, sizeof(char)*DEVICE_DESCRIPTOR_LEN);
        core->role = (char*)calloc(1, sizeof(char)*DEVICE_DESCRIPTOR_LEN);
        core->config_ua = (config_ua_t*)calloc(1, sizeof(config_ua_t));    
        //core->task = (task_t**)calloc(1, sizeof(task_t*));
        pthread_mutex_init(&(core->lock), NULL);
        return 0;
    }
    
    static int 
    quit(uacore *core){
        if (NULL != core->proxy) free(core->proxy);
        if (NULL != core->from) free(core->from);
        if (NULL != core->to) free(core->to);
        if (NULL != core->contact) free(core->contact);
        if (NULL != core->localip) free(core->localip);
        if (NULL != core->username) free(core->username);
        if (NULL != core->password) free(core->password);
        if (NULL != core->realm) free(core->realm);
        if (NULL != core->nonce) free(core->nonce);
        if (NULL != core->outboundproxy) free(core->outboundproxy);
        if (NULL != core->firewallip) free(core->firewallip);
        if (NULL != core->transport) free(core->transport);
        if (NULL != core->role) free(core->role);
        if (NULL != core->config_ua) free(core->config_ua);
        //if (NULL != core->task) free(core->task);
        pthread_mutex_destroy(&(core->lock));
    
        return 0;
    }
    
    static void
    stop(int signum){
        g_core.running = 0;
    }
    
    #define REQUEST 1
    #define RESPONSE 0
    static int 
    ua_printf_msg(eXosip_event_t* je, int ch)
    {
        char *dest=NULL;
        size_t length=0;
        int i=0;
        if (ch == 1)
            i = osip_message_to_str(je->request, &dest, &length);
        else if(ch == 0)
            i = osip_message_to_str(je->response, &dest, &length);
        if (i!=0)
        { 
            return -1; 
        }
        printf("%s
    ", dest);
    
        osip_free(dest);
        return 0;
    }
    
    /*decode system config file*/
    static int config_ua_handler(void* user, const char* section, const char* name,
                       const char* value)
    {
        config_ua_t* pconfig = (config_ua_t*)user;
    
        #define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
        if (MATCH("UA", "role")) {
            pconfig->role = strdup(value);
        } else if (MATCH("UA", "server_id")) {
            pconfig->server_id = strdup(value);
        } else if (MATCH("UA", "user_id")) {
            pconfig->user_id = strdup(value);
        } else if (MATCH("UA", "passwd")) {
            pconfig->passwd = strdup(value);
        } else if (MATCH("UA", "server_ip")) {
            pconfig->server_ip = strdup(value);
        } else if (MATCH("UA", "server_port")) {
            pconfig->server_port = atoi(value);
        } else if (MATCH("UA", "user_ip")) {
            pconfig->user_ip = strdup(value);
        } else if (MATCH("UA", "user_port")) {
            pconfig->user_port = atoi(value);
        } else if (MATCH("UA", "transport")) {
            pconfig->transport = strdup(value);
        }else if (MATCH("UA", "rtp_port_fix")) {
            pconfig->rtp_port_fix = strdup(value);
        } else if (MATCH("UA", "rtp_port_fix_port")) {
            pconfig->rtp_port_fix_port = atoi(value);
        } else if (MATCH("UA", "rtp_port_start")) {
            pconfig->rtp_port_start = atoi(value);
        } else if (MATCH("UA", "rtp_port_end")) {
            pconfig->rtp_port_end = atoi(value);
        } else if (MATCH("UA", "heartbeat")) {
            pconfig->heartbeat = atoi(value);
        } else if (MATCH("UA", "expiry")) {
            pconfig->expiry = atoi(value);
        } else {
            return 0;  /* unknown section/name, error */
        }
        return 1;
    }
    
    /***************************** command *****************************/
    static int
    ua_add_outboundproxy(osip_message_t *msg, const char *outboundproxy)
    {
        int ret = 0;
        char head[BUFFER_LEN] = { 0 };
    
        if (NULL == null_if_empty(outboundproxy)){
            return 0;
        }
        snprintf(head, sizeof(head)-1, "<%s;lr>", outboundproxy);
    
        osip_list_special_free(&msg->routes, (void(*)(void*))osip_route_free);
        ret = osip_message_set_route(msg, head);
        return ret;
    }
    
    static int
    ua_cmd_register(uacore *core)
    {
        int ret = -1;
        osip_message_t *msg = NULL;
    
        if (core->regid > 0){ // refresh register
            ret = eXosip_register_build_register(core->context, core->regid, core->expiry, &msg);
            if (0 != ret){
                ualog(LOG_ERR, "register %d refresh build failed %d", core->regid, ret);
                return -1;
            }
        }
        else{ // new register
            core->regid = eXosip_register_build_initial_register(core->context,
                core->from, core->proxy, core->contact, core->expiry, &msg);
            if (core->regid <= 0){
                ualog(LOG_ERR, "register build failed %d", core->regid);
                return -1;
            }
            ua_add_outboundproxy(msg, core->outboundproxy);
        }
        ret = eXosip_register_send_register(core->context, core->regid, msg);
        if (0 != ret){
            ualog(LOG_ERR, "register %d send failed", core->regid);
            return ret;
        }
        return ret;
    }
    
    static int
    ua_cmd_unregister(uacore *core)
    {
        int ret = -1;
        osip_message_t *msg = NULL;
        int expiry = 0; //unregister 
    
        ret = eXosip_register_build_register(core->context, core->regid, expiry, &msg);
        if (0 != ret){
            ualog(LOG_ERR, "unregister %d build failed %d", core->regid, ret);
            return -1;
        }
    
        ret = eXosip_register_send_register(core->context, core->regid, msg);
        if (0 != ret){
            ualog(LOG_ERR, "register %d send failed %d", core->regid, ret);
            return ret;
        }
        core->regid = 0;
        return ret;
    }
    
    static int
    ua_cmd_callstart(uacore *core, char *sdp)
    {
        int ret = -1;
        char session_exp[BUFFER_LEN] = { 0 };
        osip_message_t *msg = NULL;
    
        ret = eXosip_call_build_initial_invite(core->context, &msg, core->to, core->from, NULL, NULL);
        if (0 != ret){
            ualog(LOG_ERR, "call build failed %s %s", core->from, core->to);
            return -1;
        }
        ua_add_outboundproxy(msg, core->outboundproxy);
        osip_message_set_body(msg, sdp, strlen(sdp));
        osip_message_set_content_type(msg, "application/sdp");
    
        /* UAC call timeout */
        snprintf(session_exp, sizeof(session_exp)-1, "%i;refresher=uac", core->calltimeout);
        osip_message_set_header(msg, "Session-Expires", session_exp);
        osip_message_set_supported(msg, "timer");
    
        core->callid = eXosip_call_send_initial_invite(core->context, msg);
        ret = (core->callid > 0) ? 0 : -1;
        return ret;
    }
    
    static int
    ua_cmd_callring(uacore *core)
    {
        int ret = 0;
        int code = 180;
        osip_message_t *msg = NULL;
    
        ret = eXosip_call_build_answer(core->context, core->transactionid, code, &msg);
        if (0 != ret){
            ualog(LOG_ERR, "call %d build ring failed", core->callid);
            return ret;
        }
    
        ret = eXosip_call_send_answer(core->context, core->transactionid, code, msg);
        if (0 != ret){
            ualog(LOG_ERR, "call %d send ring failed", core->callid);
            return ret;
        }
        return ret;
    }
    
    static int
    ua_cmd_callanswer(uacore *core, char *sdp)
    {
        int ret = 0;
        int code = 200;
        osip_message_t *msg = NULL;
    
        ret = eXosip_call_build_answer(core->context, core->transactionid, code, &msg);
        if (0 != ret){
            ualog(LOG_ERR, "call %d build answer failed", core->callid);
            return ret;
        }
    
        /* UAS call timeout */
        osip_message_set_supported(msg, "timer");
        osip_message_set_body(msg, sdp, strlen(sdp));
        osip_message_set_content_type(msg, "application/sdp");
    
        ret = eXosip_call_send_answer(core->context, core->transactionid, code, msg);
        if (0 != ret){
            ualog(LOG_ERR, "call %d send answer failed", core->callid);
            return ret;
        }
        return ret;
    }
    
    static int
    ua_cmd_callkeep(uacore *core)
    {
        int ret = -1;
        char session_exp[BUFFER_LEN] = { 0 };
        osip_message_t *msg = NULL;
    
        ret = eXosip_call_build_request(core->context, core->dialogid, "INVITE", &msg);
        if (NULL == msg){
            ualog(LOG_ERR, "call %d build keep failed", core->callid);
            return ret;
        }
    
        ret = eXosip_call_send_request(core->context, core->dialogid, msg);
        if (0 != ret){
            ualog(LOG_ERR, "call %d send keep failed", core->callid);
            return ret;
        }
        return ret;
    }
    
    static int
    ua_cmd_callstop(uacore *core)
    {
        int ret = 0;
        ret = eXosip_call_terminate(core->context, core->callid, core->dialogid);
        if (0 != ret){
            ualog(LOG_ERR, "call %d send stop failed", core->callid);
            return ret;
        }
        return ret;
    }
    
    /*****************************ua notify *****************************/
    static int
    ua_notify_callack(uacore *core, eXosip_event_t *je)
    {
        int ret = 0;
        osip_message_t *msg = NULL;
    
        ret = eXosip_call_build_ack(core->context, je->did, &msg);
        if (0 != ret){
            ualog(LOG_ERR, "call %d build ack failed", je->cid);
            return ret;
        }
        ua_add_outboundproxy(msg, core->outboundproxy);
    
        ret = eXosip_call_send_ack(core->context, je->did, msg);
        if (0 != ret){
            ualog(LOG_ERR, "call %d send ack failed", je->cid);
            return ret;
        }
        return ret;
    }
    
    static int
    ua_notify_callkeep(uacore *core, eXosip_event_t *je)
    {
        int ret = 0;
        int code = 200;
        osip_message_t *msg = NULL;
        eXosip_call_build_answer(core->context, je->tid, code, &msg);
        if (NULL == msg){
            ualog(LOG_ERR, "call %d send keep answer failed", je->cid);
        }
        ret = eXosip_call_send_answer(core->context, je->tid, code, msg);
        if (0 != ret){
            ualog(LOG_ERR, "call %d send keep answer failed", je->cid);
            return ret;
        }
        return ret;
    }
    
    static int
    ua_notify_keepalive(uacore *core, eXosip_event_t *je)
    {
        osip_message_t* heart_msg = NULL;
        static long int heart_tick = 0;
        heart_tick++;
        char tmp[4096];
        memset(tmp, 0, sizeof(tmp));
        snprintf(tmp, 4096, 
            "<?xml version="1.0" encoding="UTF-8"?>
    "
            "<Notify>
    "
            "<CmdType>Keepalive</CmdType>
    "
            "<SN>%ld</SN>
    "
            "<DeviceID>%s</DeviceID>
    "
            "<Status>OK</Status>
    "
            "</Notify>
    ",heart_tick, g_core.config_ua->user_id);
        eXosip_message_build_request(core->context, &heart_msg, "MESSAGE", core->proxy, core->from, NULL);    
        osip_message_set_body(heart_msg, tmp, strlen(tmp));
        osip_message_set_content_type(heart_msg, "Application/MANSCDP+xml");
        eXosip_message_send_request(core->context, heart_msg);
        return 0;
    }
    
    static int
    ua_notidy_callid(uacore *core, eXosip_event_t *je)
    {
        core->callid = je->cid;
        core->dialogid = je->did;
        core->transactionid = je->tid;
        return 0;
    }
    
    /*****************************ua response *****************************/
    static int 
    get_str( const char* data, const char* s_mark, bool with_s_make, const char* e_mark, bool with_e_make, char* dest )
    {
        const char* satrt = strstr( data, s_mark );
        if( satrt != NULL )
        {
            const char* end = strstr( satrt, e_mark );
            if( end != NULL ){
                int s_pos = with_s_make ? 0 : strlen(s_mark);
                int e_pos = with_e_make ? strlen(e_mark) : 0;
                strncpy( dest, satrt+s_pos, (end+e_pos) - (satrt+s_pos) );
            }
            return 0;
        }
        return -1;
    }
    
    static void 
    ua_register401_unauthorized_response(uacore *core, eXosip_event_t *je)
    {
        int ret = 0;
        osip_message_t * reg = NULL;
    
        osip_www_authenticate_t * header = NULL;
        osip_www_authenticate_init(&header);
    
        osip_www_authenticate_set_auth_type (header,osip_strdup("Digest"));
        osip_www_authenticate_set_realm(header,osip_enquote(core->realm));
        osip_www_authenticate_set_nonce(header,osip_enquote(core->nonce));
    
        char *dest = NULL;
        osip_www_authenticate_to_str(header,&dest);
    
        ret = eXosip_message_build_answer (core->context,je->tid,401,&reg);
        if ( ret == 0 && reg != NULL )
        {
            osip_message_set_www_authenticate(reg,dest);
            osip_message_set_content_type(reg,"Application/MANSCDP+xml");
            eXosip_lock(core->context);
            eXosip_message_send_answer (core->context,je->tid,401,reg);
            eXosip_unlock(core->context);
        }
    
        osip_www_authenticate_free(header);
        osip_free(dest);
    }
    
    static void 
    ua_auth_calc_response(uacore *core, char *username, char *uri, char *method, HASHHEX response)
    {
        HASHHEX HA1;
        DigestCalcHA1("REGISTER",username,core->realm,core->password,core->nonce,NULL,HA1);
        HASHHEX rresponse;
        DigestCalcResponse(HA1,core->nonce,NULL,NULL,NULL,0,method,uri,NULL,rresponse);
        memcpy(response,rresponse,HASHHEXLEN);
    }
    
    static void 
    ua_register_success_response(uacore *core, eXosip_event_t *je)
    {
        int ret = 0 ;
        osip_message_t * reg = NULL;
        ret = eXosip_message_build_answer (core->context,je->tid,200,&reg);
        if ( ret == 0 && reg != NULL )
        {
            eXosip_lock(core->context);
            eXosip_message_send_answer (core->context,je->tid,200,reg);
            eXosip_unlock(core->context);
        }
    }
    
    static void 
    ua_register_failed_response(uacore *core, eXosip_event_t *je)
    {
        int ret = 0 ;
        osip_message_t * reg = NULL;
        ret = eXosip_message_build_answer (core->context,je->tid,401,&reg);
        if ( ret == 0 && reg != NULL )
        {
            eXosip_lock(core->context);
            eXosip_message_send_answer (core->context,je->tid,401,reg);
            eXosip_unlock(core->context);
        }
    }
    
    static int ua_device_info_response(char* SN, char* DeviceID, char* rsp_xml_body)
    {
        snprintf(rsp_xml_body, 4096, "<?xml version="1.0"?>
    "
            "<Response>
    "
            "<CmdType>DeviceInfo</CmdType>
    "
            "<SN>%s</SN>
    "
            "<DeviceID>%s</DeviceID>
    "
            "<Result>OK</Result>
    "
            "<DeviceType>simulate client</DeviceType>
    "
            "<Manufacturer>ZHD</Manufacturer>
    "
            "<Model>28181</Model>
    "
            "<Firmware>fireware</Firmware>
    "
            "<MaxCamera>1</MaxCamera>
    "
            "<MaxAlarm>0</MaxAlarm>
    "
            "</Response>
    ",
            SN, DeviceID);
            return 0;
    }
    
    static int ua_device_boot_response(char* SN, char* DeviceID, char* rsp_xml_body)
    {    
        snprintf(rsp_xml_body, 4096, "<?xml version="1.0"?>
    "
            "<Response>
    "
            "<CmdType>DeviceStatus</CmdType>
    "
            "<SN>%s</SN>
    "
            "<DeviceID>%s</DeviceID>
    "
            "<Result>OK</Result>
    "
            "</Response>
    ",
            SN, DeviceID);
            return 0;
    }
    
    static int ua_device_status_response(char* SN, char* DeviceID, char* rsp_xml_body)
    {
        time_t rawtime;
        struct tm* timeinfo;
        time(&rawtime);
        timeinfo = localtime(&rawtime);
        char curtime[72] = {0};
        sprintf(curtime, "%d-%d-%dT%02d:%02d:%02d", (timeinfo->tm_year + 1900), (timeinfo->tm_mon + 1), 
                            timeinfo->tm_mday, timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);
        snprintf(rsp_xml_body, 4096, "<?xml version="1.0"?>
    "
            "<Response>
    "
            "<CmdType>DeviceStatus</CmdType>
    "
            "<SN>%s</SN>
    "
            "<DeviceID>%s</DeviceID>
    "
            "<Result>OK</Result>
    "
            "<Online>ONLINE</Online>
    "
            "<Status>OK</Status>
    "
            "<DeviceTime>%s</DeviceTime>
    "
            "<Alarmstatus Num="0">
    "
            "</Alarmstatus>
    "    
            "<Encode>ON</Encode>
    "    
            "<Record>OFF</Record>
    "    
            "</Response>
    ",
            SN, DeviceID, curtime);
            return 0;
    }
    
    static int ua_catalog_response(char* SN, char* DeviceID, char* rsp_xml_body)
    {
        snprintf(rsp_xml_body, 4096, "<?xml version="1.0"?>
    "
            "<Response>
    "
            "<CmdType>Catalog</CmdType>
    "
            "<SN>%s</SN>
    "
            "<DeviceID>%s</DeviceID>
    "
            "<SumNum>1</SumNum>
    "
            "<DeviceList Num="1">
    "
            "<Item>
    "
            "<DeviceID>%s</DeviceID>
    "
            "<Name>simulate client</Name>
    "
            "<Manufacturer>ZHD</Manufacturer>
    "
            "<Model>28181</Model>
    "
            "<Owner>Owner</Owner>
    "
            "<CivilCode>CivilCode</CivilCode>
    "
            "<Address>Address</Address>
    "
            "<Parental>0</Parental>
    "
            "<SafetyWay>0</SafetyWay>
    "
            "<RegisterWay>1</RegisterWay>
    "
            "<Secrecy>0</Secrecy>
    "
            "<Status>ON</Status>
    "
            "</Item>
    "
            "</DeviceList>
    "
            "</Response>
    ",
            SN, DeviceID, DeviceID);
            return 0;
    }
    
    /* event ua_notify loop */
    static void *
    ua_notify_thread(void *arg)
    {
        uacore *core = (uacore *)arg;
        int ret = 0;
        int code = -1;
    
        while (core->running){
    
            osip_message_t *msg = NULL;
            eXosip_event_t *je = eXosip_event_wait(core->context, 0, 20);
            
            if (osip_strcasecmp(g_core.role, "UAC") == 0){
                static int counter = 0;
                counter++;
                if (counter % (10*g_core.config_ua->heartbeat) == 0) {
                  struct eXosip_stats stats;
    
                  memset (&stats, 0, sizeof (struct eXosip_stats));
                  eXosip_lock (core->context);
                  eXosip_set_option (core->context, EXOSIP_OPT_GET_STATISTICS, &stats);
                  eXosip_unlock (core->context);
                  uaslog ("eXosip stats: inmemory=(tr:%i//reg:%i) average=(tr:%f//reg:%f)", stats.allocated_transactions, stats.allocated_registrations, stats.average_transactions, stats.average_registrations);
    
                  ua_notify_keepalive(core, je);
                }
            }
            
            if (NULL == je){
                /* auto process,such as:register refresh,auth,call keep... */
                eXosip_automatic_action(core->context);
                osip_usleep(100000);
                continue;
            }
    
            eXosip_automatic_action(core->context);
            switch (je->type){
            case EXOSIP_REGISTRATION_SUCCESS:
                if (UA_CMD_REGISTER == core->cmd){
                    //ua_printf_msg(je, REQUEST);
                    ualog(LOG_INFO, "register %d sucess", je->rid);
                    ua_notify_keepalive(core, je);
                }
                else {
                    //ua_printf_msg(je, REQUEST);
                    ualog(LOG_INFO, "unregister %d sucess", je->rid);
                }
                break;
            case EXOSIP_REGISTRATION_FAILURE:
                if (UA_CMD_REGISTER == core->cmd){
                    //ua_printf_msg(je, REQUEST);
                    ualog(LOG_INFO, "register %d failure", je->rid);
                }
                else{
                    //ua_printf_msg(je, REQUEST);
                    ualog(LOG_INFO, "unregister %d failure", je->rid);
                }
                break;
            case EXOSIP_CALL_INVITE:{
                //ua_printf_msg(je, REQUEST);
                ua_notidy_callid(core, je);
                ua_cmd_callring(core);         
                ualog(LOG_INFO, "call %d incoming,please answer...", je->cid);
    
                #if 1
                sdp_message_t *sdp_msg = eXosip_get_remote_sdp(core->context, je->did);
                if ( !sdp_msg )
                   break;
    
                sdp_connection_t *connection = eXosip_get_video_connection(sdp_msg);
                if ( !connection )
                    break;
                char *remote_ip = connection->c_addr;
    
                sdp_media_t * video_sdp = eXosip_get_video_media(sdp_msg);
                if ( !video_sdp ) 
                  break;
                char* remote_port = video_sdp->m_port;
    
                /*media_type:rtp_over_udp/rtp_over_tcp*/            
                printf("m_media:%s,m_port:%s,m_number_of_port:%s,m_proto:%s
    ", 
                        video_sdp->m_media,video_sdp->m_port,video_sdp->m_number_of_port,video_sdp->m_proto);
    
                /*setup:active/passive*/
                char setup[64];
                for (int i = 0; i < video_sdp->a_attributes.nb_elt; i++)
                {
                    sdp_attribute_t *attr = (sdp_attribute_t*)osip_list_get(&video_sdp->a_attributes, i);
                    printf("%s : %s
    ", attr->a_att_field, attr->a_att_value);
                    if(strcmp(attr->a_att_field,"setup")==0) strcpy(setup, attr->a_att_value);
                }
                 
                char tmp[4096];
    
                if(strcmp(video_sdp->m_proto, "RTP/AVP") == 0){
                    snprintf (tmp, 4096,
                              "v=0
    "
                              "o=%s 0 0 IN IP4 %s
    "
                              "s=Play
    "
                              "c=IN IP4 %s
    "
                              "t=0 0
    "
                              "m=video %s RTP/AVP 96 98 97
    "
                              "a=recvonly
    "
                              "a=rtpmap:96 PS/90000
    "
                              "a=rtpmap:98 H264/90000
    "
                              "a=rtpmap:97 MPEG4/90000
    "
                              "y=0100000001
    "
                              "f=
    ", g_core.config_ua->user_id, g_core.config_ua->server_ip, get_ip(), remote_port);
                }else if(strcmp(video_sdp->m_proto, "TCP/RTP/AVP") == 0){
                    snprintf (tmp, 4096,
                              "v=0
    "
                              "o=%s 0 0 IN IP4 %s
    "
                              "s=Play
    "
                              "c=IN IP4 %s
    "
                              "t=0 0
    "
                              "m=video %s TCP/RTP/AVP 96 98 97
    "
                              "a=recvonly
    "
                              "a=rtpmap:96 PS/90000
    "
                              "a=rtpmap:98 H264/90000
    "
                              "a=rtpmap:97 MPEG4/90000
    "
                              "a=setup:passive
    "
                              "a=connection:new
    "
                              "y=0100000001
    "
                              "f=
    ", g_core.config_ua->user_id, g_core.config_ua->server_ip, get_ip(), remote_port);
                }else{
                    /*unknow media translate proto type !*/
                }
    
                ua_cmd_callanswer(&g_core, tmp);
    
                #endif
    
                break;
            }
            case EXOSIP_CALL_REINVITE:
                //ua_printf_msg(je, REQUEST);
                ua_notidy_callid(core, je);
                ualog(LOG_INFO, "call %d keep", je->cid);
                ua_notify_callkeep(core, je);
                break;
            case EXOSIP_CALL_RINGING:
                if (je->request){
                    //ua_printf_msg(je, REQUEST);
                    ua_notidy_callid(core, je);         
                    ualog(LOG_INFO, "call %d ring", je->cid);
                }
                else{
                    //ua_printf_msg(je, RESPONSE);
                    uaslog("ringing!
    ");  
                    uaslog("call_id %d,dialog_id %d 
    ",je->cid,je->did);                  
                }
                break;
            case EXOSIP_CALL_PROCEEDING: 
                //ua_printf_msg(je, RESPONSE);
                uaslog("proceeding!
    ");             
                break;  
            case EXOSIP_CALL_ANSWERED:
                if (je->response){
                    //ua_printf_msg(je, RESPONSE);
                    uaslog("connected!
    ");
                    code = osip_message_get_status_code(je->response);                            
                    osip_message_t* ack;
                    eXosip_call_build_ack(core->context,je->did,&ack);  
                    eXosip_call_send_ack(core->context,je->did,ack); 
    
                    
                    sdp_message_t *sdp_msg = eXosip_get_remote_sdp(core->context, je->did);
                    if ( !sdp_msg )
                       break;
    
                    sdp_connection_t *connection = eXosip_get_video_connection(sdp_msg);
                    if ( !connection )
                        break;
                    char *remote_ip = connection->c_addr;
    
                    sdp_media_t * video_sdp = eXosip_get_video_media(sdp_msg);
                    if ( !video_sdp ) 
                      break;
                    char* remote_port = video_sdp->m_port;
    
                    /*media_type:rtp_over_udp/rtp_over_tcp*/            
                    printf("m_media:%s,m_port:%s,m_number_of_port:%s,m_proto:%s
    ", 
                            video_sdp->m_media,video_sdp->m_port,video_sdp->m_number_of_port,video_sdp->m_proto);
    
                    /*setup:active/passive*/
                    char setup[64];
                    for (int i = 0; i < video_sdp->a_attributes.nb_elt; i++)
                    {
                        sdp_attribute_t *attr = (sdp_attribute_t*)osip_list_get(&video_sdp->a_attributes, i);
                        printf("%s : %s
    ", attr->a_att_field, attr->a_att_value);
                        if(strcmp(attr->a_att_field,"setup")==0) strcpy(setup, attr->a_att_value);
                    }
                                                                             
                    #if 0
                    (*(core->task)) = (task_t*)calloc(1, sizeof(task_t));
                    (*(core->task))->remote_ip = (char*)calloc(1, sizeof(char)*64);
                    (*(core->task))->local_ip = (char*)calloc(1, sizeof(char)*64);
                    (*(core->task))->role = (char*)calloc(1, sizeof(char)*64);
                    (*(core->task))->transport = (char*)calloc(1, sizeof(char)*64);
                    (*(core->task))->setup = (char*)calloc(1, sizeof(char)*64);
                    (*(core->task))->buffer = rb_create(DATA_ITEM_NMAX, sizeof(data_t));
                    (*(core->task))->buf = (char*)calloc(1, sizeof(char)*TASK_BUFFER_SIZE);
    
                    strcpy((*(core->task))->remote_ip, remote_ip);
                    (*(core->task))->remote_port = atoi(remote_port);
                    strcpy((*(core->task))->local_ip, get_ip());
                    (*(core->task))->local_port = atoi(remote_port)/*core->rtp_port*/;
                    strcpy((*(core->task))->role, core->role);
                    strcpy((*(core->task))->transport, video_sdp->m_proto);
                    strcpy((*(core->task))->setup, setup);
                    (*(core->task))->media_index = core->media_index;
                    task_gb28181_bridge_creat_run((*(core->task)));
                    
                    (*(core->task))++;
                    core->media_index++;           
                    #endif
    
                    uaslog("created ps stream channel to recv device data (rtp port:%s)", remote_port);
    
                }
                else{
                    //ua_printf_msg(je, REQUEST);
                    ua_notidy_callid(core, je);          
                    ualog(LOG_INFO, "call %d answer %d", je->cid, code);
                    ua_notify_callack(core, je);
                }
                break;
            case EXOSIP_CALL_NOANSWER:
                //ua_printf_msg(je, REQUEST);
                ualog(LOG_INFO, "call %d noanswer", je->cid);
                ua_notidy_callid(core, je);        
                break;
            case EXOSIP_CALL_REQUESTFAILURE:
            case EXOSIP_CALL_GLOBALFAILURE:
            case EXOSIP_CALL_SERVERFAILURE:
                ua_notidy_callid(core, je);
                if (je->response)
                    code = osip_message_get_status_code(je->response);
                ualog(LOG_INFO, "call %d failture %d", je->cid, code);
                break;
            case EXOSIP_CALL_ACK:{
                //ua_printf_msg(je, REQUEST);
                ualog(LOG_INFO, "call %d ack", je->cid);
                ua_notidy_callid(core, je); 
    
                
                sdp_message_t *sdp_msg = eXosip_get_remote_sdp(core->context, je->did);
                if ( !sdp_msg )
                   break;
    
                sdp_connection_t *connection = eXosip_get_video_connection(sdp_msg);
                if ( !connection )
                    break;
                char *remote_ip = connection->c_addr;
    
                sdp_media_t * video_sdp = eXosip_get_video_media(sdp_msg);
                if ( !video_sdp ) 
                  break;
                char* remote_port = video_sdp->m_port;
    
                /*media_type:rtp_over_udp/rtp_over_tcp*/            
                printf("m_media:%s,m_port:%s,m_number_of_port:%s,m_proto:%s
    ", 
                        video_sdp->m_media,video_sdp->m_port,video_sdp->m_number_of_port,video_sdp->m_proto);
    
                /*setup:active/passive*/
                char setup[64];
                for (int i = 0; i < video_sdp->a_attributes.nb_elt; i++)
                {
                    sdp_attribute_t *attr = (sdp_attribute_t*)osip_list_get(&video_sdp->a_attributes, i);
                    printf("%s : %s
    ", attr->a_att_field, attr->a_att_value);
                    if(strcmp(attr->a_att_field,"setup")==0) strcpy(setup, attr->a_att_value);
                }
                                                                         
                #if 0
                (*(core->task)) = (task_t*)calloc(1, sizeof(task_t));
                (*(core->task))->remote_ip = (char*)calloc(1, sizeof(char)*64);
                (*(core->task))->local_ip = (char*)calloc(1, sizeof(char)*64);
                (*(core->task))->role = (char*)calloc(1, sizeof(char)*64);
                (*(core->task))->transport = (char*)calloc(1, sizeof(char)*64);
                (*(core->task))->setup = (char*)calloc(1, sizeof(char)*64);
                (*(core->task))->buffer = rb_create(DATA_ITEM_NMAX, sizeof(data_t));
                (*(core->task))->buf = (char*)calloc(1, sizeof(char)*TASK_BUFFER_SIZE);
    
                strcpy((*(core->task))->remote_ip, remote_ip);
                (*(core->task))->remote_port = atoi(remote_port);
                strcpy((*(core->task))->local_ip, get_ip());
                (*(core->task))->local_port = atoi(remote_port)/*core->rtp_port*/;
                strcpy((*(core->task))->role, core->role);
                strcpy((*(core->task))->transport, video_sdp->m_proto);
                strcpy((*(core->task))->setup, setup);
                (*(core->task))->media_index = core->media_index;
                task_gb28181_bridge_creat_run((*(core->task)));
                
                //(*(core->task))++;
                core->media_index++;            
                #endif
    
                uaslog("push ps stream to server rtp port:%s", remote_port);
          
                break;
            }
            case EXOSIP_CALL_CLOSED:
                if (je->request){
                    //ua_printf_msg(je, REQUEST);
                    ualog(LOG_INFO, "call %d stop", je->cid);
                    //task_gb28181_bridge_release(*(core->task));
                }
                else{
                    //ua_printf_msg(je, RESPONSE);
                    uaslog("other side closed!
    ");     
                }
    
                break;
            case EXOSIP_CALL_CANCELLED:
                //ua_printf_msg(je, REQUEST);
                ualog(LOG_INFO, "call %d cancel", je->cid);
                break;
            case EXOSIP_CALL_RELEASED:
                //ua_printf_msg(je, REQUEST);
                ualog(LOG_INFO, "call %d release", je->cid);
                break;
    
            /*UA eXosip message event*/
            case EXOSIP_MESSAGE_NEW:
                                                        
                if ( MSG_IS_REGISTER(je->request) )
                {
                    //ua_printf_msg(je, RESPONSE);
                    osip_authorization_t * ss_dest = NULL;
                    osip_message_get_authorization(je->request,0,&ss_dest);
                    if ( ss_dest != NULL )
                    {                           
                        char *ss_method = je->request->sip_method;
                        char *ss_algorithm = osip_strdup_without_quote(ss_dest->algorithm);
                        char *ss_username = NULL;
                        if ( ss_dest->username != NULL )
                        {
                            ss_username = osip_strdup_without_quote(ss_dest->username);
                        }
                        char *ss_realm = NULL;
                        if ( ss_dest->realm != NULL )
                        {
                            ss_realm = osip_strdup_without_quote(ss_dest->realm);
                        }
                        char *ss_nonce = NULL;
                        if ( ss_dest->nonce != NULL )
                        {
                            ss_nonce = osip_strdup_without_quote(ss_dest->nonce);
                        }
                        char *ss_nonce_count = NULL;
                        if ( ss_dest->nonce_count != NULL)
                        {
                            ss_nonce_count = osip_strdup_without_quote(ss_dest->nonce_count);
                        }
                        char *ss_uri = NULL;
                        if ( ss_dest->uri != NULL )
                        {
                            ss_uri = osip_strdup_without_quote(ss_dest->uri);
                        }
                        
                        HASHHEX HA1;
                        DigestCalcHA1(ss_algorithm,ss_username,ss_realm,core->password,ss_nonce,
                                      ss_nonce_count, HA1);
    
                        HASHHEX Response;
                        HASHHEX HA2="";
                        DigestCalcResponse(HA1,ss_nonce,ss_nonce_count,ss_dest->cnonce,ss_dest->message_qop,0,
                                           ss_method,ss_uri,HA2,Response);
                        
                        char calc_response[HASHHEXLEN];
                        ua_auth_calc_response(core,ss_username,ss_uri,ss_method,calc_response);
                        
                        if ( memcmp(calc_response,Response,HASHHEXLEN) == 0 )
                        {
                            ua_register_success_response(core,je);
                            uaslog("register_success
    ");
                        }
                        else
                        {
                            ua_register_failed_response(core,je);
                            uaslog("register_failed
    ");
                        }
                                                   
                        osip_free(ss_algorithm);
                        osip_free(ss_username);
                        osip_free(ss_realm);
                        osip_free(ss_nonce);
                        osip_free(ss_nonce_count);
                        osip_free(ss_uri);
                    }
                    else
                    {
                        uaslog("register401_unauthorized
    ");
                        ua_register401_unauthorized_response(core,je);
                    }
                }
                else if(MSG_IS_MESSAGE(je->request))
                {
                    //ua_printf_msg(je, REQUEST);
                    osip_body_t* req_body = NULL;
                    osip_message_get_body(je->request, 0, &req_body);
                    char CmdType[64] = {0}, SN[64] = {0}, DeviceID[64] = {0}, TeleBoot[64] = {0},  rsp_xml_body[4096] = {0};
                    get_str(req_body->body, "<CmdType>", false, "</CmdType>", false, CmdType);
                    get_str(req_body->body, "<SN>", false, "</SN>", false, SN);
                    get_str(req_body->body, "<DeviceID>", false, "</DeviceID>", false, DeviceID);
                    uaslog("SIP Message : CmdType~%s, SN~%s,DeviceID~%s", CmdType, SN, DeviceID);
                    if(strcmp(CmdType, "DeviceInfo") == 0)
                        ua_device_info_response(SN, DeviceID, rsp_xml_body);
                    if (strcmp(CmdType, "Catalog") == 0)
                        ua_catalog_response(SN, DeviceID, rsp_xml_body);
                    if (strcmp(CmdType, "DeviceStatus") == 0)
                        ua_device_status_response(SN, DeviceID, rsp_xml_body);
                    if (strcmp(CmdType, "DeviceControl") == 0)
                    {
                        get_str(req_body->body, "<TeleBoot>", false, "</TeleBoot>", false, TeleBoot);
                        if (strcmp(TeleBoot, "Boot"))
                            ua_device_boot_response(SN, DeviceID, rsp_xml_body);
                    }
                    osip_message_t* rsp_msg = NULL;
                    sprintf (core->from, "%s%s%s%s%s%d", "sip:",g_core.config_ua->user_id,"@",
                                    get_ip(),":",g_core.config_ua->user_port);
                    sprintf (core->to, "%s%s%s%s%s%d", "sip:",g_core.config_ua->server_id,"@"
                                    ,g_core.config_ua->server_ip,":",g_core.config_ua->server_port);
                    eXosip_message_build_request(core->context, &rsp_msg, "MESSAGE", core->to, core->from, NULL);
                    osip_message_set_body(rsp_msg, rsp_xml_body, strlen(rsp_xml_body));
                    osip_message_set_content_type(rsp_msg, "Application/MANSCDP+xml");
                    eXosip_message_send_request(core->context,rsp_msg);    
                }
                break;
    
            case EXOSIP_MESSAGE_ANSWERED:{
                break; 
            }
            case EXOSIP_MESSAGE_REQUESTFAILURE:
                break;
            default:
                ualog(LOG_INFO, "recv unknow msg %d
    ",je->type);
                break;
            }
            eXosip_event_free(je);
        }
        eXosip_quit(core->context);
        osip_free(core->context);
    
        pthread_detach(pthread_self());
        return 0;
    }
    
    /***************************** main *****************************/
    int
    main(int argc, char *argv[])
    {
        int ret = 0;
        struct servent *service = NULL;
        /* init */
        signal(SIGINT, stop);
        memset(&g_core, 0, sizeof(uacore));
        g_core.running = 1;
        g_core.expiry = 3600;
        g_core.localport = 5060;
        g_core.calltimeout = 1800;
        /*0:rtp_over_udp, 1:rtp_over_tcp*/
        g_core.media_proto = 1;
        /*0:passive, 1:active*/
        g_core.media_req_mode = 0;
    
        init(&g_core);
        
        if(strcmp(argv[1],"-c") == 0){
            if (ini_parse(argv[2], config_ua_handler, (g_core.config_ua)) < 0) {
                printf("load 'config file' failed !
    ");
                return -1;
            }
            sprintf (g_core.role, "%s", g_core.config_ua->role);
        }
       
        if (osip_strcasecmp(g_core.role, "UA") == 0){
    
            sprintf (g_core.username, "%s", g_core.config_ua->server_id);
            sprintf (g_core.password, "%s", g_core.config_ua->passwd);
            sprintf (g_core.transport, "%s", g_core.config_ua->transport);
            sprintf (g_core.realm, "%s", "3402000000");
            sprintf (g_core.nonce, "%s", "1234567890123456");
    
            sprintf (g_core.from, "%s%s%s%s%s%d", "sip:",g_core.config_ua->user_id,"@",
                                g_core.config_ua->server_ip,":",g_core.config_ua->server_port);
            sprintf (g_core.proxy, "%s%s%s%d", "sip:",g_core.config_ua->server_ip,":",g_core.config_ua->server_port);
            sprintf (g_core.outboundproxy, "%s%s%s%d", "sip:",g_core.config_ua->server_ip,":",g_core.config_ua->server_port);
            sprintf (g_core.contact, "%s%s%s%s%s%d", "sip:",g_core.config_ua->user_id,"@",
                                g_core.config_ua->server_ip,":",g_core.config_ua->server_port);
            g_core.expiry = g_core.config_ua->expiry;
            g_core.localport = g_core.config_ua->user_port;
    
        }else if (osip_strcasecmp(g_core.role, "UAS") == 0){
    
            sprintf (g_core.username, "%s", g_core.config_ua->server_id);
            sprintf (g_core.password, "%s", g_core.config_ua->passwd);
            sprintf (g_core.transport, "%s", g_core.config_ua->transport);
            sprintf (g_core.realm, "%s", "3402000000");
            sprintf (g_core.nonce, "%s", "1234567890123456");
            g_core.expiry = g_core.config_ua->expiry;
            g_core.localport = g_core.config_ua->server_port;      
        }else if (osip_strcasecmp(g_core.role, "UAC") == 0){
    
            sprintf (g_core.username, "%s", g_core.config_ua->user_id);
            sprintf (g_core.password, "%s", g_core.config_ua->passwd);
            sprintf (g_core.transport, "%s", g_core.config_ua->transport);
            g_core.expiry = g_core.config_ua->expiry;
            g_core.localport = g_core.config_ua->user_port;
    
            sprintf (g_core.from, "%s%s%s%s%s%d", "sip:",g_core.config_ua->user_id,"@",
                                g_core.config_ua->server_ip,":",g_core.config_ua->user_port);
            sprintf (g_core.proxy, "%s%s%s%s%s%d", "sip:",g_core.config_ua->server_id,"@",
                                g_core.config_ua->server_ip,":",g_core.config_ua->server_port);
        
            sprintf (g_core.contact, "%s%s%s%s%s%d", "sip:",g_core.config_ua->user_id,"@", 
                                get_ip(),":",g_core.config_ua->user_port);
    
            //sprintf (g_core.outboundproxy, "%s%s%s%d", "sip:",g_core.config_ua->server_ip,":",g_core.config_ua->server_port);
    
        }else{
            printf(    
                "	-r --proxy	sip:proxyhost[:port]
    "
                "	-f --fromuser	sip:fromuser@host[:port]
    "
                "	-t --touser	sip:touser@host[:port]
    "
                "	-c --contact	sip:user@host[:port]
    "
                "	-R --route	outboundproxy or SBC or P-CSCF(sip:outboundproxyhost[:port])
    " 
            );      
        }
    
        ualog(LOG_INFO, "proxy: %s", g_core.proxy);
        ualog(LOG_INFO, "outboundproxy: %s", g_core.outboundproxy);
        ualog(LOG_INFO, "from: %s", g_core.from);
        ualog(LOG_INFO, "to: %s", g_core.to);
        ualog(LOG_INFO, "contact: %s", g_core.contact);
        ualog(LOG_INFO, "expiry: %d", g_core.expiry);
        ualog(LOG_INFO, "localport: %d", g_core.localport);
        ualog(LOG_INFO, "transport: %s", g_core.transport);
        ualog(LOG_INFO, "role: %s", g_core.role);
        ualog(LOG_INFO, "calltimeout: %d", g_core.calltimeout);
    
        g_core.context = eXosip_malloc();
        if (eXosip_init(g_core.context)){
            ualog(LOG_ERR, "init failed");
            return -1;
        }
        if (osip_strcasecmp(g_core.transport, "UDP") == 0){
            ret = eXosip_listen_addr(g_core.context, IPPROTO_UDP, NULL, g_core.localport, AF_INET, 0);
        }
        else if (osip_strcasecmp(g_core.transport, "TCP") == 0){
            ret = eXosip_listen_addr(g_core.context, IPPROTO_TCP, NULL, g_core.localport, AF_INET, 0);
        }
        else if (osip_strcasecmp(g_core.transport, "TLS") == 0){
            ret = eXosip_listen_addr(g_core.context, IPPROTO_TCP, NULL, g_core.localport, AF_INET, 1);
        }
        else if (osip_strcasecmp(g_core.transport, "DTLS") == 0){
            ret = eXosip_listen_addr(g_core.context, IPPROTO_UDP, NULL, g_core.localport, AF_INET, 1);
        }
        else{
            ret = -1;
        }
        if (ret){
            ualog(LOG_ERR, "listen failed");
            return -1;
        }
        if (g_core.localip){
            ualog(LOG_INFO, "local address: %s", g_core.localip);
            eXosip_masquerade_contact(g_core.context, g_core.localip, g_core.localport);
        }
        if (g_core.firewallip){
            ualog(LOG_INFO, "firewall address: %s:%i", g_core.firewallip, g_core.localport);
            eXosip_masquerade_contact(g_core.context, g_core.firewallip, g_core.localport);
        }
    
        eXosip_set_user_agent(g_core.context, UA_VERSION);
    
        if (g_core.username && g_core.password){
            ualog(LOG_INFO, "username: %s", g_core.username);
            ualog(LOG_INFO, "password: ******");
            ualog(LOG_INFO, "realm: %s", g_core.realm);
            ualog(LOG_INFO, "nonce: %s", g_core.nonce);
            if (eXosip_add_authentication_info(g_core.context, g_core.username,
                g_core.username, g_core.password, NULL, NULL)){
                ualog(LOG_ERR, "add_authentication_info failed");
                return -1;
            }
        }
    
        /* start */
        if (osip_strcasecmp(g_core.role, "UAS") == 0){ 
            uaslog("eXosip UAS Startup...");      
            uas_cmd_usage();
        }else if (osip_strcasecmp(g_core.role, "UAC") == 0){
            ualog(LOG_INFO, "eXosip UAC Startup...");
            ua_cmd_usage();
        }else{
            ualog(LOG_INFO, "eXosip UA Startup...");
            ua_cmd_usage();
        }
    
        pthread_create(&g_core.ua_notifythread, NULL, ua_notify_thread, &g_core);
    
        if (osip_strcasecmp(g_core.role, "UAC") == 0){
            g_core.cmd = UA_CMD_REGISTER;
            ua_cmd_register(&g_core);
        }
    
        printf("....................test......................
    ");
        printf(">");
        while (g_core.running){
            char c = getchar();
            eXosip_lock(g_core.context);
            switch (c){
            case UA_CMD_REGISTER:
                g_core.cmd = c;          
                ua_cmd_register(&g_core);
                break;
            case UA_CMD_CALL_START:{ 
                char tmp[4096];          
                if (osip_strcasecmp(g_core.role, "UAS") == 0){         
                    //test
                    const char *user_id = "34020000001320000222";
                    const char *user_ip = "172.16.23.89";
                    const int user_port = 5222;
                                    
                    sprintf (g_core.from, "%s%s%s%s%s%d", "sip:",g_core.config_ua->server_id,"@", get_ip(),":", 
                                g_core.config_ua->server_port);
    
                    sprintf (g_core.to, "%s%s%s%s%s%d", "sip:", user_id, "@", user_ip, ":", user_port);
    
                    sprintf (g_core.contact, "%s%s%s%s%s%d", "sip:",g_core.config_ua->server_id,"@", 
                                g_core.config_ua->server_ip,":",g_core.config_ua->server_port);
    
                    //sprintf (g_core.outboundproxy, "%s%s%s%d", "sip:",g_core.config_ua->server_ip,":", 
                                g_core.config_ua->server_port);
    
                    g_core.rtp_port = get_rand_rtp_port(g_core.config_ua->rtp_port_start, g_core.config_ua->rtp_port_end);
                   
                    if(g_core.media_proto==0){
                        snprintf (tmp, 4096,
                                  "v=0
    "
                                  "o=%s 0 0 IN IP4 %s
    "
                                  "s=Play
    "
                                  "c=IN IP4 %s
    "
                                  "t=0 0
    "
                                  "m=video %d RTP/AVP 96 98 97
    "
                                  "a=recvonly
    "
                                  "a=rtpmap:96 PS/90000
    "
                                  "a=rtpmap:98 H264/90000
    "
                                  "a=rtpmap:97 MPEG4/90000
    "
                                  "y=0100000001
    "
                                  "f=
    ", g_core.config_ua->server_id, get_ip(), get_ip(), g_core.rtp_port);
                    }else if(g_core.media_proto==1){
                        snprintf (tmp, 4096,
                                  "v=0
    "
                                  "o=%s 0 0 IN IP4 %s
    "
                                  "s=Play
    "
                                  "c=IN IP4 %s
    "
                                  "t=0 0
    "
                                  "m=video %d TCP/RTP/AVP 96 98 97
    "
                                  "a=recvonly
    "
                                  "a=rtpmap:96 PS/90000
    "
                                  "a=rtpmap:98 H264/90000
    "
                                  "a=rtpmap:97 MPEG4/90000
    "
                                  "a=setup:passive
    "
                                  "a=connection:new
    "
                                  "y=0100000001
    "
                                  "f=
    ", g_core.config_ua->server_id, get_ip(), get_ip(), g_core.rtp_port);
                    }else{
                        /*unknow media translate proto type !*/
                    }
    
                }
                ua_cmd_callstart(&g_core, tmp);
                break;
            }
            case UA_CMD_CALL_ANSWER:{
                /*
                char tmp[4096];
                int rtp_port = 6000;
                snprintf (tmp, 4096,
                          "v=0
    "
                          "o=%s 0 0 IN IP4 %s
    "
                          "s=Play
    "
                          "c=IN IP4 %s
    "
                          "t=0 0
    "
                          "m=video %d RTP/AVP 96
    "
                          "a=rtpmap:96 PS/90000
    "
                          "a=sendonly
    ", g_core.config_ua->user_id, g_core.config_ua->server_ip, get_ip(),rtp_port);
                ua_cmd_callanswer(&g_core, tmp);
                */
                break;
            }
            case UA_CMD_CALL_KEEP:{
                ua_cmd_callkeep(&g_core);
            }
                break;
            case UA_CMD_CALL_STOP:{
                //test
                const char *user_id = "34020000001320000222";
                const char *user_ip = "172.16.23.89";
                const int user_port = 5222;
    
                sprintf (g_core.from, "%s%s%s%s%s%d", "sip:",g_core.config_ua->server_id,"@", get_ip(),":", 
                            g_core.config_ua->server_port);
    
                sprintf (g_core.to, "%s%s%s%s%s%d", "sip:", user_id, "@", user_ip, ":", user_port);
    
                sprintf (g_core.contact, "%s%s%s%s%s%d", "sip:",g_core.config_ua->server_id,"@", 
                            g_core.config_ua->server_ip,":",g_core.config_ua->server_port);
    
                //sprintf (g_core.outboundproxy, "%s%s%s%d", "sip:",g_core.config_ua->server_ip,":", 
                            g_core.config_ua->server_port);
    
                ua_cmd_callstop(&g_core);
                break;
            }
            case UA_CMD_UNREGISTER:
                g_core.cmd = c;
                ua_cmd_unregister(&g_core);
                break;
            case UA_CMD_HELP:
                ua_cmd_usage();
                break;
            case UA_CMD_QUIT:
                g_core.running = 0;
                break;
            case '
    ':
                printf(">");
                break;
            default:
                ualog(LOG_ERR, "unknown '%c'", c);
                break;
            }
            eXosip_unlock(g_core.context);
        }
    
        /* stop */
        if (osip_strcasecmp(g_core.role, "UAS") == 0){ 
            printf("%s stop
    ", UAS_VERSION);
        }else{
            printf("%s stop
    ", UA_VERSION);
        }
        quit(&g_core);
    
        return 0;
    }

    4. demo测试

    启动国标服务器

    dong@dong-ubuntu:~/zhoudd/ua$ ./ua -c ./conf/gb28181.server.ini
    proxy:
    >outboundproxy:
    >from:
    >to:
    >contact:
    >expiry: 0
    >localport: 5060
    >transport: UDP
    >role: UAS
    >calltimeout: 1800
    >local address:
    >firewall address: :5060
    >username: 34020000002000000001
    >password: ******
    >realm: 3402000000
    >nonce: 1234567890123456
    >[2020-05-14 10:43:12.09] eXosip UAS Startup...
    please select:
        2: call start
        5: call stop
        h: help
        q: quit
    ....................test......................
    >[2020-05-14 10:43:32.19] register401_unauthorized

    [2020-05-14 10:43:32.19] register_success

    [2020-05-14 10:43:32.19] SIP Message : CmdType~Keepalive, SN~1,DeviceID~34020000001320000222

    >2
    >[2020-05-14 10:43:34.96] proceeding!

    call 1 ring
    >[2020-05-14 10:43:35.08] connected!

    m_media:video,m_port:17950,m_number_of_port:(null),m_proto:TCP/RTP/AVP
    recvonly : (null)
    rtpmap : 96 PS/90000
    rtpmap : 98 H264/90000
    rtpmap : 97 MPEG4/90000
    setup : passive
    connection : new
    [2020-05-14 10:43:35.08] created ps stream channel to recv device data (rtp port:17950)
    [2020-05-14 10:44:08.02] SIP Message : CmdType~Keepalive, SN~2,DeviceID~34020000001320000222
    [2020-05-14 10:44:44.45] SIP Message : CmdType~Keepalive, SN~3,DeviceID~34020000001320000222
    [2020-05-14 10:45:20.76] SIP Message : CmdType~Keepalive, SN~4,DeviceID~34020000001320000222
    [2020-05-14 10:45:57.20] SIP Message : CmdType~Keepalive, SN~5,DeviceID~34020000001320000222
    [2020-05-14 10:46:33.51] SIP Message : CmdType~Keepalive, SN~6,DeviceID~34020000001320000222
    [2020-05-14 10:47:09.95] SIP Message : CmdType~Keepalive, SN~7,DeviceID~34020000001320000222

    启动国标客户端

    dong@ubuntu:~/ua$ ./ua -c ./conf/gb28181.client.ini
    proxy: sip:34020000002000000001@172.16.23.240:5060
    >outboundproxy:
    >from: sip:34020000001320000222@172.16.23.240:5222
    >to:
    >contact: sip:34020000001320000222@172.16.23.89:5222
    >expiry: 3600
    >localport: 5222
    >transport: UDP
    >role: UAC
    >calltimeout: 1800
    >local address:
    >firewall address: :5222
    >username: 34020000001320000222
    >password: ******
    >realm:
    >nonce:
    >eXosip UAC Startup...
    >please select:
        1: register
        2: call start
        3: call answer
        4: call keep
        5: call stop
        6: unregister
        h: help
        q: quit
    ....................test......................
    >register 1 failure
    >register 1 sucess
    >call 1 incoming,please answer...
    >m_media:video,m_port:17950,m_number_of_port:(null),m_proto:TCP/RTP/AVP
    recvonly : (null)
    rtpmap : 96 PS/90000
    rtpmap : 98 H264/90000
    rtpmap : 97 MPEG4/90000
    setup : passive
    connection : new
    call 1 ack
    >m_media:video,m_port:17950,m_number_of_port:(null),m_proto:TCP/RTP/AVP
    recvonly : (null)
    rtpmap : 96 PS/90000
    rtpmap : 98 H264/90000
    rtpmap : 97 MPEG4/90000
    setup : passive
    connection : new
    [2020-05-14 10:43:35.08] push ps stream to server rtp port:17950
    [2020-05-14 10:44:07.96] eXosip stats: inmemory=(tr:2//reg:1) average=(tr:399.959991//reg:99.989998)
    [2020-05-14 10:44:44.32] eXosip stats: inmemory=(tr:2//reg:1) average=(tr:249.987503//reg:49.997501)
    [2020-05-14 10:45:20.71] eXosip stats: inmemory=(tr:2//reg:1) average=(tr:198.158600//reg:33.026432)
    [2020-05-14 10:45:57.09] eXosip stats: inmemory=(tr:2//reg:1) average=(tr:173.788788//reg:24.826969)
    [2020-05-14 10:46:33.47] eXosip stats: inmemory=(tr:2//reg:1) average=(tr:159.112869//reg:19.889109)
    [2020-05-14 10:47:09.85] eXosip stats: inmemory=(tr:2//reg:1) average=(tr:148.621399//reg:16.513489)

    demo下载

    https://files.cnblogs.com/files/dong1/ua.tar.gz

    5. 功能完善

    作为客户端,接入到第三方SIP服务器调试工具

    作为客户端,接入到公安部SPVMN调测工具

    国标28181有近30个操作摄像头的SIP消息,SPVMN界面上这些差不多齐全了,这些操作都是同一类消息。

    消息操作的SDP描述信息列举到这里

    #register
    REGISTER sip:34020000002000000001@3402000000:5060 SIP/2.0
    Via: SIP/2.0/UDP 172.16.23.205:5060;rport=5060;branch=z9hG4bK486745920;received=172.16.23.205
    From: <sip:34020000001320000001@3402000000:5060>;tag=664773380
    To: <sip:34020000001320000001@3402000000:5060>
    Call-ID: 790171336
    CSeq: 1 REGISTER
    Contact: <sip:34020000001320000001@172.16.23.205:5060>
    Max-Forwards: 70
    User-Agent: IP Camera
    Expires: 3600
    Content-Length: 0


    SIP/2.0 401 Unauthorized
    To: <sip:34020000001320000001@3402000000:5060>;tag=65990692_53173353_531c5a1e-2a55-4e70-8d7a-03ea484ba3ab
    CSeq: 1 REGISTER
    Call-ID: 790171336
    Via: SIP/2.0/UDP 172.16.23.205:5060;rport=5060;branch=z9hG4bK486745920;received=172.16.23.205
    From: <sip:34020000001320000001@3402000000:5060>;tag=664773380
    WWW-Authenticate: Digest realm="3402000000",nonce="c98f6d56cb2ab8e6"
    Content-Length: 0


    REGISTER sip:34020000002000000001@3402000000:5060 SIP/2.0
    Via: SIP/2.0/UDP 172.16.23.205:5060;rport=5060;branch=z9hG4bK1887657866;received=172.16.23.205
    From: <sip:34020000001320000001@3402000000:5060>;tag=664773380
    To: <sip:34020000001320000001@3402000000:5060>
    Call-ID: 790171336
    CSeq: 2 REGISTER
    Contact: <sip:34020000001320000001@172.16.23.205:5060>
    Authorization: Digest username="34020000001320000001",realm="3402000000",nonce="c98f6d56cb2ab8e6",uri="sip:34020000002000000001@3402000000:5060",response="79d8846430436131196c50746cd97fa5",algorithm=MD5
    Max-Forwards: 70
    User-Agent: IP Camera
    Expires: 3600
    Content-Length: 0


    SIP/2.0 200 OK
    To: <sip:34020000001320000001@3402000000:5060>;tag=91259330_53173353_e4ab511d-9718-4fdc-a1f7-4e466c4345b9
    CSeq: 2 REGISTER
    Call-ID: 790171336
    Via: SIP/2.0/UDP 172.16.23.205:5060;rport=5060;branch=z9hG4bK1887657866;received=172.16.23.205
    From: <sip:34020000001320000001@3402000000:5060>;tag=664773380
    Contact: <sip:34020000001320000001@172.16.23.205:5060>
    Expires: 3600
    Date: 2020-04-21T10:52:55.103
    TimeRevise: 20200421105255
    Content-Length: 0

    #heartbeat
    MESSAGE sip:34020000002000000001@3402000000 SIP/2.0
    Via: SIP/2.0/UDP 172.16.23.205:5060;rport=5060;branch=z9hG4bK219387606;received=172.16.23.205
    From: <sip:34020000001320000001@3402000000>;tag=1293913070
    To: <sip:34020000002000000001@3402000000>
    Call-ID: 1375843967
    CSeq: 20 MESSAGE
    Content-Type: Application/MANSCDP+xml
    Max-Forwards: 70
    User-Agent: IP Camera
    Content-Length: 160

    <?xml version="1.0" encoding="UTF-8"?>
    <Notify>
    <CmdType>Keepalive</CmdType>
    <SN>1</SN>
    <DeviceID>34020000001320000001</DeviceID>
    <Status>OK</Status>
    </Notify>

    SIP/2.0 200 OK
    To: <sip:34020000002000000001@3402000000>;tag=63521570_53173353_d383f4f9-7693-4a43-8dac-ef24aa3a0bcd
    CSeq: 20 MESSAGE
    Call-ID: 1375843967
    Via: SIP/2.0/UDP 172.16.23.205:5060;rport=5060;branch=z9hG4bK219387606;received=172.16.23.205
    From: <sip:34020000001320000001@3402000000>;tag=1293913070
    Content-Length: 0


    #device catlog
    <?xml version="1.0"?>
    <Query>
    <CmdType>Catalog</CmdType>
    <SN>248</SN>
    <DeviceID>34020000001320000001</DeviceID>
    </Query>

    #device info
    <?xml version="1.0"?>
    <Query>
    <CmdType>DeviceInfo</CmdType>
    <SN>17430</SN>
    <DeviceID>34020000001320000001</DeviceID>
    </Query>

    #device status
    <?xml version="1.0"?>
    <Query>
    <CmdType>DeviceStatus</CmdType>
    <SN>248</SN>
    <DeviceID>34020000001320000001</DeviceID>
    </Query>

    #boot
    <?xml version="1.0"?>
    <Control>
    <CmdType>DeviceControl</CmdType>
    <SN>17298</SN>
    <DeviceID>34020000001320000001</DeviceID>
    <TeleBoot>Boot</TeleBoot>
    </Control>

    #invite
    v=0
    o=34020000002000000001 0 0 IN IP4 172.16.23.113
    s=Play
    c=IN IP4 172.16.23.113
    t=0 0
    m=video 6000 RTP/AVP 96 98 97
    a=recvonly
    a=rtpmap:96 PS/90000
    a=rtpmap:98 H264/90000
    a=rtpmap:97 MPEG4/90000
    y=0100000001
    f=

    #tcp active invite
    v=0
    o=34020000002000000001 0 0 IN IP4 172.16.23.113
    s=Play
    c=IN IP4 172.16.23.113
    t=0 0
    m=video 6000 TCP/RTP/AVP 96 98 97
    a=recvonly
    a=rtpmap:96 PS/90000
    a=rtpmap:98 H264/90000
    a=rtpmap:97 MPEG4/90000
    a=setup:active
    a=connection:new
    y=0100000001
    f=

    #tcp passive invite
    v=0
    o=34020000002000000001 0 0 IN IP4 172.16.23.113
    s=Play
    c=IN IP4 172.16.23.113
    t=0 0
    m=video 6000 TCP/RTP/AVP 96 98 97
    a=recvonly
    a=rtpmap:96 PS/90000
    a=rtpmap:98 H264/90000
    a=rtpmap:97 MPEG4/90000
    a=setup:passive
    a=connection:new
    y=0100000001
    f=

    #left

    <?xml version="1.0"?>
    <Control>
    <CmdType>DeviceControl</CmdType>
    <SN>11</SN>
    <DeviceID>34020000001320000001</DeviceID>
    <PTZCmd>A50F01021F0000D6</PTZCmd>
    </Control>

    #right
    <?xml version="1.0"?>
    <Control>
    <CmdType>DeviceControl</CmdType>
    <SN>11</SN>
    <DeviceID>34020000001320000001</DeviceID>
    <PTZCmd>A50F01011F0000D5</PTZCmd>
    </Control>

    #up
    <?xml version="1.0"?>
    <Control>
    <CmdType>DeviceControl</CmdType>
    <SN>11</SN>
    <DeviceID>34020000001320000001</DeviceID>
    <PTZCmd>A50F0108001F00DC</PTZCmd>
    </Control>

    #down
    <?xml version="1.0"?>
    <Control>
    <CmdType>DeviceControl</CmdType>
    <SN>11</SN>
    <DeviceID>34020000001320000001</DeviceID>
    <PTZCmd>A50F0104001F00D8</PTZCmd>
    </Control>

    #zoom in
    <?xml version="1.0"?>
    <Control>
    <CmdType>DeviceControl</CmdType>
    <SN>11</SN>
    <DeviceID>34020000001320000001</DeviceID>
    <PTZCmd>A50F0110000010D5</PTZCmd>
    </Control>

    #zoom out
    <?xml version="1.0"?>
    <Control>
    <CmdType>DeviceControl</CmdType>
    <SN>11</SN>
    <DeviceID>34020000001320000001</DeviceID>
    <PTZCmd>A50F0120000010E5</PTZCmd>
    </Control>

    #ptz stop
    <?xml version="1.0"?>
    <Control>
    <CmdType>DeviceControl</CmdType>
    <SN>11</SN>
    <DeviceID>34020000001320000001</DeviceID>
    <PTZCmd>A50F0100000000B5</PTZCmd>
    </Control>

    #playback
    v=0
    o=34020000002000000001 0 0 IN IP4 172.16.23.113
    s=Playback
    u=34020000001320000001:3
    c=IN IP4 172.16.23.113
    t=1311904968 1311906769
    m=video 6000 RTP/AVP 96 98 97
    a=recvonly
    a=rtpmap:96 PS/90000
    a=rtpmap:98 H264/90000
    a=rtpmap:97 MPEG4/90000
    y=1100000000
    f=

    #download
    v=0
    o=34020000002000000001 0 0 IN IP4 172.16.23.113
    s=Download
    u=34020000001320000001:3
    c=IN IP4 172.16.23.113
    t=1311904968 1311906769
    m=video 6000 RTP/AVP 96 98 97
    a=recvonly
    a=rtpmap:96 PS/90000
    a=rtpmap:98 H264/90000
    a=rtpmap:97 MPEG4/90000
    y=1100000000
    f=

    #play
    PLAY RTSP/1.0
    CSeq: 2
    Scale: 1.0
    Range: npt=15-

    #pause
    PAUSE RTSP/1.0
    CSeq: 1
    PauseTime: 15

    #play scale+
    PLAY RTSP/1.0
    CSeq: 3
    Scale: 2.0
    Range: npt=0-

    #play scale-
    PLAY RTSP/1.0
    CSeq: 3
    Scale: 0.5
    Range: npt=0-

    #record
    <?xml version="1.0"?>
    <Control>
    <CmdType>DeviceControl</CmdType>
    <SN>17</SN>
    <DeviceID>34020000001320000001</DeviceID>
    <RecordCmd>Record</RecordCmd>
    </Control>

    #stop record
    <?xml version="1.0"?>
    <Control>
    <CmdType>DeviceControl</CmdType>
    <SN>17</SN>
    <DeviceID>34020000001320000001</DeviceID>
    <RecordCmd>StopRecord</RecordCmd>
    </Control>

    #record info
    <?xml version="1.0"?>
    <Query>
    <CmdType>RecordInfo</CmdType>
    <SN>17430</SN>
    <DeviceID>34020000001320000001</DeviceID>
    <StartTime>2010-11-11T19:46:17</StartTime>
    <EndTime>2010-11-12T19:46:17</EndTime>
    <FilePath>64010000002100000001</FilePath>
    <Address>Address1</Address>
    <Secrecy>0</Secrecy>
    <Type>time</Type>
    <RecorderID>64010000003000000001</RecorderID>
    </Query>

    #set guard
    <?xml version="1.0"?>
    <Control>
    <CmdType>DeviceControl</CmdType>
    <SN>17294</SN>
    <DeviceID>34020000001320000001</DeviceID>
    <GuardCmd>SetGuard</GuardCmd>
    </Control>

    #reset guard
    <?xml version="1.0"?>
    <Control>
    <CmdType>DeviceControl</CmdType>
    <SN>17294</SN>
    <DeviceID>34020000001320000001</DeviceID>
    <GuardCmd>ResetGuard</GuardCmd>
    </Control>

    #reset alarm
    <?xml version="1.0"?>
    <Control>
    <CmdType>DeviceControl</CmdType>
    <SN>17438</SN>
    <DeviceID>34020000001320000001</DeviceID>
    <AlarmCmd>ResetAlarm</AlarmCmd>
    <Info>
    <AlarmMethod>2</AlarmMethod>
    </Info>
    </Control>

    除了SPVMN,还有些第三方工具可以调试SIP指令,SPVMN加上以下这个自动化测试工具,几乎包含了所有的GB28181-2016的协议细节。

    当然用来做生产批量测试也很好。

    有了上面的客户端和服务器SIP交互,再加上媒体部分(收发),就可以定制一整套国标系统了。

    模拟8路客户端,比较稳定。

    我自己添加的国标功能部分不能共享,因为是上班时间给公司做的。

    其实就是在larkguo的基础上,添加了部分国标定制的SIP交互和RTP收发PS流。

    上面demo的sip部分已经有了国标基础功能(更多的交互请自行添加),剩下的媒体部分可以参考如下:

    rtp over udp 参考
    jrtplib/example/exapmle1.cpp

    rtp over tcp 参考
    jrtplib/test/tcptest.cpp

    也可以参考我的笔记
    https://www.cnblogs.com/dong1/p/12179996.html

    ps流封装与解析
    可以用libmpeg库
    https://github.com/ireader/media-server/tree/master/libmpeg
    熟悉ffmpeg,也可以定制
    ffmpeg/example/muxing.c/demuxing.c/remuxing.c

    相关工具下载

    https://download.csdn.net/download/candy89720/10867021

    http://www.happytimesoft.com/products/gb28181-device/index.html

    https://download.csdn.net/download/qq_24798461/9820447 

    6. 感谢

    https://github.com/staskobzar/sip_stacks_examples/blob/master/libexosip/sipua.c
    https://github.com/staskobzar/sip_stacks_examples
    https://github.com/hfreire/sipc/blob/master/src/rtp.c
    https://github.com/Cashwini/PJSIPClient/blob/master/sip_client.c
    https://github.com/larkguo/SIP_UA/blob/master/ua.c
    https://github.com/larkguo/sip2rtsp

  • 相关阅读:
    JAVA GUI设
    3.4 jmu-java-随机数-使用蒙特卡罗法计算圆周率的值 (10 分)
    问题:关于2.3 jmu-Java-02基本语法-03-身份证排序 (9 分)
    关于3.1 jmu-Java-03面向对象基础-01-构造函数与toString (3 分)
    linux vim文件编辑的常用命令
    linux的常用命令
    linux文件存储方式
    第一个java
    hdu 2795
    hdu 1394
  • 原文地址:https://www.cnblogs.com/dong1/p/12607489.html
Copyright © 2011-2022 走看看