QT开发pjsip的VOIP
开发环境
平台:A8
环境:Linux-3.0.8
实现功能:使用QT开发VOIP进行初始化、拨号、挂起
测试工具:minisipserver服务器
效果
界面:
minisipserver显示:
封装SIP操作接口:
#include "qt_sip.h"
qt_sip::qt_sip()
{
}
初始化
bool qt_sip::init_sip(void)
{
pj_status_t status;
/* Create pjsua first! */
status = pjsua_create();
if (status != PJ_SUCCESS)
return -1;
/* Init pjsua */
{
pjsua_config cfg;
pjsua_logging_config log_cfg;
pjsua_config_default(&cfg);
cfg.cb.on_incoming_call = &on_incoming_call;
cfg.cb.on_call_media_state = &on_call_media_state;
cfg.cb.on_call_state = &on_call_state;
pjsua_logging_config_default(&log_cfg);
log_cfg.console_level = 4;
status = pjsua_init(&cfg, &log_cfg, NULL);
if (status != PJ_SUCCESS)
return -3;
}
/* Add UDP transport. */
{
pjsua_transport_config cfg;
pjsua_transport_config_default(&cfg);
cfg.port = 5060;
status = pjsua_transport_create(PJSIP_TRANSPORT_UDP, &cfg, NULL);
if (status != PJ_SUCCESS)
return -4;
}
/* Initialization is done, now start pjsua */
status = pjsua_start();
if (status != PJ_SUCCESS)
return -5;
}
void qt_sip::on_incoming_call(pjsua_acc_id acc_id, pjsua_call_id call_id,pjsip_rx_data *rdata)
{
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);
}
/* Callback called by the library when call's state has changed */
void qt_sip::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(3,(THIS_FILE, "Call %d state=%.*s", call_id,
(int)ci.state_text.slen,
ci.state_text.ptr));
}
/* Callback called by the library when call's media state has changed */
void qt_sip::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);
}
}
/* Display error and exit application */
void qt_sip::error_exit(const char *title, pj_status_t status)
{
pjsua_perror(THIS_FILE, title, status);
pjsua_destroy();
exit(1);
}
注册
说明:
在封装sip协议栈的操作接口时,最好是使用SIP协议栈提供的接口,比如:
使用pj_ansi_snprintf这个函数,而不直接使用C的snprintf或是sprintf函数。
int qt_sip::sip_register(char *cname,char *cpasswd,char *sdomain)
{
pj_status_t status;
/* Register to SIP server by creating SIP account. */
{
pjsua_acc_config cfg;
pjsua_acc_config_default(&cfg);
char uri[PJSIP_MAX_URL_SIZE];
//local地址
//minisipserver的ip地址:100.100.100.199
//在minisipserver服务器上添加SIP账号,名称:100,密码:100
//形式:"sip:账号名称@服务器地址"
pj_ansi_snprintf(uri, PJSIP_MAX_URL_SIZE,
"sip:%s@%s",
cname,sdomain);
cfg.id = pj_str(uri);
//服务器地址
/ /形式:“sip:地址”
//“sip:100.100.100.199”
char reg_uri[PJSIP_MAX_URL_SIZE];
pj_ansi_snprintf(reg_uri, PJSIP_MAX_URL_SIZE,"sip:%s",sdomain);
PJ_LOG(3,(THIS_FILE, "***%s***",reg_uri));
cfg.reg_uri = pj_str(reg_uri);
cfg.cred_count = 1;
char realm_uri[PJSIP_MAX_URL_SIZE];
pj_ansi_snprintf(realm_uri,100,"%s",sdomain);
PJ_LOG(3,(THIS_FILE, "***%s***",realm_uri));
cfg.cred_info[0].realm = pj_str("*");
//cfg.cred_info[0].scheme = pj_str("digest");
cfg.cred_info[0].username = pj_str(cname);
cfg.cred_info[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
cfg.cred_info[0].data = pj_str(cpasswd);
status = pjsua_acc_add(&cfg, PJ_TRUE, &g_acc_id);
if (status != PJ_SUCCESS)
return -6;
}
return 0;
}
拨号
//在minisipserver服务器上添加SIP账号,名称:101
//使用另外的客户端注册
//拨打101,命令格式:“sip:101@100.100.100.199”
int qt_sip::sip_dial(char *phonenum)
{
pj_status_t status;
char tmp_uri[PJSIP_MAX_URL_SIZE];
pj_ansi_snprintf(tmp_uri, PJSIP_MAX_URL_SIZE,
"sip:%s@%s",
phonenum,g_server_name);
/* If argument is specified, it's got to be a valid SIP URL */
status = pjsua_verify_url(tmp_uri);
if (status != PJ_SUCCESS)
return -1;
pj_str_t uri = pj_str(tmp_uri);
status = pjsua_call_make_call(g_acc_id, &uri, 0, NULL, NULL, NULL);
if (status != PJ_SUCCESS)
return -2;
return 0;
}
挂断
void qt_sip::sip_hangup()
{
pjsua_call_hangup_all();
}
打印日志:
1)初始化
[root@FriendlyARM QT_PJSIP_VOIP-build-desktop-Qt_4_7_0__QtEmbedded-4_7_0-arm____]# ./QTVOIP -qws
11:56:48.281 os_core_unix.c !pjlib 2.1 for POSIX initialized
11:56:58.294 sip_endpoint.c .Creating endpoint instance...
11:56:58.295 pjlib .select() I/O Queue created (0x1b16d8)
11:56:58.295 sip_endpoint.c .Module "mod-msg-print" registered
11:56:58.295 sip_transport. .Transport manager created.
11:56:58.295 pjsua_core.c .PJSUA state changed: NULL --> CREATED
11:56:58.295 sip_endpoint.c .Module "mod-pjsua-log" registered
11:56:58.295 sip_endpoint.c .Module "mod-tsx-layer" registered
11:56:58.295 sip_endpoint.c .Module "mod-stateful-util" registered
11:56:58.295 sip_endpoint.c .Module "mod-ua" registered
11:56:58.295 sip_endpoint.c .Module "mod-100rel" registered
11:56:58.295 sip_endpoint.c .Module "mod-pjsua" registered
11:56:58.296 sip_endpoint.c .Mo[19531.501318] EPLL Rate changes from 49152000 to 67738000
[19531.503760] EPLL Rate changes from 67738000 to 49152000
dule "mod-invite" registered
11:56:58.364 pa_dev.c ..PortAudio sound library initialized, status=0
11:56:58.364 pa_dev.c ..PortAudio host api count=2
11:56:58.364 pa_dev.c ..Sound device count=4
11:56:58.364 pjlib ..select() I/O Queue created (0x1c947c)
11:56:58.396 sip_endpoint.c .Module "mod-evsub" registered
11:56:58.396 sip_endpoint.c .Module "mod-presence" registered
11:56:58.397 sip_endpoint.c .Module "mod-mwi" registered
11:56:58.397 sip_endpoint.c .Module "mod-refer" registered
11:56:58.397 sip_endpoint.c .Module "mod-pjsua-pres" registered
11:56:58.397 sip_endpoint.c .Module "mod-pjsua-im" registered
11:56:58.397 sip_endpoint.c .Module "mod-pjsua-options" registered
11:56:58.397 pjsua_core.c .1 SIP worker threads created
11:56:58.397 pjsua_core.c .pjsua version 2.1 for Linux-3.0.8/armv7l/glibc-2.11 initialized
11:56:58.397 pjsua_core.c .PJSUA state changed: CREATED --> INIT
11:57:08.402 pjsua_core.c SIP UDP socket reachable at 100.100.100.102:5060
11:57:08.402 udp0x1d7e78 SIP UDP transport started, published address is 100.100.100.102:5060
11:57:08.402 pjsua_core.c PJSUA state changed: INIT --> STARTING
11:57:08.402 sip_endpoint.c .Module "mod-unsolicited-mwi" registered
11:57:08.402 pjsua_core.c .PJSUA state changed: STARTING --> RUNNING
2)注册
11:59:02.256 APP ***sip:100.100.100.199***
11:59:02.256 APP ***100.100.100.199***
11:59:02.256 pjsua_acc.c Adding account: id=sip:100@100.100.100.199
11:59:02.256 pjsua_acc.c .Account sip:100@100.100.100.199 added with id 0
11:59:02.256 pjsua_acc.c .Acc 0: setting registration..
11:59:02.257 pjsua_core.c ...TX 506 bytes Request msg REGISTER/cseq=44772 (tdta0x2b89e8) to UDP 100.100.100.199:5060:
REGISTER sip:100.100.100.199 SIP/2.0
Via: SIP/2.0/UDP 100.100.100.102:5060;rport;branch=z9hG4bKPj82a14091-f95e-44de-b525-fe21626f594b
Max-Forwards: 70
From: <sip:100@100.100.100.199>;tag=b6314bb4-660d-487b-b2f0-8e7099dbd28a
To: <sip:100@100.100.100.199>
Call-ID: c90be808-43c1-498a-9817-1a4c53b06c4a
CSeq: 44772 REGISTER
Contact: <sip:100@100.100.100.102:5060;ob>
Expires: 300
Allow: PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, INFO, SUBSCRIBE, NOTIFY, REFER, MESSAGE, OPTIONS
Content-Length: 0
--end msg--
11:59:02.258 pjsua_acc.c ..Acc 0: Registration sent
11:59:02.271 pjsua_core.c .RX 595 bytes Response msg 407/REGISTER/cseq=44772 (rdata0x1d92a4) from UDP 100.100.100.199:5060:
SIP/2.0 407 Proxy Authentication Required
Via: SIP/2.0/UDP 100.100.100.102:5060;rport;branch=z9hG4bKPj82a14091-f95e-44de-b525-fe21626f594b
From: <sip:100@100.100.100.199>;tag=b6314bb4-660d-487b-b2f0-8e7099dbd28a
To: <sip:100@100.100.100.199>;tag=2db82286
CSeq: 44772 REGISTER
Call-ID: c90be808-43c1-498a-9817-1a4c53b06c4a
Allow: REGISTER,INVITE,OPTIONS,ACK,CANCEL,BYE,REFER,NOTIFY,SUBSCRIBE
User-Agent: miniSipServer V2.3.2 (100) build on Nov 6 2008
Proxy-Authenticate: Digest realm="example.com",algorithm=MD5,nonce="649b3b454ccd12ff21c6509715c2513b",stale=false
Content-Length: 0
--end msg--
11:59:02.272 pjsua_core.c ....TX 700 bytes Request msg REGISTER/cseq=44773 (tdta0x2b89e8) to UDP 100.100.100.199:5060:
REGISTER sip:100.100.100.199 SIP/2.0
Via: SIP/2.0/UDP 100.100.100.102:5060;rport;branch=z9hG4bKPj2ac23c60-15b7-475f-abd2-247976b94d3e
Max-Forwards: 70
From: <sip:100@100.100.100.199>;tag=b6314bb4-660d-487b-b2f0-8e7099dbd28a
To: <sip:100@100.100.100.199>
Call-ID: c90be808-43c1-498a-9817-1a4c53b06c4a
CSeq: 44773 REGISTER
Contact: <sip:100@100.100.100.102:5060;ob>
Expires: 300
Allow: PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, INFO, SUBSCRIBE, NOTIFY, REFER, MESSAGE, OPTIONS
Proxy-Authorization: Digest username="100", realm="example.com", nonce="649b3b454ccd12ff21c6509715c2513b", uri="sip:100.100.100.199", response="22b3e8e9d88a2f9ace62c83308c7d741", algorithm=MD5
Content-Length: 0
--end msg--
11:59:02.273 pjsua_core.c .RX 503 bytes Response msg 200/REGISTER/cseq=44773 (rdata0x1d92a4) from UDP 100.100.100.199:5060:
SIP/2.0 200 OK
Via: SIP/2.0/UDP 100.100.100.102:5060;rport;branch=z9hG4bKPj2ac23c60-15b7-475f-abd2-247976b94d3e
From: <sip:100@100.100.100.199>;tag=b6314bb4-660d-487b-b2f0-8e7099dbd28a
To: <sip:100@100.100.100.199>;tag=2db82286
CSeq: 44773 REGISTER
Call-ID: c90be808-43c1-498a-9817-1a4c53b06c4a
Allow: REGISTER,INVITE,OPTIONS,ACK,CANCEL,BYE,REFER,NOTIFY,SUBSCRIBE
User-Agent: miniSipServer V2.3.2 (100) build on Nov 6 2008
Contact: <sip:100@100.100.100.102>
Expires: 300
Content-Length: 0
--end msg--
11:59:02.273 pjsua_acc.c ....SIP outbound status for acc 0 is not active
11:59:02.273 pjsua_acc.c ....sip:100@100.100.100.199: registration success, status=200 (OK), will re-register in 300 seconds
11:59:02.273 pjsua_acc.c ....Keep-alive timer started for acc 0, destination:100.100.100.199:5060, interval:15s
3)拨号
12:00:10.864 pjsua_call.c !Making call with acc #0 to sip:101@100.100.100.199
12:00:10.864 pjsua_aud.c .Set sound device: capture=-1, playback=-2
12:00:10.865 pjsua_aud.c ..Opening sound device PCM@16000/1/20ms
Expression 'SetApproximateSampleRate( pcm, hwParams, sr )' failed in 'src/../../../portaudio/src/hostapi/alsa/pa_linux_alsa.c', line: 1294
Expression 'PaAlsaStreamComponent_InitialConfigure( &self->playback, outParams, self->primeBuffers, hwParamsPlayback, &realSr )' failed in 'src/../../../portaudio/src/hostapi/alsa/pa_linux_alsa.c', line: 1873
Expression 'PaAlsaStream_Configure( stream, inputParameters, outputParameters, sampleRate, framesPerBuffer, &inputLatency, &outputLatency, &hostBufferSizeMode )' failed in 'src/../../../portaudio/src/hostapi/alsa/pa_linux_alsa.c', line: 1994
12:00:10.876 ec0x2beb68 ...AEC created, clock_rate=16000, channel=1, samples per frame=320, tail length=200 ms, latency=100 ms
12:00:10.877 pjsua_media.c .Call 0: initializing media..
12:00:15.893 sound_port.c EC suspended because of inactivity
12:00:20.886 pjsua_media.c !..RTP socket reachable at 100.100.100.102:40000
12:00:20.887 pjsua_media.c ..RTCP socket reachable at 100.100.100.102:40001
12:00:20.887 pjsua_media.c ..Media index 0 selected for audio call 0
12:00:20.888 pjsua_core.c ....TX 1088 bytes Request msg INVITE/cseq=9089 (tdta0x2f2898) to UDP 100.100.100.199:5060:
INVITE sip:101@100.100.100.199 SIP/2.0
Via: SIP/2.0/UDP 100.100.100.102:5060;rport;branch=z9hG4bKPjb02d3774-83fd-4ff5-8694-26d12697d8d3
Max-Forwards: 70
From: sip:100@100.100.100.199;tag=eb1a9606-dde3-42d8-9253-955509e34509
To: sip:101@100.100.100.199
Contact: <sip:100@100.100.100.102:5060;ob>
Call-ID: b30d7a62-82ce-4a1c-8927-fd69d15c8b3b
CSeq: 9089 INVITE
Allow: PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, INFO, SUBSCRIBE, NOTIFY, REFER, MESSAGE, OPTIONS
Supported: replaces, 100rel, timer, norefersub
Session-Expires: 1800
Min-SE: 90
Content-Type: application/sdp
Content-Length: 484
v=0
o=- 3541291220 3541291220 IN IP4 100.100.100.102
s=pjmedia
b=AS:84
t=0 0
a=X-nat:0
m=audio 40000 RTP/AVP 98 97 99 104 3 0 8 9 96
c=IN IP4 100.100.100.102
b=TIAS:64000
a=rtcp:40001 IN IP4 100.100.100.102
a=sendrecv
a=rtpmap:98 speex/16000
a=rtpmap:97 speex/8000
a=rtpmap:99 speex/32000
a=rtpmap:104 iLBC/8000
a=fmtp:104 mode=30
a=rtpmap:3 GSM/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:9 G722/8000
a=rtpmap:96 telephone-event/8000
a=fmtp:96 0-15
--end msg--
12:00:20.888 APP .......Call 0 state=CALLING
12:00:20.897 pjsua_core.c .RX 486 bytes Response msg 100/INVITE/cseq=9089 (rdata0x1d92a4) from UDP 100.100.100.199:5060:
SIP/2.0 100 Trying
Via: SIP/2.0/UDP 100.100.100.102:5060;rport;branch=z9hG4bKPjb02d3774-83fd-4ff5-8694-26d12697d8d3
From: sip:100@100.100.100.199;tag=eb1a9606-dde3-42d8-9253-955509e34509
To: sip:101@100.100.100.199;tag=2a46556f
CSeq: 9089 INVITE
Call-ID: b30d7a62-82ce-4a1c-8927-fd69d15c8b3b
Allow: REGISTER,INVITE,OPTIONS,ACK,CANCEL,BYE,REFER,NOTIFY,SUBSCRIBE
User-Agent: miniSipServer V2.3.2 (100) build on Nov 6 2008
Contact: <sip:101@100.100.100.199>
Content-Length: 0
--end msg--
12:00:20.907 pjsua_core.c .RX 487 bytes Response msg 180/INVITE/cseq=9089 (rdata0x1d92a4) from UDP 100.100.100.199:5060:
SIP/2.0 180 Ringing
Via: SIP/2.0/UDP 100.100.100.102:5060;rport;branch=z9hG4bKPjb02d3774-83fd-4ff5-8694-26d12697d8d3
From: sip:100@100.100.100.199;tag=eb1a9606-dde3-42d8-9253-955509e34509
To: sip:101@100.100.100.199;tag=2a46556f
CSeq: 9089 INVITE
Call-ID: b30d7a62-82ce-4a1c-8927-fd69d15c8b3b
Allow: REGISTER,INVITE,OPTIONS,ACK,CANCEL,BYE,REFER,NOTIFY,SUBSCRIBE
User-Agent: miniSipServer V2.3.2 (100) build on Nov 6 2008
Contact: <sip:101@100.100.100.199>
Content-Length: 0
--end msg--
12:00:20.907 APP .....Call 0 state=EARLY
4)挂断
12:01:03.160 pjsua_call.c !Hangup all calls..
12:01:03.160 pjsua_call.c .Call 0 hanging up: code=0..
12:01:03.160 pjsua_core.c .....TX 345 bytes Request msg CANCEL/cseq=9089 (tdta0x2a7e00) to UDP 100.100.100.199:5060:
CANCEL sip:101@100.100.100.199 SIP/2.0
Via: SIP/2.0/UDP 100.100.100.102:5060;rport;branch=z9hG4bKPjb02d3774-83fd-4ff5-8694-26d12697d8d3
Max-Forwards: 70
From: sip:100@100.100.100.199;tag=eb1a9606-dde3-42d8-9253-955509e34509
To: sip:101@100.100.100.199
Call-ID: b30d7a62-82ce-4a1c-8927-fd69d15c8b3b
CSeq: 9089 CANCEL
Content-Length: 0
--end msg--
12:01:03.162 pjsua_core.c .RX 482 bytes Response msg 200/CANCEL/cseq=9089 (rdata0x1d92a4) from UDP 100.100.100.199:5060:
SIP/2.0 200 OK
Via: SIP/2.0/UDP 100.100.100.102:5060;rport;branch=z9hG4bKPjb02d3774-83fd-4ff5-8694-26d12697d8d3
From: sip:100@100.100.100.199;tag=eb1a9606-dde3-42d8-9253-955509e34509
To: sip:101@100.100.100.199;tag=2a46556f
CSeq: 9089 CANCEL
Call-ID: b30d7a62-82ce-4a1c-8927-fd69d15c8b3b
Allow: REGISTER,INVITE,OPTIONS,ACK,CANCEL,BYE,REFER,NOTIFY,SUBSCRIBE
User-Agent: miniSipServer V2.3.2 (100) build on Nov 6 2008
Contact: <sip:101@100.100.100.199>
Content-Length: 0
--end msg--
12:01:03.162 pjsua_core.c .RX 498 bytes Response msg 487/INVITE/cseq=9089 (rdata0x1d92a4) from UDP 100.100.100.199:5060:
SIP/2.0 487 Request Terminated
Via: SIP/2.0/UDP 100.100.100.102:5060;rport;branch=z9hG4bKPjb02d3774-83fd-4ff5-8694-26d12697d8d3
From: sip:100@100.100.100.199;tag=eb1a9606-dde3-42d8-9253-955509e34509
To: sip:101@100.100.100.199;tag=2a46556f
CSeq: 9089 INVITE
Call-ID: b30d7a62-82ce-4a1c-8927-fd69d15c8b3b
Allow: REGISTER,INVITE,OPTIONS,ACK,CANCEL,BYE,REFER,NOTIFY,SUBSCRIBE
User-Agent: miniSipServer V2.3.2 (100) build on Nov 6 2008
Contact: <sip:101@100.100.100.199>
Content-Length: 0
--end msg--
12:01:03.162 pjsua_core.c ..TX 352 bytes Request msg ACK/cseq=9089 (tdta0x2f71a0) to UDP 100.100.100.199:5060:
ACK sip:101@100.100.100.199 SIP/2.0
Via: SIP/2.0/UDP 100.100.100.102:5060;rport;branch=z9hG4bKPjb02d3774-83fd-4ff5-8694-26d12697d8d3
Max-Forwards: 70
From: sip:100@100.100.100.199;tag=eb1a9606-dde3-42d8-9253-955509e34509
To: sip:101@100.100.100.199;tag=2a46556f
Call-ID: b30d7a62-82ce-4a1c-8927-fd69d15c8b3b
CSeq: 9089 ACK
Content-Length: 0
--end msg--
12:01:03.163 APP .....Call 0 state=DISCONNCTD
12:01:03.163 pjsua_media.c .....Call 0: deinitializing media..
12:01:04.163 pjsua_aud.c Closing sound device after idle for 1 second(s)
12:01:04.163 pjsua_aud.c .Closing mini210: (hw:0,0) sound playback device and mini210: (hw:0,0) sound capture device