sip网络电话
sip网络电话,经过了一个月的时间,终于把网络电话做出来了,其实功能也不是很完善,不过正常沟通是没有问题的,想把这一个月所学的东西都记录下来,分享给大家,也留给自己。
我是一个即将毕业的学生,来北京找工作,找到了一个公司,比较小,在实习阶段老板让我作这个sip的网络电话,刚开始就觉得莫名其妙,一个新来的,什么都没学过,就做sip,我连什么是sip都不知道,可是没办法,金融危机,工作不好找,有个工作就干吧,而且这个公司跟我学的专业也挺对口的(嵌入式),不过眼前的这个任务确实有点偏。
刚开始就在网上找这方面的资料,一点一点学,慢慢的了解,想想第一天知道网络电话要先注册的时候就挺好笑的。我的想法就是现在网上找找这方面的资源,然后再找个QQ群去沟通,如果有人带,那就会很快的完成任务阿。
我加过一个QQ群,高手很多,我是菜鸟,很多人都不屑理睬我,追着人家文问题的时候确实很让人烦,时间长了,老在群里面问问题,就说不定会惹到谁,也因为这个闹了一点小矛盾,最后退群了。
在学习的过程中得到过很多人的帮助,在这里谢谢 颓废 heeb osip(QQ名字,我在群里面的名字叫小饭团)等,还有很多人,不好意思,记不请了,对我的帮助都很大的。
言归正传开始说事儿:
首先要配置环境,需要这么几个库,libosip,libeXosip2,ortp,mediastreamer2.
libosip,libeXosip2这两个库是负责信令部分的,ortp,medastreamer2是负责媒体流传输的。如果想了解更多的关于这些库方面的信息,可以去网上搜索,会有很多相关的信息,总之学习不要怕麻烦。是师傅令进门,修行在个人。学习sip要看rfc3261 3265 3550 4353 ,还有eXosip,osip,ortp,mediastreamer2的帮助手册等。资料多了才好学习嘛。
sipAPI:http://www.gnu.org/software/osip/doc/html/group__oSIP__MESSAGE.html
eXosipAPI:http://www.antisip.com/doc/exosip2/group__eXosip2__sdp.html#gdab1e84d04b387ada72e0d548444f3c0
ortpAPI:http://download.savannah.gnu.org/releases-noredirect/linphone/ortp/docs/ortp_8h.html
mediastreamerAPI:http://www.antisip.com/doc/mediastreamer2/mscommon_8h.html
以上紧紧作为参考,并不是很全,如果想细细的研究分析,建议自己去看源码。哈,虽然会很累,但是效果很好
下面这段是注册代码:
- #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>
- // ip_url 为服务器ip,
- int myregister(char *ip_url,char *port,char *username,char * password)
- {
- int i;
- char identity[50];
- char registerer[50];
- char localip[128];
- static int flag = 0;
- int id;
- eXosip_guess_localip (AF_INET, localip, 128);
- sprintf(identity,"sip:%s@%s",username,localip);
- sprintf(registerer,"sip:%s:%s",ip_url,port);
- //初始化
- if( flag == 0)
- {
- i = eXosip_init();
- if (i != 0)
- {
- return -1;
- }
- printf("eXosip_init success/n");
- flag ++;
- i = eXosip_listen_addr(IPPROTO_UDP, NULL, 5060, AF_INET, 0);
- if (i != 0)
- {
- eXosip_quit();
- fprintf(stderr, "could not initialize transport layer/n");
- return -1;
- }
- printf("eXosip_listen_addr success/n");
- }
- osip_message_t *reg = NULL;
- eXosip_lock();
- id = eXosip_register_build_initial_register (identity,registerer, NULL, 1800, ®);
- printf("id = %d", id);
- if (id < 0)
- {
- eXosip_unlock();
- fprintf (stderr, "eXosip_register_build_initial_register failed:(bad arguments?)/n");
- return 0;
- }
- eXosip_lock();
- i = eXosip_register_send_register(id, reg);
- if (i != 0)
- {
- fprintf (stderr, "eXosip_register_send_register failed: (bad arguments?)/n");
- return 0;
- }
- eXosip_unlock ();
- printf("eXosip_register_send_register OK/n");
- eXosip_event_t *je;
- for (;;)
- {
- je = eXosip_event_wait (0, 50);
- eXosip_lock();
- eXosip_automatic_action ();
- eXosip_unlock();
- if (je == NULL)
- {
- continue;
- }
- if (je->type == EXOSIP_REGISTRATION_SUCCESS)
- {
- printf("textinfo is %s/n", je->textinfo);
- return 1;
- break;
- }
- if(je->type == EXOSIP_REGISTRATION_FAILURE)
- {
- //注册失败之后,再次提交授权信息, 也可放在上面
- eXosip_add_authentication_info(username, username,password, NULL, NULL);
- }
- if(je->type == EXOSIP_REGISTRATION_REFRESHED)
- {
- printf("refreshed");
- return 0;
- }
- }
- eXosip_quit();
- }
ps:注册其实挺简单的,代码是用eXosip实现的,帮助手册上面都有,只要细细分析就能看明白,网上有pdf版本的,csdn上也有,英文的。
继续,下面这段是拨号的代码:
- #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>
- int call(char *telNum)
- {
- eXosip_event_t *je;
- osip_message_t *invite = NULL;
- osip_message_t *ack = NULL;
- // int call_id, dialog_id;
- int i,flag;
- char tmp[4096];
- char localip[128];
- char source_call[100];
- char dest_call[100];
- sprintf(source_call,"sip:%s@%s:%s",s_username,s_ip,s_port);
- sprintf(dest_call,"sip:%s@%s:%s",telNum,s_ip,s_port);
- i = eXosip_call_build_initial_invite (&invite, dest_call, source_call, NULL, "This si a call for a conversation");
- if (i != 0)
- {
- printf ("Intial INVITE failed!/n");
- return -1;
- }
- eXosip_guess_localip (AF_INET, localip, 128);
- snprintf (tmp, 4096,
- "v=0/r/n"
- "o=josua 0 0 IN IP4 %s/r/n"
- "s=conversation/r/n"
- "c=IN IP4 %s/r/n"
- "t=0 0/r/n"
- "m=audio %s 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-11/r/n", localip, localip, "9900");
- 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 ();
- flag = 1;
- while (flag)
- {
- je = eXosip_event_wait (0, 200);
- if (je == NULL)
- {
- printf ("No response or the time is over!/n");
- break;
- }
- eXosip_lock ();
- eXosip_default_action(je);
- eXosip_unlock ();
- switch (je->type)
- {
- case EXOSIP_CALL_INVITE:
- printf ("a new invite reveived!/n");
- break;
- case EXOSIP_CALL_PROCEEDING:
- printf ("proceeding!/n");
- call_id = je->cid;
- break;
- case EXOSIP_CALL_RINGING:
- printf ("ringing!/n");
- printf ("call_id is %d, dialog_id is %d /n", je->cid, je->did);
- break;
- case EXOSIP_CALL_ANSWERED:
- 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);
- eXosip_call_build_ack (je->did, &ack);
- eXosip_call_send_ack (je->did, ack);
- break;
- case EXOSIP_CALL_CLOSED:
- printf ("the other sid closed!/n");
- return -1;//对方挂断
- break;
- case EXOSIP_CALL_ACK:
- printf ("ACK received!/n");
- break;
- default:break;
- }
- eXosip_event_free (je);
- }
- return 0;
- }
ps: 初学者可能不了解格式,所以程序会调不通,学的不好给大家随便说一下,别见怪阿。
- sprintf(source_call,"sip:%s@%s:%s",s_username,s_ip,s_port);
- sprintf(dest_call,"sip:%s@%s:%s",telNum,s_ip,s_port);
- i = eXosip_call_build_initial_invite (&invite, dest_call, source_call, NULL, "This si a call for a conversation");
用户名: 77001234
密码: 987654321
要呼叫的号码:12340602252
服务器ip:192.168.8.24
端口:5060
》》 source_call为 77001234@192.168.8.24:5060
》》 dest_call 为 12340602252@192.168.8.24:5060
密码没有涉及到,因为注册的时候已经提供密码