libosip2,libeXosip2 編譯

    最近業務中需要做網絡電話,在研究sip協議,藉助osip2和eXosip2進行學習,

以下是初步編譯和實踐經驗,分享在此:

   使用庫的版本:libosip2-3.6.0.tar,libeXosip2-3.6.0.tar

   解壓libosip2-3.6.0.tar ,比如解壓目錄爲 /usr/local/libosip2-3.6.0,進入該目錄,

   編譯該lib庫:

   #./configure

   #make

   #make install

   同理編譯libeXosip2

   #./configure

   #make

   #make install

   注意最後要更新庫,否則在程序執行時,可能會提示找不到庫,編譯後的庫文件及頭文件會默認放在/usr/local目錄下:

   #ldconfig

   在運行測試程序時,如果輸出類似以下的提示信息時,原因可能是沒有配置默認網關:

   Debug=... network is unreachable

  

測試程序:uac.c 客戶端,可以實現註冊,撥號,振鈴,掛機等網絡電話事務, 調試已通過(sip服務器藉助 mjserver6 ,我的下載資源中提供)

/*

gcc -o exosip_phone exosip_phone.c -losip2 -leXosip2 -lpthread

*/

#include <eXosip2/eXosip.h>
  #include <osip2/osip_mt.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include <sys/types.h>
  #include <netinet/in.h>
  #include <sys/socket.h>
 //  #include <mediastreamer2/mediastream.h>
  #include <osipparser2/osip_message.h>
  #include <osipparser2/osip_parser.h>
  #include <pthread.h>


  #define WAIT_TIMER 200
  #define REG_TIMER 30*1000
 
  int doing;
  int rtp_port;
  int dtmfing, calling,picked;
  int call_id ,dialog_id;   
   
  char *m_strAuth;
  char *dtmf_str="2002";
   //CString dtmf_str;
  char *server_url="192.168.1.106";
  char *dest_url="192.168.1.102";
  char *server_port="5060";
  char *local_port="5000";
  char *username="10007";
  char *password="10007";
  char *telNum="10008";
   
//  AudioStream *audio = NULL;
 // RtpProfile *profile = NULL;
//  RtpSession *session = NULL;
//  OrtpEvQueue *q = NULL;

   eXosip_event_t *uac_e;              /* 事件處理 */  
   osip_message_t *ack = NULL;         /* 響應消息 */   
   osip_message_t *answer = NULL;      /* 請求消息的迴應 */   
  
   eXosip_event_t *uac_call;              /* answer事件處理 */ 
   osip_message_t *answer_call = NULL;      /* answer請求消息的迴應 */ 

int build_media(int local_port, const char *remote_ip, int remote_port, int payload, const char *fmtp, int jitter, int ec, int bitrate)   
{   
    if(payload != 0 && payload != 8)   
    {   
        /* 目前僅支持0,8 711ulaw,711alaw */    
        return -1;   
    }   
   
    // PayloadType *pt;   
       
  //  profile = rtp_profile_clone_full(&av_profile);   
   // q = ortp_ev_queue_new();       
  /* 
    pt = rtp_profile_get_payload(profile, payload);   
    if (pt==NULL)   
    {   
        printf("codec error!");   
        return -1;   
    }   
    */

   // if (fmtp != NULL) payload_type_set_send_fmtp(pt, fmtp);   
    //if (bitrate > 0) pt->normal_bitrate = bitrate;   
  /* 
    if (pt->type != PAYLOAD_VIDEO)   
     {   
        printf("audio stream start!");   
        audio = audio_stream_start(profile, local_port, remote_ip, remote_port, payload, jitter, ec);   
        if (audio)    
        {   
            session = audio->session;   
        }   
        else   
        {   
            printf("session error!");   
            return -1;   
        }   
    }   
    else   
    {   
        printf("codec select error!");   
        return -1;   
    }   
    rtp_session_register_event_queue(session, q);      
   */
    return 0;   
}


int real_send_register(int expires)
 {   
    char identity[100];   
    char registerer[100];     
    char localip[128];   
    int id;
    int ret;
    eXosip_guess_localip (AF_INET, localip, 128);
    printf("%s\n",localip);
    //sprintf(identity,"sip:%s@%s:%s",username,localip,local_port);
    sprintf(identity,"sip:%s@%s",username,server_url);
    sprintf(registerer,"sip:%s:%s",server_url,server_port);      
       
    osip_message_t *reg = NULL;       
       
    eXosip_lock ();   
    id = eXosip_register_build_initial_register(identity, registerer, NULL,expires, &reg);     
    eXosip_unlock ();   
    if(0 > id)   
    {   
        printf("register init Failed!\n");   
        return -1;   
    }   
       
    eXosip_lock ();
    eXosip_clear_authentication_info();    //去除上次加入的錯誤認證信息,再應用新輸入的鑑權信息
    eXosip_add_authentication_info(username, username,password, "md5", NULL);  
    ret = eXosip_register_send_register(id, reg);   
    eXosip_unlock ();   
    if(0 != ret)   
    {   
        printf("register send Failed!\n");   
        return -1;   
    }   
       
    return id;      
}


int sip_ua_monitor()   
{   
    int ret = -1;   
    char *payload_str;                  /* 服務器優先編碼值 */   
    char localip[128];   
    char tmp[4096];    
    char dtmf[50] = {0};
   
    int reg_remain = REG_TIMER;      
    usleep(500);
    printf("Event monitor for uac/uas start!\n");   
   

   
    /* 響應SDP(用於UAC) */   
    sdp_message_t * msg_rsp = NULL;   
    sdp_connection_t * con_rsp = NULL;   
    sdp_media_t * md_rsp = NULL;   
   
    /* 請求SDP(用於UAS) */   
    sdp_message_t * msg_req = NULL;   
    sdp_connection_t * con_req = NULL;   
    sdp_media_t * md_req = NULL;   
       
    char out_str[100] = {0};   
       
    eXosip_lock ();   
    eXosip_automatic_action();   
    eXosip_unlock ();   
   
    while(doing)   
    {   
        eXosip_lock ();   
        uac_e = eXosip_event_wait (0, WAIT_TIMER);   
        eXosip_unlock ();   
   
        reg_remain = reg_remain - WAIT_TIMER;   
        if(reg_remain < 0)   
        {   
            //超時,重新註冊   
            eXosip_lock ();   
            eXosip_automatic_refresh();   
            eXosip_unlock ();   
            reg_remain = REG_TIMER;   
            printf("register timeout,retry!");   
        }   
   
        if(dtmfing)   
        {           
            strcpy(dtmf, dtmf_str);   
             int index;  
            for( index=0; index<50; index++)   
            {   
                //依次讀取字符   
                if(dtmf[index] == '\0') break;   
                   
                /* 發送DTMF */   
                eXosip_lock();   
                //audio_stream_send_dtmf(audio, dtmf[index]);   
                eXosip_unlock();   
   
                sprintf(out_str, "DTMF send <%c> OK!", dtmf[index]);   
                printf("%s",out_str);
                usleep(500);   
            }   
   
            dtmfing = 0;   
        }   
   
        if (uac_e == NULL)   
        {   
            //DEBUG_INFO("nothing");   
            continue;   
        }   
   
        eXosip_lock ();   
        eXosip_default_action(uac_e);   /* 處理407加入鑑權信息 */   
        eXosip_unlock ();   
   
        if(NULL != uac_e->response)   
        {   
            //UAC 消息處理前檢查   
            sprintf(out_str, "%d %s\n", uac_e->response->status_code, uac_e->response->reason_phrase);   
            printf(out_str);   
   
            if(487 == uac_e->response->status_code)   
            {   
               printf("qu xiao hujiao chenggong\n");     
                continue;   
            }   
   
            if(480 == uac_e->response->status_code)   
            {   
                //480 無應答   
                printf("wu ying da\n");   

                picked = 0;   
                calling = 0;   
                call_id = 0;   
                dialog_id = 0;                
                continue;   
            }
           
           if(401 == uac_e->response->status_code)   
            {   
                //480 無應答   
                printf("register again!\n");
                eXosip_add_authentication_info(username, username,password, NULL, NULL);  
               
                osip_message_t *rereg;

                eXosip_register_build_register(uac_e->rid, 300, &rereg);//
                  //取回認證的字符串authorization
                {
                    printf("取回認證字符串,重新註冊");
                    osip_authorization_t * auth;
                    char *strAuth=NULL;
                    osip_message_get_authorization(rereg,0,&auth);
                    osip_authorization_to_str(auth,&strAuth);
                    m_strAuth=strAuth;//保存認證字符串
                }
                 eXosip_register_send_register(uac_e->rid,rereg);
               
               continue;   
            }   
        }   
   
        if(NULL != uac_e->request)   
        {   
        }   
   
        if(NULL != uac_e->ack)   
        {   
        }   
           
        switch (uac_e->type)   
        {   
            case EXOSIP_CALL_SERVERFAILURE:   
            case EXOSIP_CALL_RELEASED:   
                /* 服務器錯誤或對方忙 */   
                printf("busy");   
                   
                call_id = 0;   
                dialog_id = 0;   
                picked = 0;   
                calling = 0;   
                   
                printf("Dest or Server Busy!");   
                break;
   
            /* UAS 處理事件 */   
            case EXOSIP_MESSAGE_NEW: //新的消息到來
            {
                printf("EXOSIP_MESSAGE_NEW!\n");
                if(MSG_IS_MESSAGE(uac_e->request)) //如果接受到的消息類型是MESSAGE
                {
                   osip_body_t *body;
                   osip_message_get_body (uac_e->request, 0, &body);
                   printf ("I get the a msg : %s\n", body->body);
                }
                //按照規則,需要回復200 OK信息
                eXosip_message_build_answer (uac_e->tid, 200,&answer);
                eXosip_message_send_answer (uac_e->tid, 200,answer);
            }
            break;
           
            case EXOSIP_CALL_INVITE:   
                sprintf(out_str, "recevfrom %s",uac_e->request->from->url->string);   
                printf("%s\n",out_str);   
   
                eXosip_lock ();   
                eXosip_call_send_answer(uac_e->tid, 180, NULL);   
               if(0 != eXosip_call_build_answer(uac_e->tid, 200, &answer))   
                {   
                    eXosip_call_send_answer(uac_e->tid, 603, NULL);   
                    printf("error build answer!");   
                    continue;   
                }   
                eXosip_unlock ();   
                   
                call_id = uac_e->cid;                   //供掛斷電話上下文操作   
                dialog_id = uac_e->did;   
   
                //構建本地SDP消息供媒體建立  
                eXosip_guess_localip(AF_INET, localip, 128);   
                snprintf (tmp, 4096,   
                    "v=0\r\n"   
                    "o=youtoo 1 1 IN IP4 %s\r\n"   
                    "s=##youtoo demo\r\n"   
                    "c=IN IP4 %s\r\n"   
                    "t=0 0\r\n"   
                    "m=audio %d RTP/AVP 0 8 101\r\n"   
                    "a=rtpmap:0 PCMU/8000\r\n"   
                    "a=rtpmap:8 PCMA/8000\r\n"   
                    "a=rtpmap:101 telephone-event/8000\r\n"   
                    "a=fmtp:101 0-15\r\n", localip, localip, rtp_port);   
                   
                //設置回覆的SDP消息體,下一步計劃分析消息體   
                eXosip_lock ();   
                osip_message_set_body(answer, tmp, strlen(tmp));   
                osip_message_set_content_type(answer, "application/sdp");   
                   
                //// 解析SDP   
                msg_req = eXosip_get_remote_sdp(uac_e->did);   
                con_req = eXosip_get_audio_connection(msg_req);   
                md_req = eXosip_get_audio_media(msg_req);   
                eXosip_unlock ();   
                   
                //payload_str = (char *)osip_list_get(&md_req->m_payloads, 0); //取主叫媒體能力編碼  
                //暫時只支持0/8 711u/711a  
                    
   
                calling = 1;   
                uac_call=uac_e;
                answer_call=answer;
   
              /*  while(!picked)   
                {   
                    //未接通進入循環檢測   
                    usleep(200);   
                }   
   
                eXosip_unlock ();   
                eXosip_call_send_answer(uac_e->tid, 200, answer);   
                eXosip_unlock ();   
   
                printf("200 ok 發送");    */
                break;   
   
            case EXOSIP_CALL_CANCELLED:   
                /* 拒絕接聽 */    
               
                call_id = 0;   
                dialog_id = 0;                
                picked = 0;   
                calling = 0;   
                printf("hujiao jujue\n");   
                break;   
   
            case EXOSIP_CALL_ACK:   
                /* 返回200後收到ack才建立媒體 */   
                if(calling)   
                {   
                    /* 建立RTP連接 */   
                    printf("this is answer\n");
     /* 
                    ret = build_media(rtp_port, con_req->c_addr, atoi(md_req->m_port), 0, NULL, 0, 0, 0);   
                    if(!ret)   
                    {   
                        printf("媒體建立失敗,無法創建通話,請掛斷!");   
                        //pMainWnd->OnHang();   
                    }  
     */
                }   
                break;   
   
            /* UAC 處理事件 */   
            case EXOSIP_REGISTRATION_SUCCESS:
                printf("textinfo is %s\n", uac_e->textinfo);
                break; 
   
            case EXOSIP_CALL_CLOSED:   
               /*   if(audio)    
                {   
                    //被動關閉媒體連接(遠端觸發)   
                    eXosip_lock ();   
                    audio_stream_stop(audio);   
                       
                    ortp_ev_queue_destroy(q);   
                    rtp_profile_destroy(profile);   
                    eXosip_unlock ();   
   
                    audio = NULL;   
                    q = NULL;   
                    profile = NULL;   
                    printf("audio stream stoped!");   
                }   
    */
                printf("(對方已掛斷)");                   
                call_id = 0;   
                dialog_id = 0;                
                picked = 0;   
                calling = 0;   
                break;   
                   
            case EXOSIP_CALL_PROCEEDING:   
                printf("(查找連接中..)");                    
                break;   
   
            case EXOSIP_CALL_RINGING:   
                printf("(對方振鈴)");               
                call_id = uac_e->cid;   
                dialog_id = uac_e->did;   
   
                /*  
                RingStream *r;  
                MSSndCard *sc;  
                sc=ms_snd_card_manager_get_default_card(ms_snd_card_manager_get());  
                r=ring_start("D:\\mbstudio\\vcwork\\YouToo\\dial.wav",2000,sc);  
                  
                Sleep(10);  
                ring_stop(r);  
                */   
                break;   
                   
            case EXOSIP_CALL_ANSWERED:   
                //ring_stop(ring_p);                   
                printf("(對方已接聽)");             
                   
                call_id = uac_e->cid;   
                dialog_id = uac_e->did;   
                   
                eXosip_lock ();   
                eXosip_call_build_ack (uac_e->did, &ack);   
                eXosip_call_send_ack (uac_e->did, ack);   
   
                /* 響應SIP消息中SDP分析 */   
                msg_rsp = eXosip_get_sdp_info(uac_e->response);   
                con_rsp = eXosip_get_audio_connection(msg_rsp);   
                md_rsp = eXosip_get_audio_media(msg_rsp);   
   
                /* 取服務器支持的最優先的編碼方式 */   
            //    payload_str = (char *)osip_list_get(&md_rsp->m_payloads, 0);   
                eXosip_unlock ();   
   
                /* 建立RTP連接 */   
                printf("this is call\n");
             /*
     ret = build_media(rtp_port, con_rsp->c_addr, atoi(md_rsp->m_port), atoi(payload_str), NULL, 0, 0, 0);   
                if(!ret)   
                {   
                    printf("媒體建立失敗,無法創建通話,請掛斷!");   
                    //pMainWnd->OnHang();   
                }   
    */
                break;   
   
            default:   
                break;   
        }   
           
        eXosip_event_free (uac_e);   
      
        fflush(stdout);
    }   
       
    return 0;   
}

void OnHang()    
{   
    int ret;   
   
 /*
    if(audio)    
    {   
        //主動關閉媒體連接(本地端)   
        eXosip_lock ();   
        audio_stream_stop(audio);   
   
        ortp_ev_queue_destroy(q);   
        rtp_profile_destroy(profile);   
        eXosip_unlock ();   
           
        printf("audio stream stoped!");    
        audio = NULL;   
        q = NULL;   
        profile = NULL;   
    }   
      */             
    eXosip_lock ();   
    ret = eXosip_call_terminate(call_id, dialog_id);     
    eXosip_unlock ();   
    if(0 != ret)   
    {   
        printf("hangup/terminate Failed!\n");  
    }   
    else
    { 
        printf("(已掛斷)");     
        call_id = 0;   
        dialog_id = 0;   
        picked = 0;   
        calling = 0;   
    }
}  
 
  int sip_init()   
{   
    int ret = 0;   
   
    ret = eXosip_init ();   
    eXosip_set_user_agent("liangzi1.0");   
   
    if(0 != ret)   
    {   
        printf("Couldn't initialize eXosip!\n");   
        return -1;   
    }   
   
    ret = eXosip_listen_addr (IPPROTO_UDP, NULL, 5000, AF_INET, 0);   
    if(0 != ret)   
    {   
        eXosip_quit ();   
        printf("Couldn't initialize transport layer!\n");   
        return -1;   
    }   
   
    //AfxBeginThread(sip_ua_monitor,(void *)this);
    pthread_t id;
   //改動
 int i=pthread_create(&id,NULL,(void *) sip_ua_monitor,NULL);
    if(i!=0)
    {
        printf ("Create pthread error!\n");
        return -1;
    }
   
    /* rtp */   
   // ortp_init();   

    //ortp_set_log_level_mask(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL);   
   
    /* media */   
    //ms_init();
      
    return 0;   
}


 int main()
 {
    char *payload_str;
    char localip[128];
    char tmp[4096];
    char command;
    char dtmf[50] = {0};   
       
    int reg_remain = REG_TIMER;
    char out_str[100] = {0};
   
    osip_message_t *invite=NULL;
   osip_message_t *info=NULL;
   osip_message_t *message=NULL;
  
   char source_call[100];   
   char dest_call[100];
  
    doing = 1;                   /* 事件循環開關 */   
    calling = 0;                /* 是否正在被叫(判斷ack類型) */   
    picked = 0;   
    dtmfing = 0;
   
    if(0 != sip_init ())   
    {   
        printf("Quit!\n");   
        return -1;   
    }   
   
   
     
   
   
    call_id = 0;   
    dialog_id = 0;   
   
     
   
    printf("r   zhu ce \n\n");
    printf("c   qu xiao zuce \n\n");
    printf("i   hujiao qingqiu\n\n");
    printf("h   guaduan\n\n");
    printf("a    jieting\n\n");
    printf("q   tuichu\n\n");
    printf("s   INFO\n\n");
    printf("m   MESSAGE\n\n");
   
   int flag=1;
 
    while(flag)
   {
       //輸入命令
       printf("Please input the command:\n");
       scanf("%c",&command);
       getchar();

       switch(command)
       {
       case 'r':
             real_send_register(2000);

             //usleep(500);
             //real_send_register(2000);
             break;
       case 'i':
            eXosip_guess_localip (AF_INET, localip, 128);       
            sprintf(source_call,"sip:%s@%s:%s",username,localip,local_port);
            sprintf(dest_call,"sip:%s@%s:%s",telNum,server_url,server_port);   
            printf("src_call:%s \n dest_call:%s \n",source_call,dest_call);
            //char tmp[4096];
            bzero(tmp,4096);  
       
            int i = eXosip_call_build_initial_invite (&invite, dest_call, source_call, NULL, "This is a call invite");   
            if (i != 0)   
              {   
                    printf("Intial INVITE failed!\n");   
              }   
       
//            char localip[128];   
                   
//            eXosip_guess_localip (AF_INET, localip, 128);   
            snprintf (tmp, 4096,   
                "v=0\r\n"   
                "o=liangzi 0 0 IN IP4 %s\r\n"   
                "s=##liangzi demo\r\n"   
                "c=IN IP4 %s\r\n"   
                "t=0 0\r\n"   
                "m=audio %d RTP/AVP 0 8 101\r\n"   
                "a=rtpmap:0 PCMU/8000\r\n"   
                "a=rtpmap:8 PCMA/8000\r\n"   
                "a=rtpmap:101 telephone-event/8000\r\n"   
                "a=fmtp:101 0-15\r\n", localip, localip, rtp_port);   
                   
            osip_message_set_body (invite, tmp, strlen(tmp));   
            osip_message_set_content_type (invite, "application/sdp");   
                   
            eXosip_lock ();   
            i = eXosip_call_send_initial_invite (invite);   
            eXosip_unlock ();
                 
            break;

       case 'h':   //掛斷
          OnHang();
          break;

       case 'c':
          // real_send_register(0);
           //printf("This modal is not commpleted!\n");
           break;

       case 's': //傳輸INFO方法
           eXosip_call_build_info(dialog_id,&info);
           snprintf(tmp,4096,"\nThis is a sip message(Method:INFO)");
           osip_message_set_body(info,tmp,strlen(tmp));
           //格式可以任意設定,text/plain代表文本信息
           osip_message_set_content_type(info,"text/plain");
           eXosip_call_send_request(dialog_id,info);
           break;

       case 'm':
            bzero(tmp,4096);
            sprintf(source_call,"sip:%s@%s:%s",username,localip,local_port);
            sprintf(dest_call,"sip:%s@%s:%s",telNum,dest_url,server_port);
           //傳輸MESSAGE方法,也就是即時消息,和INFO方法相比,我認爲主要區別是:
           //MESSAGE不用建立連接,直接傳輸信息,而INFO消息必須在建立INVITE的基礎上傳輸
           printf("the method : MESSAGE\n");
           eXosip_message_build_request(&message,"MESSAGE",dest_call,source_call,NULL);
                                        //內容,方法,      to       ,from      ,route
           snprintf(tmp,4096,"This is a sip message(Method:MESSAGE)");
           osip_message_set_body(message,tmp,strlen(tmp));
           //假設格式是xml
           osip_message_set_content_type(message,"text/xml");
           eXosip_message_send_request(message);
           break;

       case 'q':
           doing = -1;
           flag=0;   
           usleep(1000);                //保證事件線程能退出(線程循環檢測時間毫秒級<1000)   
           //主動關閉媒體連接(本地端)      
           printf("Bye!\n");
           break;
          
        case 'a':
           picked = 1;
           printf("answer the call\n");
           eXosip_lock ();   
           eXosip_call_send_answer(uac_call->tid, 200, answer_call);   
           eXosip_unlock ();   
   
                printf("200 ok send");
           printf("connection completed!\n");
           break;
          
         case 'd':
           dtmfing=1;
           break;
         default:
            printf("input error! please input again\n");
            break;
    }
}
return(0);
}

發佈了14 篇原創文章 · 獲贊 1 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章