基于eXosip的SIP客户端

SipContact.h:

#ifndef _SIP_CONTACT_H_
#define _SIP_CONTACT_H_

#include "SoftPhoneDataDef.h"
#include <eXosip2/eXosip.h>

class CSipContact
{
   
public:
	CSipContact(void);
	~CSipContact(void);

public:
	void Start();
private:
	//注册操作
	eXosip_event_type_t Registeration(int nLisPort,int expires);
public:
	//取消注册操作
	eXosip_event_type_t UnRegisteration();
	//发起呼叫
	int Invite(const char* destUserid);
	//接听
	void Answer();
	//挂断
	void Hold();
	//退出
	void Exit();
private:
	struct UserMrg m_sUser;//登录用户
	int m_nAdTrPort; //音频传输端口
	//int nCall_id;	//呼叫id
	//int nDlg_id;	//回话id
};

#endif

SipContact.cpp:

#include "SipContact.h"
#include <winsock2.h>
#include <osip2/osip_mt.h>
#include <osip2/osip.h>
#include <osipparser2/osip_message.h>
#include <osipparser2/osip_parser.h>
#include <osipparser2/osip_md5.h>
#include <eXosip2/eX_call.h>
#include "jcalls.h"

static int m_nCall_id = -1;	//呼叫id
static int m_nDlg_id = -1;	//绘话id
static int m_nt_id = -1;	

void invite_answer()
{
   
	sdp_message_t *remote_sdp = NULL; 
	osip_message_t *answer = NULL; 
	char tmp[4096]; 
	char localip[128]; 
	int pos = 0;     //初始化sip   

	if (-1 == m_nt_id)
	{
   
		return;
	}

	remote_sdp = eXosip_get_remote_sdp (m_nt_id);  
	eXosip_lock ();        
	//eXosip_call_send_answer (m_nt_id, 180, NULL);       
	int i = eXosip_call_build_answer (m_nt_id, 200, &answer);       
	if (i != 0)         
	{
               
		printf ("This request msg is invalid!Cann't response!\n");           
		eXosip_call_send_answer (m_nt_id, 400, NULL);         
	}      
	else         
	{
             	
		eXosip_guess_localip (AF_INET, localip, 128); // 获取本地IP
		//SDP格式
		snprintf (tmp, 4096,
			"v=0\r\n"
			"o=josua 0 0 IN IP4 %s\r\n"// 用户名、ID、版本、网络类型、地址类型、IP地址 
			"s=conversation\r\n" 
			"t=0 0\r\n"
			"a=username:%s\r\n"
			"a=password:%s\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-11\r\n",
			localip,remote_sdp->o_username,remote_sdp->o_addr,2056);           
		osip_message_set_body (answer, tmp, strlen(tmp));            
		osip_message_set_content_type (answer, "application/sdp"); 
		eXosip_call_send_answer (m_nt_id, 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 ++;         
	} 
}

int josua_event_get()
{
   
	int counter = 0;
	/* use events to print some info */
	eXosip_event_t *je;
	osip_message_t *ack = NULL;
	osip_message_t *answer = NULL; 

	for (;;)
	{
   
		je = eXosip_event_wait (0, 50);
		eXosip_lock ();
		
		eXosip_default_action (je);
		eXosip_automatic_refresh ();
		
		eXosip_unlock ();
		if (je == NULL)
			break;
		counter++;

		switch(je->type)
		{
   
		case EXOSIP_MESSAGE_NEW://新的消息到来       
			printf ("EXOSIP_MESSAGE_NEW!\n");  
			eXosip_lock ();
			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);       
			}        //按照规则,需要回复200 OK信息        
			eXosip_message_build_answer (je->tid, 200,&answer);       
			eXosip_message_send_answer (je->tid, 200,answer);   
			eXosip_unlock ();
			break;  

		case EXOSIP_REGISTRATION_SUCCESS:// 注册成功
			printf("EXOSIP_REGISTRATION_SUCCESS\n");
			printf("je->rid=%d\n", je->rid);
			break;

		case EXOSIP_REGISTRATION_FAILURE:// 注册失败
			printf("EXOSIP_REGISTRATION_FAILURE\n");
			printf("je->rid=%d\n", je->rid);

			call_serverfailure(je);
			break;

		case EXOSIP_CALL_INVITE:
			//printf ("a new invite reveived!\n");
			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格式.   
			m_nt_id = je->tid;			     
			m_nCall_id = je->cid;
			m_nDlg_id = je->did;              
			printf ("call_id is %d, dialog_id is %d \n", je->cid, je->did);  
			/*eXosip_lock ();        
			eXosip_call_send_answer (m_nt_id, 180, NULL);  
			eXosip_unlock (); */

			call_new (je);//
			//invite_answer();
			break;

		case EXOSIP_CALL_PROCEEDING:
			printf ("proceeding!\n");

			call_proceeding (je);//
			break;

		case EXOSIP_CALL_RINGING:
			printf ("ringing!\n");
			printf ("call_id is %d, dialog_id is %d \n", je->cid, je->did);

			call_ringing(je);//
			break;

		case EXOSIP_CALL_ANSWERED:
			printf ("ok! connected!\n");
			m_nCall_id = je->cid;
			m_nDlg_id = je->did;
			printf ("call_id is %d, dialog_id is %d \n", je->cid, je->did);

			call_answered(je);//
			//eXosip_call_build_ack (je->did, &ack);
			//eXosip_call_send_ack (je->did, ack);
			break;

		case EXOSIP_CALL_NOANSWER:
			printf ("no answer!\n");
			break;

		case EXOSIP_CALL_CLOSED:
			printf ("the other sid closed!\n");
			/*{
				int 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");         
				} 
			}*/
			call_closed (je);//
			break;

		case EXOSIP_CALL_ACK:
			printf ("ACK received!\n");

			call_ack(je);//
			break;

		case EXOSIP_CALL_REQUESTFAILURE:
			printf ("%s\n",je->textinfo);

			call_requestfailure (je);
			break;

		case EXOSIP_CALL_RELEASED:
			printf ("%s\n",je->textinfo);

			call_closed (je);//
			break;

		default:
			printf ("other response!\n");
			break;
		}
		
		eXosip_event_free (je);
    }
	
	if (counter > 0)
		return 0;
	
	return -1;
}

//事件监听线程
DWORD WINAPI EventThread(LPVOID pParam)
{
   
	while(true)
	{
   
		josua_event_get();
	}
}

CSipContact::CSipContact(void)
{
   
	strcpy_s(m_sUser.chServerIP,"172.23.50.184");
	strcpy_s(m_sUser.chUserName,"waaaa");
	strcpy_s(m_sUser.chUserId,"6666");
	strcpy_s(m_sUser.chUserPwd,"123456");
	m_sUser.unServerPort = 5060;
	m_nAdTrPort = 2056;	
	//nCall_id = -1;
	//nDlg_id = -1;
}

CSipContact::~CSipContact(void)
{
   
	//Exit();
}

//注册操作
eXosip_event_type_t CSipContact::Registeration(int nLisPort,int expires)
{
   
	//初始化环境
	if (eXosip_init ()) {
   
		printf("eXosip_init failed\n");

		return EXOSIP_REGISTRATION_TERMINATED;
	}

	int i = eXosip_listen_addr (IPPROTO_UDP, NULL, nLisPort, AF_INET, 0);
	if (i!=0) {
   
		eXosip_quit();
		printf("could not initialize transport layer\n");

		return EXOSIP_REGISTRATION_TERMINATED;
	}

	//鉴权
	eXosip_clear_authentication_info();
	if (eXosip_add_authentication_info
		(m_sUser.chUserName, m_sUser.chUserId, m_sUser.chUserPwd, NULL, NULL))
	{
   
		return EXOSIP_REGISTRATION_TERMINATED;
	}

	//接收线程
	HANDLE pEventThread;
	DWORD  nEventThreadID;

	pEventThread = ::CreateThread(NULL,0,
		EventThread, NULL, 0, &nEventThreadID); 

	int ret=0;
	osip_message_t *reg = NULL;
	char *from;
	char *proxy;
	proxy = (char*)malloc(100);
	from = (char*)malloc(100);
	sprintf(from, "sip:%s@%s", m_sUser.chUserId, m_sUser.chServerIP);
	sprintf(proxy, "sip:%s:%d", m_sUser.chServerIP, m_sUser.unServerPort);

	eXosip_lock ();
	int reg_id = eXosip_register_build_initial_register(from, proxy, NULL,expires,&reg);
	if (reg_id< 0)
	{
   
		eXosip_unlock();
		eXosip_quit();
		printf("could not initialize register\n");

		return EXOSIP_REGISTRATION_TERMINATED;
	}

	ret = eXosip_register_send_register (reg_id, reg);
	eXosip_unlock ();
	if ( ret != 0)
	{
   
		printf("eXosip_register_send_register error!\n");
		free(from);
		free(proxy);

		return EXOSIP_REGISTRATION_TERMINATED;
	}
	else printf("eXosip_register_send_register success!\n");

	free(proxy);
	free(from);
	return EXOSIP_REGISTRATION_SUCCESS;
}

//发起呼叫
int CSipContact::Invite(const char* destUserid)
{
   
	osip_message_t *invite = NULL;
	char localip[128];
	char tmp[4096];
	char *source_call;
	char *dest_call;

	source_call = (char*)malloc(100);
	dest_call = (char*)malloc(100);
	sprintf(source_call, "sip:%s@%s", m_sUser.chUserId, m_sUser.chServerIP);
	sprintf(dest_call, "sip:%s@%s", destUserid, m_sUser.chServerIP);

	int 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;
	}
	osip_message_set_supported (invite, "100rel");  
	eXosip_guess_localip (AF_INET, localip, 128); // 获取本地IP
	//SDP格式
	snprintf (tmp, 4096,
		"v=0\r\n"
		"o=josua 0 0 IN IP4 %s\r\n"// 用户名、ID、版本、网络类型、地址类型、IP地址 
		"s=conversation\r\n" 
		"t=0 0\r\n"
		"a=username:%s\r\n"
		"a=password:%s\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-11\r\n",
		localip,m_sUser.chUserName,m_sUser.chUserPwd,m_nAdTrPort);    

	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 ();

	return 0;
}

void CSipContact::Start()
{
   
	if (EXOSIP_REGISTRATION_TERMINATED == Registeration(5060,1800))
	{
   
		printf("eXosip register terminated!\n");
	}
}

//挂断
void CSipContact::Hold()
{
   
	printf ("Holded !\n");
	eXosip_lock ();
	eXosip_call_terminate (m_nCall_id, m_nDlg_id);
	eXosip_unlock ();
}

//退出
void CSipContact::Exit()
{
   
	eXosip_quit ();
	printf ("Exit the setup!\n");
}

//接听
void CSipContact::Answer()
{
   
	invite_answer();
}

//取消注册操作
eXosip_event_type_t CSipContact::UnRegisteration()
{
   
	int ret=0;
	osip_message_t *reg = NULL;
	char *from;
	char *proxy;
	proxy = (char*)malloc(100);
	from = (char*)malloc(100);
	sprintf(from, "sip:%s@%s", m_sUser.chUserId, m_sUser.chServerIP);
	sprintf(proxy, "sip:%s:%d", m_sUser.chServerIP, m_sUser.unServerPort);

	eXosip_lock ();
	int reg_id = eXosip_register_build_initial_register(from, proxy, NULL,0,&reg);
	if (reg_id< 0)
	{
   
		eXosip_unlock();
		eXosip_quit();
		printf("could not initialize register\n");

		return EXOSIP_REGISTRATION_TERMINATED;
	}

	ret = eXosip_register_send_register (reg_id, reg);
	eXosip_unlock ();
	if ( ret != 0)
	{
   
		printf("eXosip_register_send_register error!\n");
		free(from);
		free(proxy);

		return EXOSIP_REGISTRATION_TERMINATED;
	}
	else printf("eXosip_register_send_register success!\n");

	free(proxy);
	free(from);
	return EXOSIP_REGISTRATION_SUCCESS;
}

wave音频采集与播放及G729a的编解码:

/*
 * josua - Jack's open sip User Agent
 *
 * Copyright (C) 2002,2003   Aymeric Moizard <jack@atosc.org>
 *
 * This is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2,
 * or (at your option) any later version.
 *
 * This is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with dpkg; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include "jcalls.h"
#include "sdptools.h"
#include <osip2/osip_mt.h>
#ifdef WIN32
#include <windows.h>
#include <mmsystem.h>
#include <mmreg.h>
#include <msacm.h>
#pragma comment(lib, "Winmm.lib") 

WAVEFORMATEX wfx;

#define MAX_IN_BUFFERS 32
#define USED_IN_BUFFERS 6
#define MAX_OUT_BUFFERS 32
#define USED_OUT_BUFFERS 32

unsigned int waveoutDeviceID = WAVE_MAPPER;
WAVEHDR waveHdrOut[MAX_OUT_BUFFERS];
HWAVEOUT hWaveOut;
char dataBufferOut[MAX_OUT_BUFFERS][3200];
unsigned int waveinDeviceID = WAVE_MAPPER;
HWAVEIN hWaveIn;
WAVEHDR waveHdrIn[MAX_IN_BUFFERS];
char dataBufferIn[MAX_IN_BUFFERS][3200];

call_t *current_call = NULL;

extern "C" void va_g729a_init_encoder();
extern "C" void va_g729a_encoder(short *speech, unsigned char *bitstream);
extern "C" void va_g729a_init_decoder();
extern "C" void va_g729a_decoder(unsigned char *bitstream, short *synth_short, int bfi);

static void CALLBACK
SpeakerCallback (HWAVEOUT _hWaveOut, UINT uMsg, DWORD dwInstance
  • 3
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
以下是一个基于 eXosip 库实现的 SIP 服务器转发主叫消息到被叫的代码示例: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <exosip2/exosip.h> // 定义一个回调函数,用于处理 SIP 消息 static int on_message_recv(exosip_event_t *je) { switch (je->type) { case EXOSIP_CALL_INVITE: // 收到 INVITE 消息 if (je->request) { char to_uri[256]; char from_uri[256]; char contact_uri[256]; osip_message_t *msg = je->request; osip_message_get_to(msg, 0, &to_uri); osip_message_get_from(msg, 0, &from_uri); osip_message_get_contact(msg, 0, &contact_uri); // 构建 SIP 消息的头部 osip_message_t *invite = NULL; osip_message_init(&invite); osip_message_set_method(invite, "INVITE"); osip_message_set_uri(invite, to_uri); osip_message_set_from(invite, from_uri); osip_message_set_contact(invite, contact_uri); osip_message_set_call_id(invite, osip_message_get_call_id(msg)); osip_message_set_version(invite, osip_message_get_version(msg)); // 发送 SIP 消息 exosip_lock(); exosip_call_send_initial_invite(je->did, invite); exosip_unlock(); osip_message_free(invite); } break; default: break; } return 0; } int main() { // 初始化 eXosip 库 int ret = exosip_init(); if (ret != 0) { printf("eXosip initialization failed: %d\n", ret); return -1; } // 注册一个 SIP 帐号 char *username = "用户名"; char *password = "密码"; char *realm = "realm"; char *proxy = "IP 地址"; char *local_ip = "本地 IP 地址"; char to_uri[256]; sprintf(to_uri, "sip:%s@%s", username, proxy); exosip_proxy_t *proxy_cfg = exosip_proxy_build(proxy, EXOSIP_DEFAULT_PROXY_PORT, NULL, NULL, 0); exosip_event_t *je = NULL; exosip_listen_addr_t *addr = NULL; // 添加监听地址 exosip_listen_addr_build(&addr, "UDP", local_ip, EXOSIP_DEFAULT_UDP_PORT, AF_INET, 0); // 启动监听 exosip_listen_address_add(addr); // 注册 SIP 帐号 exosip_set_authentication_info(username, password, realm); exosip_register_build_initial_register(to_uri, proxy_cfg, NULL, 3600, &je); exosip_lock(); exosip_register_send_initial_register(je); exosip_unlock(); exosip_event_free(je); // 等待事件循环 while (1) { exosip_event_wait(1); while ((je = exosip_event_get()) != NULL) { on_message_recv(je); exosip_event_free(je); } } // 销毁 eXosip 库 exosip_quit(); return 0; } ``` 在这个示例中,我们通过 `exosip_call_send_initial_invite` 函数向被叫发送了一条 INVITE 消息。在实际应用中,需要根据具体的需求和业务场景来选择合适的 SIP 消息类型和内容。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值