PJSIP初体验

最近研究了下PJSIP这个强大的VOIP开源库,简单的来记录下遇到一些问题和解决思路,最后附上完整的工程代码供参考

功能:

1.实现用户的注册

2.实现收发短信

3.实现通话功能

 

踩的坑

1.默认的UDP的端口是5060这个需要改变,需要使用代理设置

2.发送短信编码格式乱码 需要进行转码

3.通话没有声音 是没有添加 媒体改变的回调函数

 

直接放上代码了

/*
2020年10月14日 10:45:31
初始化UA
*/

#include <pjsua-lib/pjsua.h>
#include <string>
#include <comutil.h>  
#pragma comment(lib, "comsuppw.lib")

#define THIS_FILE	__FILE__

#define SIP_DOMAIN	"JamesWu9527"
#define SIP_USER	"JamesWu9527"
#define SIP_PASSWD	"123456"
#define SIPURL		"192.168.0.1"

std::wstring UTF8ToUnicode(const std::string& str)
{
	int  len = 0;
	len = str.length();
	int  unicodeLen = ::MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, NULL, 0);
	wchar_t* pUnicode;
	pUnicode = new  wchar_t[unicodeLen + 1];
	memset(pUnicode, 0, (unicodeLen + 1) * sizeof(wchar_t));
	::MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, (LPWSTR)pUnicode, unicodeLen);
	std::wstring  rt;
	rt = (wchar_t*)pUnicode;
	delete  pUnicode;
	return  rt;
}

std::string UnicodeToUTF8(const std::wstring& str)
{
	char* pElementText;
	int    iTextLen;
	iTextLen = WideCharToMultiByte(CP_UTF8, 0, str.c_str(), -1, NULL, 0, NULL, NULL);
	pElementText = new char[iTextLen + 1];
	memset((void*)pElementText, 0, sizeof(char) * (iTextLen + 1));
	::WideCharToMultiByte(CP_UTF8, 0, str.c_str(), -1, pElementText, iTextLen, NULL, NULL);
	std::string strText;
	strText = pElementText;
	delete[] pElementText;
	return strText;
}

std::string wstring2string(const std::wstring& ws)
{
	_bstr_t t = ws.c_str();
	char* pchar = (char*)t;
	std::string result = pchar;
	return result;
}


//收到短信的回调
void on_pager(pjsua_call_id call_id, const pj_str_t* from, const pj_str_t* to, const pj_str_t* contact,
	const pj_str_t* mime_type, const pj_str_t* body)
{
	PJ_LOG(2, (THIS_FILE, "call_id:%d from: %s to: %s contact:%s mime %s body: %s", call_id, from->ptr, to->ptr,
		contact->ptr, mime_type->ptr, body->ptr));

	//解析body的内容
	std::string strResult = wstring2string(UTF8ToUnicode(body->ptr));
	PJ_LOG(2, (THIS_FILE, "%s", strResult.c_str()));

}

//收到电话的回调
void on_incoming_call(pjsua_acc_id acc_id, pjsua_call_id call_id,
	pjsip_rx_data* rdata)
{
	PJ_LOG(2, (THIS_FILE, "来信息了"));

	pjsua_call_info ci;

	PJ_UNUSED_ARG(acc_id);
	PJ_UNUSED_ARG(rdata);

	pjsua_call_get_info(call_id, &ci);

	PJ_LOG(3, (THIS_FILE, "Incoming call from %.*s!!",
		(int)ci.remote_info.slen,
		ci.remote_info.ptr));

	/* Automatically answer incoming calls with 200/OK */
	pjsua_call_answer(call_id, 200, NULL, NULL);

}

//媒体状态发生改变时,会调用的函数
static void on_call_media_state(pjsua_call_id call_id)
{
	pjsua_call_info ci;

	pjsua_call_get_info(call_id, &ci);

	if (ci.media_status == PJSUA_CALL_MEDIA_ACTIVE) {
		// When media is active, connect call to sound device.
		pjsua_conf_connect(ci.conf_slot, 0);
		pjsua_conf_connect(0, ci.conf_slot);
	}
}

//呼叫状态发生变化的时候回调函数
void on_call_state(pjsua_call_id call_id, pjsip_event* e)
{
	pjsua_call_info ci;

	PJ_UNUSED_ARG(e);

	pjsua_call_get_info(call_id, &ci);
	PJ_LOG(2, (THIS_FILE, "Call %d state=%.*s", call_id,
		(int)ci.state_text.slen,
		ci.state_text.ptr));
}


static pj_status_t app_init()
{
	//Step1 创建PJSUA
	pj_status_t status = pjsua_create();
	if (status != PJ_SUCCESS)
	{
		pjsua_perror(THIS_FILE, "error about app_init() function",status);
		return status;
	}

	pjsua_config ua_cfg;
	pjsua_config_default(&ua_cfg);
	ua_cfg.cb.on_pager = &on_pager;			//接收消息的回调函数
	ua_cfg.cb.on_incoming_call = &on_incoming_call;			//来电通知
	ua_cfg.cb.on_call_media_state = &on_call_media_state;	//媒体状态发生变化的回调函数
	ua_cfg.cb.on_call_state = &on_call_state;	//呼叫状态


	pjsua_logging_config log_cfg;
	pjsua_logging_config_default(&log_cfg);

	pjsua_media_config media_cfg;
	pjsua_media_config_default(&media_cfg);

	//Step2 初始化pjsua
	status = pjsua_init(&ua_cfg, &log_cfg, &media_cfg);
	if (status != PJ_SUCCESS)
	{
		pjsua_perror(THIS_FILE, "error about pjsua_init() function", status);
		return status;
	}

	//Step3 创建sip传输
	pjsua_transport_config transp_cfg;
	pjsua_transport_config_default(&transp_cfg);
	transp_cfg.port = 6050;
	transp_cfg.public_addr = pj_str(SIPURL);
	pjsua_transport_id transp_id;

	status = pjsua_transport_create(PJSIP_TRANSPORT_UDP, &transp_cfg, &transp_id);
	if (status != PJ_SUCCESS)
	{
		pjsua_perror(THIS_FILE, "error about pjsua_transport_create() function", status);
		return status;
	}

	//Step4 运行pjsua
	status = pjsua_start();
	if (status != PJ_SUCCESS)
	{
		pjsua_perror(THIS_FILE, "error about pjsua_start() function", status);
		pjsua_destroy();
		return status;
	}

	//Step5 注册账号
	pjsua_acc_config acc_config;
	pjsua_acc_config_default(&acc_config);

	acc_config.id = pj_str("sip:" SIP_USER "@" SIP_DOMAIN);
	acc_config.reg_uri = pj_str("sip:" SIP_DOMAIN);
	acc_config.cred_count = 1;

	//默认的UDP端口是试用的5060端口,如果需要试用其他端口 需要进行下面两句代码的设置  增加代理设置
	acc_config.proxy_cnt = 1;
	acc_config.proxy[0] = pj_str("sip:" SIPURL ":" "6050");

	acc_config.cred_info[0].realm = pj_str(SIP_DOMAIN);
	acc_config.cred_info[0].scheme = pj_str("digest");
	acc_config.cred_info[0].username = pj_str(SIP_USER);
	acc_config.cred_info[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
	acc_config.cred_info[0].data = pj_str(SIP_PASSWD);


	pjsua_acc_id acc_id;
	status = pjsua_acc_add(&acc_config, 0, &acc_id);
	if (status != PJ_SUCCESS)
	{
		PJ_LOG(2, (__FILE__, "pjsua_acc_add() error"));
		return status;
	}

	char option[10];
	while (1)
	{
		puts("Press 'q' to quit");
		if (fgets(option, sizeof(option), stdin) == NULL)
		{
			puts("EOF while reading stdin, will quit now..");
			break;
		}

		if (option[0] == 'q')	//退出系统
			break;
		else if (option[0] == 's')	//发送短信
		{
			//发送短信
			pj_str_t to = pj_str("sip:10010006@kinet");
			std::string strcontent = UnicodeToUTF8(L"我是中文测试");
			
			pj_str_t content = pj_str(const_cast<char *>(strcontent.c_str()));

			status = pjsua_im_send(acc_id, &to, NULL, &content , NULL, NULL);
			if (status != PJ_SUCCESS)
			{
				PJ_LOG(2, (__FILE__, "发送消息失败 %d",status));
				break;
			}

		}
		else if (option[0] == 'm')
		{
			//拨打电话
			pj_str_t dst_uri = pj_str("sip:10010006@kinet");
			status = pjsua_call_make_call(acc_id, &dst_uri, NULL, NULL, NULL, NULL);
			if (status != PJ_SUCCESS)
			{
				PJ_LOG(2, (__FILE__, "拨打电话失败 %d", status));
				break;
			}
		}
		else if (option[0] == 'h')	//挂断电话
		{
			pjsua_call_hangup_all();
		}
		

	}
	pjsua_destroy();
	system("pause");
}

int main()
{
	app_init();
	return 0;
}

 

Guess you like

Origin blog.csdn.net/Wuzm_/article/details/109079588