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

期间还向CSDN论坛求助了下,但是还没有反应:http://bbs.csdn.net/topics/390499635?page=1#post-394866714

描述: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 <eXosip2/eXosip.h>
#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>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,端口是15060char *registar="sip:133@127.0.0.1:15061"; //UAS,端口是15061char *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 sendeXosip_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 callprintf("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));//假设格式是xmlosip_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 <eXosip2/eXosip.h>
# include <stdio.h>
# include <stdlib.h>
# include <Winsock2.h>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 ipchar command;char tmp[4096];char localip[128];int pos = 0;//初始化sipi = 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");
}
}
}

例子已经上传:http://download.csdn.net/detail/longlong530/5647749

运行示意图:

Windows下编译eXosip、osip,以及UAC和UAS的例子相关推荐

  1. Linux及Windows下编译exosip和osip2源码

    eXosip库及编译流程简介 1.eXosip库的简介 1.1.osip简介 osip2是一个开放源代码的sip协议栈,是开源代码中不多使用C语言写的协议栈之一,它具有短小简洁的特点,专注于sip底层 ...

  2. Windows下编译Chrome V8

    主要还是参考google的官方文档: How to Download and Build V8 Building on Windows 同时也参考了一些其它的中文博客: 脚本引擎小pk:SpiderM ...

  3. Windows下编译 Hadoop

    Windows下编译 Hadoop-2.9.2 系统环境 系统: Windows 10 10.0_x64 maven: Apache Maven 3.6.0 jdk: jdk_1.8.0_201 Pr ...

  4. Windows下编译tensorflow-gpu教程

    这两个也要看: https://zhuanlan.zhihu.com/p/29029860 https://zhuanlan.zhihu.com/p/34942873 Windows下编译tensor ...

  5. Windows下编译TensorFlow1.3 C++ library及创建一个简单的TensorFlow C++程序

    参考:https://www.cnblogs.com/jliangqiu2016/p/7642471.html Windows下编译TensorFlow1.3 C++ library及创建一个简单的T ...

  6. windows下编译支持https的curl

    先编译好openssl,过程详见:<windows下编译openssl> 编译好zlib,过程详见<windows下编译zlib> 1. 下载curl 官网:https://c ...

  7. 在Windows下编译FFmpeg详细说明

    在Windows下编译FFmpeg详细说明 MinGW:一个可自由使用和自由发布的Windows特定头文件和使用GNC工具集导入库的集合,允许你生成本地的Windows程序而不需要第三方C运行时 Mi ...

  8. linux下find查找带有指定权限的文件(windows下编译的源代码文件)

    find -type f -perm -o=x 查找用户在windows下编译的源代码文件 转载于:https://blog.51cto.com/axlrose/1357610

  9. lua windows下编译

    从Lua5.1开始官方给出的文件只有源代码和makefile文件了,官网给出的bulid方式也是在linux平台,如果只是想找个库使用下可以到这里来下载:http://joedf.ahkscript. ...

最新文章

  1. Spider Scrapy 框架爬虫
  2. 迈入JavaWeb第一步,Java网络编程基础,TCP网络编程URL网络编程等
  3. linux bash tutorial
  4. effective C++ 条款 11:在operator= 处理‘自我赋值’
  5. 单板计算机作用上位机,SCB-1单板机的基本操作
  6. iPhone应用炫酷的下拉更新效果
  7. MATLAB完美画图:改变坐标轴刻度的显示数值,常数函数的作图
  8. TTL接口笔记本液晶屏改液晶显示器
  9. 使用nsis制作的安装包安装后,无法卸载干净的问题
  10. 风火家人:避风港湾;火泽暌:求同存异
  11. 【Python】如何利用python对c程序源码进行协助解读(学会事半功倍)
  12. 1265 最近公共祖先
  13. c语言如何标志置1与置0,c语言对于文本的基本操作
  14. perl Carp模块使用举例(转)
  15. 调用支付宝第三方接口(沙箱环境) Spring Boot+Maven
  16. 树莓派播放音频时3.5mm接口没有声音怎么办?
  17. weblogic部署前后端分离项目
  18. 请尝试写一个验证Email地址的正则表达式。版本一应该可以验证出类似的Email —— python学习笔记
  19. BOM浏览器对象模型(brower object model)
  20. cmd格式化(重置)磁盘/U盘的方法

热门文章

  1. 酷炫好玩又实用 | 可能是CES上六个最值得买的电子产品
  2. 怎么将文字转换成语音?
  3. Spring boot工程创建
  4. FTP服务器的搭建及创建虚拟用户进行认证访问
  5. weka特征选择源码阅读
  6. apache通过rewrite限制某个目录
  7. Cent OS 重置root密码
  8. spring mvc tutorial
  9. #import和@class 的区别
  10. 精确打印程序的运行时间