版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/zzqgtt/article/details/87179815
1、已经编译生成号exosip相关库,

2、复制如下代码生成UAC,该实例使用的是windows控制台程序,对于sdp的解析部分需修改一下

代码如下:

#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@192.168.0.115";   //UAC1,端口是15060char *registar = "sip:133@192.168.0.115:15061"; //UAS,端口是15061char *source_call = "sip:140@192.168.0.115";char *dest_call = "sip:814@192.168.0.103: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");//初始化struct eXosip_t *excontext;excontext = eXosip_malloc();i = eXosip_init(excontext);if (i != 0){printf("Couldn't initialize eXosip!\n");osip_free(excontext);return -1;}else{printf("eXosip_init successfully!\n");}//绑定uac自己的端口15060,并进行端口监听i = eXosip_listen_addr(excontext, IPPROTO_UDP, NULL, 15060, AF_INET, 0);if (i != 0){eXosip_quit(excontext);fprintf(stderr, "Couldn't initialize transport layer!\n");osip_free(excontext);return -1;}flag = 1;while (flag){//输入命令printf("Please input the command:\n");scanf_s("%c", &command);getchar();switch (command){case 'r':printf("This modal is not completed!\n");break;case 'i'://INVITE,发起呼叫请求i = eXosip_call_build_initial_invite(excontext, &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_s(tmp, 4096,"v=0\r\n""o=anonymous 0 0 IN IP4 0.0.0.0\r\n""t=0 0\r\n""m=audio 62100 RTP/AVP 114 0 8 101\r\n""a=rtpmap:114 AMR/8000\r\n""a=fmtp:114 octet-align=1;mode-set=7,0\r\n""a=rtpmap:0 PCMU/8000\r\n""a=rtpmap:8 PCMA/8000\r\n""m=video 62102 RTP/AVP 102 99\r\n""a=rtpmap:102 H264/90000\r\n""a=rtpmap:99 MP4V-ES/90000\r\n");osip_message_set_body(invite, tmp, strlen(tmp));osip_message_set_content_type(invite, "application/sdp");eXosip_lock(excontext);i = eXosip_call_send_initial_invite(excontext, invite); //invite SIP INVITE message to sendeXosip_unlock(excontext);//发送了INVITE消息,等待应答flag1 = 1;while (flag1){je = eXosip_event_wait(excontext, 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(excontext, je->did, &ack);eXosip_call_send_ack(excontext, 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(excontext);eXosip_call_terminate(excontext, call_id, dialog_id);eXosip_unlock(excontext);break;case 'c':printf("This modal is not commpleted!\n");break;case 's': //传输INFO方法eXosip_call_build_info(excontext, dialog_id, &info);_snprintf_s(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(excontext, dialog_id, info);break;case 'm'://传输MESSAGE方法,也就是即时消息,和INFO方法相比,我认为主要区别是://MESSAGE不用建立连接,直接传输信息,而INFO消息必须在建立INVITE的基础上传输printf("the method : MESSAGE\n");eXosip_message_build_request(excontext, &message, "MESSAGE", dest_call, source_call, NULL);//内容,方法,      to       ,from      ,route_snprintf_s(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(excontext, message);break;case 'q':eXosip_quit(excontext);printf("Exit the setup!\n");flag = 0;break;}}osip_free(excontext);return(0);
}

invite sdp 格式参照如下:

INVITE sip:609099@10.4.54.2:5060 SIP/2.0
Via: SIP/2.0/UDP 10.4.46.1:49552;rport;branch=z9hG4bK2032385714
From: <sip:8006@10.4.46.1:49552>;tag=1798441523
To: <sip:609099@10.4.54.2:5060>
Call-ID: 3012165000
CSeq: 21 INVITE
Contact: <sip:8006@10.4.46.1:49552>
Proxy-Authorization: Digest username="8006", realm="BCC", nonce="0af1a282e6687dc7fe2442989bf23ea4", uri="sip:609099@10.4.54.2:5060", response="51f136f0c58570397ba1b94c256d12b9", algorithm=MD5
Content-Type: application/sdp
Call-Info: <witen:609099>;type=videoupload;fmt=D1/CIF/QCIF;camera=1;user_confirm=0;mute=1
Max-Forwards: 70
User-Agent: #SDK Console 3.0
Subject: ## Dispatch Console!
Content-Length:   307

v=0
o=DConsole 1 1 IN IP4 10.4.46.1
s=##DConsole demo
c=IN IP4 10.4.46.1
t=0 0
m=audio 62100 RTP/AVP 114 0 8 101
a=rtpmap:114 AMR/8000
a=fmtp:114 octet-align=1;mode-set=7,0
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
m=video 62102 RTP/AVP 102 99
a=rtpmap:102 H264/90000
a=rtpmap:99 MP4V-ES/90000

3、复制如下代码生成UAS,该实例使用的是windows控制台程序,对于sdp的解析部分需修改一下,请参照音频的获取方式修改视频sdp解析代码。

代码如下:

# 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@192.168.0.115";char *dest_call = "sip:133@192.168.0.115:15060";//client ipchar command;char tmp[4096];char localip[128];int pos = 0;//初始化sipstruct eXosip_t *excontext;excontext = eXosip_malloc();i = eXosip_init(excontext);if (i != 0){printf("Can't initialize eXosip!\n");return -1;}else{printf("eXosip_init successfully!\n");}i = eXosip_listen_addr(excontext, IPPROTO_UDP, NULL, 15061, AF_INET, 0);if (i != 0){eXosip_quit(excontext);fprintf(stderr, "eXosip_listen_addr error!\nCouldn't initialize transport layer!\n");}for (;;){//侦听是否有消息到来je = eXosip_event_wait(excontext, 0, 50);//协议栈带有此语句,具体作用未知eXosip_lock(excontext);eXosip_default_action(excontext, je);//eXosip_automatic_refresh();eXosip_automatic_action(excontext);eXosip_unlock(excontext);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(excontext, je->tid, 200, &answer);eXosip_message_send_answer(excontext, 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(excontext, je->did);call_id = je->cid;dialog_id = je->did;eXosip_lock(excontext);eXosip_call_send_answer(excontext, je->tid, 180, NULL);i = eXosip_call_build_answer(excontext, je->tid, 200, &answer);if (i != 0){printf("This request msg is invalid!Cann't response!\n");eXosip_call_send_answer(excontext, je->tid, 400, NULL);}else{_snprintf_s(tmp, 4096,"v=0\r\n""o=anonymous 0 0 IN IP4 0.0.0.0\r\n""t=1 10\r\n");//设置回复的SDP消息体,下一步计划分析消息体//没有分析消息体,直接回复原来的消息,这一块做的不好。osip_message_set_body(answer, tmp, strlen(tmp));osip_message_set_content_type(answer, "application/sdp");eXosip_call_send_answer(excontext, je->tid, 200, answer);printf("send 200 over!\n");}eXosip_unlock(excontext);//显示出在sdp消息体中的attribute 的内容,里面计划存放我们的信息printf("the INFO is :\n");//sdp_media_t *connection = eXosip_get_audio_media(remote_sdp);//if (!connection)// return false;//char*  audio_ip = connection->c_addr; //audio_ipsdp_media_t * audio_sdp = eXosip_get_audio_media(remote_sdp);if (!audio_sdp)return false;char* audio_port = audio_sdp->m_port; //audio_portfor (int i = 0; i < audio_sdp->a_attributes.nb_elt; i++){sdp_attribute_t *attr = (sdp_attribute_t*)osip_list_get(&audio_sdp->a_attributes, i);printf("%s : %s\n", attr->a_att_field, attr->a_att_value);}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++;}while (!osip_list_eol(&(remote_sdp->m_medias), pos)){sdp_attribute_t *at;at = (sdp_attribute_t *)osip_list_get(&remote_sdp->m_medias, 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(excontext, je->tid, 200, &answer);if (i != 0){printf("This request msg is invalid!Cann't response!\n");eXosip_call_send_answer(excontext, je->tid, 400, NULL);}else{eXosip_call_send_answer(excontext, 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 callsEXOSIP_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(excontext);i = eXosip_call_build_answer(excontext, je->tid, 200, &answer);if (i == 0){eXosip_call_send_answer(excontext, je->tid, 200, answer);}eXosip_unlock(excontext);{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");}}
}

UAS 回复的sdp 格式请参照

SIP/2.0 200 OK
Via: SIP/2.0/UDP 10.4.46.1:49552;rport=49552;branch=z9hG4bK2032385714
From: <sip:8006@10.4.46.1:49552>;tag=1798441523
To: <sip:609099@10.4.54.2:5060>;tag=229035134
Call-ID: 3012165000
CSeq: 21 INVITE
Contact: <sip:609099@10.4.54.2:5060>
Content-Type: application/sdp
Call-Info: <witen:609099>;src_vpn_out=0;type=videoupload;fmt=D1;camera=1;user_confirm=9;mute=1;emergency_callInd=0;priority=5
User-agent: BCC/3.0
Content-Length:   215

v=0
o=B2BUA 1 1 IN IP4 10.4.54.2
s=BCC Switch
c=IN IP4 10.4.54.2
t=0 0
m=audio 26438 RTP/AVP 114
a=rtpmap:114 AMR/8000
a=fmtp:114 octet-align=1;mode-set=7
m=video 26442 RTP/AVP 102
a=rtpmap:102 H264/90000

4、以上程序的ip请修改成自己实际电脑的ip,根据UAC和UAS协商好的端口即可进行收流解析播放。

5、有问题可以给我留言 一起探讨。

————————————————
版权声明:本文为CSDN博主「zzqgtt」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/zzqgtt/article/details/87179815

基于exosip 编写呼叫流程实例相关推荐

  1. 基于价值链的流程框架分类_基于价值的类

    基于价值链的流程框架分类 在Java 8中,某些类在Javadoc中有一个小注释,说明它们是基于值的类 . 其中包括简短说明的链接,以及有关不使用它们的限制. 这很容易被忽略,如果这样做,则可能会在将 ...

  2. mule esb java实例_基于AnypointStudio IDE开发MuleESB实例

    基于AnypointStudio IDE开发MuleESB实例 本文部分内容引用https://www.cnblogs.com/enjoyingsoft/p/10132360.html,在此,对原著作 ...

  3. 网络与通信程序设计-基于UDP的广播通信实例

    目录 实验内容和设计思想 实验的内容 UDP的设计思想 UDP的协议头部 UDP通信编程思想 UDP的工作流程 UDP编程收发函数 广播通信 广播模式设置 广播套接字 UDP Socket的使用过程 ...

  4. 用python写脚本筛选原创微博_基于python编写的微博应用

    本文实例讲述了基于python编写的微博应用,分享给大家供大家参考.具体如下: 在编写自己的微博应用之前,先要到weibo开放平台申请应用的公钥和私钥. 下载python版的SDK,打开example ...

  5. php使用redis分布式锁,php基于redis的分布式锁实例详解

    在使用分布式锁进行互斥资源访问时候,我们很多方案是采用redis的实现. 固然,redis的单节点锁在极端情况也是有问题的,假设你的业务允许偶尔的失效,使用单节点的redis锁方案就足够了,简单而且效 ...

  6. (绝对正确)Zabbix基于lamp的安装流程

    目录 Zabbix基于lamp的安装流程... 1 1安装Mysql... 1 先安装相关的库和工具... 1 Mysql的安装... 1 2httpd的安装... 2 先安装相关的库和工具... 2 ...

  7. Activiti第二篇【管理流程定义、执行任务和流程实例、流程变量】

    tags: Activiti 上篇Activiti只是一个快速入门案例,这篇就讲定义.部署.查看任务等等的一些细节[涉及到的数据库表.对象等等]... 管理流程定义 管理流程定义主要涉及到以下的4张表 ...

  8. live555的安装 RTSP点播消息流程实例(客户端:VLC, RTSP服务器:LIVE555 Media Server)

    live555是一个开源的软件,主要用来生成rtsp,rtp和sip服务器和客户端的软件.前几天需要看一下vlc中的rtsp的功能,在vlc中 rtp和rtsp的功能都是使用live555中的函数来生 ...

  9. 电子元器件B2B商城系统开发:赋能企业构建进销存标准化流程实例

    经过多年的发展,我国已成为全球最大的电子制造基地,同时,也有着强大的电子元器件产业链作为支撑,具备独一无二的优势.而随着线上交易的兴起与国产半导体的崛起,我国电子供应链领域中元器件电商已是大势所趋,发 ...

  10. 星星之火-10:移动通信中的用户标识大汇总以及在手机呼叫流程中的使用--MSISDN,MSRN,IMSI,TMSI,PCI, CGI

    引言: 在移动通信中,会用到各种标识终端的标识号, 如MSISDN,MSRN,IMSI, TMSI, LMSI, P-TMIS,IMEI, 这些标识号有着不同的用途. 为了简化流程,本文以GSM为例, ...

最新文章

  1. 使用 HttpResponse.Write 方法进行字符串串联
  2. html加载less,javascript – 动态加载less.js规则
  3. 一个Linux下的 俄罗斯方块游戏,基于 ncurse 库。。
  4. PCB板设计的12个细节,你做对了吗?
  5. [渝粤题库]西北工业大学统计学
  6. [html] 页面刷新时sessionStroage会变(会清空)吗?
  7. 新版JupyterLab快捷键+调试技巧(建议收藏)
  8. 多线程的那点事儿(之数据互斥)
  9. 米斯特白帽培训讲义(v2)实战篇 捷达系统
  10. zabbix监控Nginx/Tomcat/MySQL
  11. 基于留一法的快速KNN代码
  12. Java基础——详尽说明try-catch-finally的用法
  13. C#中is、as以及强制转换之间区别
  14. linux系统中看视频,怎么在linux里看视频啊?
  15. 【lizhi125】比Nero更好用的免费小巧的光盘刻录软件——ImgBurn(中文版)
  16. 端口错误 给Arduino下载程序提示
  17. 从重大事件保障,看华为如何打造一流保障体系
  18. 爬虫--网络数据采集
  19. 国家虚拟仿真实验教学项目共享平台(实验空间)PHP SDK
  20. html颜色奶白色,象牙白rgb值是多少 和乳白哪个更白

热门文章

  1. python 字符串转字节_【转】python中的字符串和字节串
  2. Windows10下载CUDA总是下载失败的解决方案
  3. mysql导出数据到csv文件
  4. ExtJs6 combo下拉框分页、提示、换行提示等增强功能
  5. c语言求最大质数,【C语言】求解素数(质数)的N种境界
  6. python-常见的语法错误
  7. matlab 博弈论代码,各种博弈论详解(示例代码)
  8. 数据库实验报告1数据库定义实验
  9. mybatis插件助手的使用
  10. 【货干】Idea 安装 MyBatis 插件