博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Windows下编译eXosip、osip,以及UAC和UAS的例子
阅读量:7121 次
发布时间:2019-06-28

本文共 10847 字,大约阅读时间需要 36 分钟。

今天开始了SIP开源库的学习,我选择了osip和eXosip,但是这两个库的编译使用有些麻烦,源码下来之后编译会出现很多问题,网上也没有找到完整的编译介绍,只能一步一步的找办法解决,最后终于编译成功!先大概记录下编译过程,后面还要再整理下。

期间还向CSDN论坛求助了下,但是还没有反应:

描述error LNK2019: 无法解析的外部符号 _osip_transaction_set_naptr_record,该符号在函数 __eXosip_transaction_init 中被引用

原因:开源代码的库有些函数没有导出,需要手动在def文件中添加

解决方法:第二步的2,3两小步就是为了解决这个问题。

第一步,下载osip和eXosip

osip:    http://ftp.twaren.net/Unix/NonGNU//osip/libosip2-3.6.0.tar.gz

eXosip: http://download.savannah.gnu.org/releases/exosip/libeXosip2-3.6.0.tar.gz
第二步,解压,编译osip:
1.进入libosip2-3.6.0\platform\vsnet目录,用VS2010直接打开osip.sln文件,项目自动转换
2.更改libosip2-3.6.0\platform\vsnet\osip2.def 文件,在文件末尾追加
  
   osip_transaction_set_naptr_record @138

3.更改libosip2-3.6.0\platform\vsnet\osipparser2.def 文件,在文件末尾追加

   osip_realloc @416

   osip_strcasestr @417 
   __osip_uri_escape_userinfo @418
4.先编译osipparser2,再编译osip2,最后在libosip2-3.6.0\platform\vsnet\Debug DLL下生成库文件:

osip2.lib

osip2.dll

osipparser2.lib
osipparser2.dll
第三步,解压,编译eXosip
进入libeXosip2-3.6.0\platform\vsnet目录,用VS2010直接打开eXosip.sln文件,项目自动转换:
1.将osip2.lib,osip2.dll,osipparser2.lib,osipparser2.dll拷贝到Debug目录下
2.C/C++ --> 预处理器 --> 预处理器定义: 删除HAVE_OPENSSL_SSL_H
3.C/C++ --> 常规 --> 附加包含目录:     将osip的头文件libosip2-3.6.0\include包含进来

4.编译,生成eXosip.lib

第四步,新建UAC例子项目

1.链接器 --> 输入 --> 附加依赖项:增加静态库引用:Dnsapi.lib;Iphlpapi.lib;Ws2_32.lib;osip2.lib;osipparser2.lib;exosip.lib;
2.C/C++ -->常规 -->附加包含目录: 将osip和eXosip的头文件libosip2-3.6.0\include、libeXosip2-3.6.0\include包含进来

3.链接器 --> 常规  --> 附加库目录:将osip和eXosip的库包含进来,libeXosip2-3.6.0\platform\vsnet\Debug
4.编译UAC代码:

 

#include 
#include
#include
#include
int main(int argc,char *argv[]){ struct eXosip_t *context_eXosip; eXosip_event_t *je; osip_message_t *reg=NULL; osip_message_t *invite=NULL; osip_message_t *ack=NULL; osip_message_t *info=NULL; osip_message_t *message=NULL; int call_id,dialog_id; int i,flag; int flag1=1; char *identity="sip:140@127.0.0.1"; //UAC1,端口是15060 char *registar="sip:133@127.0.0.1:15061"; //UAS,端口是15061 char *source_call="sip:140@127.0.0.1"; char *dest_call="sip:133@127.0.0.1:15061"; //identify和register这一组地址是和source和destination地址相同的 //在这个例子中,uac和uas通信,则source就是自己的地址,而目的地址就是uac1的地址 char command; char tmp[4096]; printf("r 向服务器注册\n\n"); printf("c 取消注册\n\n"); printf("i 发起呼叫请求\n\n"); printf("h 挂断\n\n"); printf("q 推出程序\n\n"); printf("s 执行方法INFO\n\n"); printf("m 执行方法MESSAGE\n\n"); //初始化 i=eXosip_init(); if(i!=0) { printf("Couldn't initialize eXosip!\n"); return -1; } else { printf("eXosip_init successfully!\n"); } //绑定uac自己的端口15060,并进行端口监听 i=eXosip_listen_addr(IPPROTO_UDP,NULL,15060,AF_INET,0); if(i!=0) { eXosip_quit(); fprintf(stderr,"Couldn't initialize transport layer!\n"); return -1; } flag=1; while(flag) { //输入命令 printf("Please input the command:\n"); scanf("%c",&command); getchar(); switch(command) { case 'r': printf("This modal is not completed!\n"); break; case 'i'://INVITE,发起呼叫请求 i=eXosip_call_build_initial_invite(&invite,dest_call,source_call,NULL,"This is a call for conversation"); if(i!=0) { printf("Initial INVITE failed!\n"); break; } //符合SDP格式,其中属性a是自定义格式,也就是说可以存放自己的信息, //但是只能有两列,比如帐户信息 //但是经过测试,格式vot必不可少,原因未知,估计是协议栈在传输时需要检查的 _snprintf(tmp,4096, "v=0\r\n" "o=anonymous 0 0 IN IP4 0.0.0.0\r\n" "t=1 10\r\n" "a=username:rainfish\r\n" "a=password:123\r\n"); 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); //invite SIP INVITE message to send eXosip_unlock(); //发送了INVITE消息,等待应答 flag1=1; while(flag1) { je=eXosip_event_wait(0,200); //Wait for an eXosip event //(超时时间秒,超时时间毫秒) if(je==NULL) { printf("No response or the time is over!\n"); break; } switch(je->type) //可能会到来的事件类型 { case EXOSIP_CALL_INVITE: //收到一个INVITE请求 printf("a new invite received!\n"); break; case EXOSIP_CALL_PROCEEDING: //收到100 trying消息,表示请求正在处理中 printf("proceeding!\n"); break; case EXOSIP_CALL_RINGING: //收到180 Ringing应答,表示接收到INVITE请求的UAS正在向被叫用户振铃 printf("ringing!\n"); printf("call_id is %d,dialog_id is %d \n",je->cid,je->did); break; case EXOSIP_CALL_ANSWERED: //收到200 OK,表示请求已经被成功接受,用户应答 printf("ok!connected!\n"); call_id=je->cid; dialog_id=je->did; printf("call_id is %d,dialog_id is %d \n",je->cid,je->did); //回送ack应答消息 eXosip_call_build_ack(je->did,&ack); eXosip_call_send_ack(je->did,ack); flag1=0; //推出While循环 break; case EXOSIP_CALL_CLOSED: //a BYE was received for this call printf("the other sid closed!\n"); break; case EXOSIP_CALL_ACK: //ACK received for 200ok to INVITE printf("ACK received!\n"); break; default: //收到其他应答 printf("other response!\n"); break; } eXosip_event_free(je); //Free ressource in an eXosip event } break; case 'h': //挂断 printf("Holded!\n"); eXosip_lock(); eXosip_call_terminate(call_id,dialog_id); eXosip_unlock(); break; case 'c': 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': //传输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': eXosip_quit(); printf("Exit the setup!\n"); flag=0; break; } } return(0);}

 

第五步,编译UAS项目:

与UAC同样的设置后,编译

 

 

# include 
# include
# include
# include
int main (int argc, char *argv[]){   eXosip_event_t *je = NULL;   osip_message_t *ack = NULL;   osip_message_t *invite = NULL;   osip_message_t *answer = NULL;   sdp_message_t *remote_sdp = NULL;   int call_id, dialog_id;   int i,j;   int id;   char *sour_call = "sip:140@127.0.0.1";   char *dest_call = "sip:133@127.0.0.1:15060";//client ip   char command;   char tmp[4096];   char localip[128];   int pos = 0;   //初始化sip   i = eXosip_init ();   if (i != 0){   printf ("Can't initialize eXosip!\n");   return -1;}   else{   printf ("eXosip_init successfully!\n");}   i = eXosip_listen_addr (IPPROTO_UDP, NULL, 15061, AF_INET, 0);   if (i != 0){   eXosip_quit ();   fprintf (stderr, "eXosip_listen_addr error!\nCouldn't initialize transport layer!\n");}   for(;;){   //侦听是否有消息到来   je = eXosip_event_wait (0,50);    //协议栈带有此语句,具体作用未知   eXosip_lock ();   eXosip_default_action (je);   eXosip_automatic_refresh ();   eXosip_unlock ();   if (je == NULL)//没有接收到消息continue;   // printf ("the cid is %s, did is %s/n", je->did, je->cid);   switch (je->type){case EXOSIP_MESSAGE_NEW://新的消息到来   printf (" EXOSIP_MESSAGE_NEW!\n");   if (MSG_IS_MESSAGE (je->request))//如果接受到的消息类型是MESSAGE       {   {       osip_body_t *body;       osip_message_get_body (je->request, 0, &body);        printf ("I get the msg is: %s\n", body->body);       //printf ("the cid is %s, did is %s/n", je->did, je->cid);   }   //按照规则,需要回复OK信息   eXosip_message_build_answer (je->tid, 200,&answer);   eXosip_message_send_answer (je->tid, 200,answer);       }   break;case EXOSIP_CALL_INVITE:   //得到接收到消息的具体信息         printf ("Received a INVITE msg from %s:%s, UserName is %s, password is %s\n",je->request->req_uri->host,      je->request->req_uri->port, je->request->req_uri->username, je->request->req_uri->password);   //得到消息体,认为该消息就是SDP格式.   remote_sdp = eXosip_get_remote_sdp (je->did);   call_id = je->cid;   dialog_id = je->did;      eXosip_lock ();   eXosip_call_send_answer (je->tid, 180, NULL);   i = eXosip_call_build_answer (je->tid, 200, &answer);   if (i != 0)       {      printf ("This request msg is invalid!Cann't response!\n");      eXosip_call_send_answer (je->tid, 400, NULL);       }   else       {      snprintf (tmp, 4096,            "v=0\r\n"            "o=anonymous 0 0 IN IP4 0.0.0.0\r\n"            "t=1 10\r\n"            "a=username:rainfish\r\n"            "a=password:123\r\n");            //设置回复的SDP消息体,下一步计划分析消息体      //没有分析消息体,直接回复原来的消息,这一块做的不好。      osip_message_set_body (answer, tmp, strlen(tmp));      osip_message_set_content_type (answer, "application/sdp");            eXosip_call_send_answer (je->tid, 200, answer);      printf ("send 200 over!\n");       }   eXosip_unlock ();      //显示出在sdp消息体中的attribute 的内容,里面计划存放我们的信息   printf ("the INFO is :\n");   while (!osip_list_eol ( &(remote_sdp->a_attributes), pos))       {      sdp_attribute_t *at;            at = (sdp_attribute_t *) osip_list_get ( &remote_sdp->a_attributes, pos);      printf ("%s : %s\n", at->a_att_field, at->a_att_value);//这里解释了为什么在SDP消息体中属性a里面存放必须是两列            pos ++;       }   break;case EXOSIP_CALL_ACK:   printf ("ACK recieved!\n");   // printf ("the cid is %s, did is %s/n", je->did, je->cid);    break;case EXOSIP_CALL_CLOSED:   printf ("the remote hold the session!\n");   // eXosip_call_build_ack(dialog_id, &ack);   //eXosip_call_send_ack(dialog_id, ack);    i = eXosip_call_build_answer (je->tid, 200, &answer);   if (i != 0)       {      printf ("This request msg is invalid!Cann't response!\n");      eXosip_call_send_answer (je->tid, 400, NULL);            }   else       {      eXosip_call_send_answer (je->tid, 200, answer);      printf ("bye send 200 over!\n");       }          break;case EXOSIP_CALL_MESSAGE_NEW://至于该类型和EXOSIP_MESSAGE_NEW的区别,源代码这么解释的/*// request related events within calls (except INVITE)       EXOSIP_CALL_MESSAGE_NEW,          < announce new incoming request. // response received for request outside calls          EXOSIP_MESSAGE_NEW,          < announce new incoming request.          我也不是很明白,理解是:EXOSIP_CALL_MESSAGE_NEW是一个呼叫中的新的消息到来,比如ring trying都算,所以在接受到后必须判断         该消息类型,EXOSIP_MESSAGE_NEW而是表示不是呼叫内的消息到来。         该解释有不妥地方,仅供参考。*/   printf(" EXOSIP_CALL_MESSAGE_NEW\n");   if (MSG_IS_INFO(je->request) ) //如果传输的是INFO方法   {               eXosip_lock ();             i = eXosip_call_build_answer (je->tid, 200, &answer);             if (i == 0)            {               eXosip_call_send_answer (je->tid, 200, answer);            }             eXosip_unlock ();      {       osip_body_t *body;       osip_message_get_body (je->request, 0, &body);       printf ("the body is %s\n", body->body);      }   }   break; default:   printf ("Could not parse the msg!\n");}}}

 

例子已经上传:

运行示意图:

 

你可能感兴趣的文章
链表的各种操作(Java实现)
查看>>
git命令行下怎么查看当前分支是基于哪一个分支的,以决定是否可以执行git rebase...
查看>>
十进制小数的二进制,八进制,十六进制转换方法
查看>>
一整套WordPress模板制作的教程
查看>>
CAP理论
查看>>
js中Element的兼容问题
查看>>
对象访问
查看>>
QWebView中点击链接的处理
查看>>
指针悬挂
查看>>
修改索引从1开始
查看>>
oss挂载迁移操作手册
查看>>
一篇文章搞定前端面试
查看>>
Memcached学习
查看>>
ANT clean ear 字符串错误
查看>>
LINUX下查看CPU使用率的命令
查看>>
两个android通过usb通信
查看>>
查看mysql版本的四种方法
查看>>
找不到NTFS for Mac激活按钮怎么办
查看>>
网页无图再不是梦想
查看>>
html页面比较长,如何用js实现网页一打开显示在网页的中部?
查看>>