1
/* $Id: call.cpp 4719 2014-01-29 08:10:22Z nanang $ */
3
* Copyright (C) 2012-2013 Teluu Inc. (http://www.teluu.com)
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
#include <pjsua2/account.hpp>
20
#include <pjsua2/call.hpp>
21
#include <pjsua2/endpoint.hpp>
28
#define THIS_FILE "call.cpp"
30
///////////////////////////////////////////////////////////////////////////////
32
#define SDP_BUFFER_SIZE 1024
35
: n(0), max(0), min(0), last(0), mean(0)
39
void MathStat::fromPj(const pj_math_stat &prm)
44
this->last = prm.last;
45
this->mean = prm.mean;
48
void RtcpStreamStat::fromPj(const pjmedia_rtcp_stream_stat &prm)
50
this->update.fromPj(prm.update);
51
this->updateCount = prm.update_cnt;
52
this->pkt = (unsigned)prm.pkt;
53
this->bytes = (unsigned)prm.bytes;
54
this->discard = prm.discard;
55
this->loss = prm.loss;
56
this->reorder = prm.loss;
58
this->lossPeriodUsec.fromPj(prm.loss_period);
59
this->lossType.burst = prm.loss_type.burst;
60
this->lossType.random = prm.loss_type.random;
61
this->jitterUsec.fromPj(prm.jitter);
64
void RtcpSdes::fromPj(const pjmedia_rtcp_sdes &prm)
66
this->cname = pj2Str(prm.cname);
67
this->name = pj2Str(prm.name);
68
this->email = pj2Str(prm.email);
69
this->phone = pj2Str(prm.phone);
70
this->loc = pj2Str(prm.loc);
71
this->tool = pj2Str(prm.tool);
72
this->note = pj2Str(prm.note);
75
void RtcpStat::fromPj(const pjmedia_rtcp_stat &prm)
77
this->start.fromPj(prm.start);
78
this->txStat.fromPj(prm.tx);
79
this->rxStat.fromPj(prm.rx);
80
this->rttUsec.fromPj(prm.rtt);
81
this->rtpTxLastTs = prm.rtp_tx_last_ts;
82
this->rtpTxLastSeq = prm.rtp_tx_last_seq;
83
#if defined(PJMEDIA_RTCP_STAT_HAS_IPDV) && PJMEDIA_RTCP_STAT_HAS_IPDV!=0
84
this->rxIpdvUsec.fromPj(prm.rx_ipdv);
86
#if defined(PJMEDIA_RTCP_STAT_HAS_RAW_JITTER) && \
87
PJMEDIA_RTCP_STAT_HAS_RAW_JITTER!=0
88
this->rxRawJitterUsec.fromPj(prm.rx_raw_jitter);
90
this->peerSdes.fromPj(prm.peer_sdes);
93
void JbufState::fromPj(const pjmedia_jb_state &prm)
95
this->frameSize = prm.frame_size;
96
this->minPrefetch = prm.min_prefetch;
97
this->maxPrefetch = prm.max_prefetch;
98
this->burst = prm.burst;
99
this->prefetch = prm.prefetch;
100
this->size = prm.size;
101
this->avgDelayMsec = prm.avg_delay;
102
this->minDelayMsec = prm.min_delay;
103
this->maxDelayMsec = prm.max_delay;
104
this->devDelayMsec = prm.dev_delay;
105
this->avgBurst = prm.avg_burst;
106
this->lost = prm.lost;
107
this->discard = prm.discard;
108
this->empty = prm.empty;
111
void SdpSession::fromPj(const pjmedia_sdp_session &sdp)
113
char buf[SDP_BUFFER_SIZE];
116
len = pjmedia_sdp_print(&sdp, buf, sizeof(buf));
117
wholeSdp = (len > -1? string(buf, len): "");
118
pjSdpSession = (void *)&sdp;
121
void MediaEvent::fromPj(const pjmedia_event &ev)
124
if (type == PJMEDIA_EVENT_FMT_CHANGED) {
125
data.fmtChanged.newWidth = ev.data.fmt_changed.new_fmt.det.vid.size.w;
126
data.fmtChanged.newHeight = ev.data.fmt_changed.new_fmt.det.vid.size.h;
128
pjMediaEvent = (void *)&ev;
131
void MediaTransportInfo::fromPj(const pjmedia_transport_info &info)
133
char straddr[PJ_INET6_ADDRSTRLEN+10];
135
pj_sockaddr_print(&info.src_rtp_name, straddr, sizeof(straddr), 3);
136
srcRtpName = straddr;
137
pj_sockaddr_print(&info.src_rtcp_name, straddr, sizeof(straddr), 3);
138
srcRtcpName = straddr;
141
//////////////////////////////////////////////////////////////////////////////
143
/* Call Audio Media. */
144
class CallAudioMedia : public AudioMedia
148
* Set the conference port identification associated with the
151
void setPortId(int id);
155
void CallAudioMedia::setPortId(int id)
160
CallOpParam::CallOpParam(bool useDefaultCallSetting)
161
: statusCode(pjsip_status_code(0)), reason(""), options(0)
163
if (useDefaultCallSetting)
164
opt = CallSetting(true);
167
CallSendRequestParam::CallSendRequestParam()
172
CallVidSetStreamParam::CallVidSetStreamParam()
175
pjsua_call_vid_strm_op_param prm;
177
pjsua_call_vid_strm_op_param_default(&prm);
178
this->medIdx = prm.med_idx;
180
this->capDev = prm.cap_dev;
184
CallSetting::CallSetting(pj_bool_t useDefaultValues)
186
if (useDefaultValues) {
187
pjsua_call_setting setting;
189
pjsua_call_setting_default(&setting);
193
reqKeyframeMethod = 0;
199
bool CallSetting::isEmpty() const
201
return (flag == 0 && reqKeyframeMethod == 0 && audioCount == 0 &&
205
void CallSetting::fromPj(const pjsua_call_setting &prm)
207
this->flag = prm.flag;
208
this->reqKeyframeMethod = prm.req_keyframe_method;
209
this->audioCount = prm.aud_cnt;
210
this->videoCount = prm.vid_cnt;
213
pjsua_call_setting CallSetting::toPj() const
215
pjsua_call_setting setting;
217
setting.flag = this->flag;
218
setting.req_keyframe_method = this->reqKeyframeMethod;
219
setting.aud_cnt = this->audioCount;
220
setting.vid_cnt = this->videoCount;
226
CallMediaInfo::CallMediaInfo()
230
void CallMediaInfo::fromPj(const pjsua_call_media_info &prm)
232
this->index = prm.index;
233
this->type = prm.type;
235
this->status = prm.status;
236
if (this->type == PJMEDIA_TYPE_AUDIO) {
237
this->audioConfSlot = (int)prm.stream.aud.conf_slot;
238
} else if (this->type == PJMEDIA_TYPE_VIDEO) {
239
this->videoIncomingWindowId = prm.stream.vid.win_in;
240
this->videoCapDev = prm.stream.vid.cap_dev;
244
void CallInfo::fromPj(const pjsua_call_info &pci)
251
localUri = pj2Str(pci.local_info);
252
localContact = pj2Str(pci.local_contact);
253
remoteUri = pj2Str(pci.remote_info);
254
remoteContact = pj2Str(pci.remote_contact);
255
callIdString = pj2Str(pci.call_id);
256
setting.fromPj(pci.setting);
258
stateText = pj2Str(pci.state_text);
259
lastStatusCode = pci.last_status;
260
lastReason = pj2Str(pci.last_status_text);
261
connectDuration.fromPj(pci.connect_duration);
262
totalDuration.fromPj(pci.total_duration);
263
remOfferer = PJ2BOOL(pci.rem_offerer);
264
remAudioCount = pci.rem_aud_cnt;
265
remVideoCount = pci.rem_vid_cnt;
267
for (mi = 0; mi < pci.media_cnt; mi++) {
270
med.fromPj(pci.media[mi]);
271
media.push_back(med);
273
for (mi = 0; mi < pci.prov_media_cnt; mi++) {
276
med.fromPj(pci.prov_media[mi]);
277
provMedia.push_back(med);
281
void StreamInfo::fromPj(const pjsua_stream_info &info)
283
char straddr[PJ_INET6_ADDRSTRLEN+10];
286
if (type == PJMEDIA_TYPE_AUDIO) {
287
proto = info.info.aud.proto;
288
dir = info.info.aud.dir;
289
pj_sockaddr_print(&info.info.aud.rem_addr, straddr, sizeof(straddr), 3);
290
remoteRtpAddress = straddr;
291
pj_sockaddr_print(&info.info.aud.rem_rtcp, straddr, sizeof(straddr), 3);
292
remoteRtcpAddress = straddr;
293
txPt = info.info.aud.tx_pt;
294
rxPt = info.info.aud.rx_pt;
295
codecName = pj2Str(info.info.aud.fmt.encoding_name);
296
codecClockRate = info.info.aud.fmt.clock_rate;
297
codecParam = info.info.aud.param;
298
} else if (type == PJMEDIA_TYPE_VIDEO) {
299
proto = info.info.vid.proto;
300
dir = info.info.vid.dir;
301
pj_sockaddr_print(&info.info.vid.rem_addr, straddr, sizeof(straddr), 3);
302
remoteRtpAddress = straddr;
303
pj_sockaddr_print(&info.info.vid.rem_rtcp, straddr, sizeof(straddr), 3);
304
remoteRtcpAddress = straddr;
305
txPt = info.info.vid.tx_pt;
306
rxPt = info.info.vid.rx_pt;
307
codecName = pj2Str(info.info.vid.codec_info.encoding_name);
308
codecClockRate = info.info.vid.codec_info.clock_rate;
309
codecParam = info.info.vid.codec_param;
313
void StreamStat::fromPj(const pjsua_stream_stat &prm)
315
rtcp.fromPj(prm.rtcp);
316
jbuf.fromPj(prm.jbuf);
319
///////////////////////////////////////////////////////////////////////////////
323
pjsua_msg_data msg_data;
324
pjsua_msg_data *p_msg_data;
325
pjsua_call_setting opt;
326
pjsua_call_setting *p_opt;
332
* Default constructors with specified parameters.
334
call_param(const SipTxOption &tx_option);
335
call_param(const SipTxOption &tx_option, const CallSetting &setting,
336
const string &reason_str);
339
call_param::call_param(const SipTxOption &tx_option)
341
if (tx_option.isEmpty()) {
344
tx_option.toPj(msg_data);
345
p_msg_data = &msg_data;
352
call_param::call_param(const SipTxOption &tx_option, const CallSetting &setting,
353
const string &reason_str)
355
if (tx_option.isEmpty()) {
358
tx_option.toPj(msg_data);
359
p_msg_data = &msg_data;
362
if (setting.isEmpty()) {
365
opt = setting.toPj();
369
reason = str2Pj(reason_str);
370
p_reason = (reason.slen == 0? NULL: &reason);
373
Call::Call(Account& account, int call_id)
374
: acc(account), id(call_id)
376
if (call_id != PJSUA_INVALID_ID)
377
pjsua_call_set_user_data(call_id, this);
383
* If this instance is deleted, also hangup the corresponding call in
386
if (id != PJSUA_INVALID_ID && pjsua_get_state() < PJSUA_STATE_CLOSING) {
387
pjsua_call_set_user_data(id, NULL);
395
CallInfo Call::getInfo() const throw(Error)
397
pjsua_call_info pj_ci;
400
PJSUA2_CHECK_EXPR( pjsua_call_get_info(id, &pj_ci) );
405
bool Call::isActive() const
407
if (id == PJSUA_INVALID_ID)
410
return (pjsua_call_is_active(id) != 0);
413
int Call::getId() const
418
Call *Call::lookup(int call_id)
420
Call *call = (Call*)pjsua_call_get_user_data(call_id);
426
bool Call::hasMedia() const
428
return (pjsua_call_has_media(id) != 0);
431
Media *Call::getMedia(unsigned med_idx) const
433
/* Check if the media index is valid and if the media has a valid port ID */
434
if (med_idx >= medias.size() ||
435
(medias[med_idx] && medias[med_idx]->getType() == PJMEDIA_TYPE_AUDIO &&
436
((AudioMedia *)medias[med_idx])->getPortId() == PJSUA_INVALID_ID))
441
return medias[med_idx];
444
pjsip_dialog_cap_status Call::remoteHasCap(int htype,
446
const string &token) const
448
pj_str_t pj_hname = str2Pj(hname);
449
pj_str_t pj_token = str2Pj(token);
451
return pjsua_call_remote_has_cap(id, htype,
452
(htype == PJSIP_H_OTHER)? &pj_hname: NULL,
456
void Call::setUserData(Token user_data)
458
userData = user_data;
461
Token Call::getUserData() const
466
pj_stun_nat_type Call::getRemNatType() throw(Error)
468
pj_stun_nat_type nat;
470
PJSUA2_CHECK_EXPR( pjsua_call_get_rem_nat_type(id, &nat) );
475
void Call::makeCall(const string &dst_uri, const CallOpParam &prm) throw(Error)
477
pj_str_t pj_dst_uri = str2Pj(dst_uri);
478
call_param param(prm.txOption, prm.opt, prm.reason);
480
PJSUA2_CHECK_EXPR( pjsua_call_make_call(acc.getId(), &pj_dst_uri,
482
param.p_msg_data, &id) );
485
void Call::answer(const CallOpParam &prm) throw(Error)
487
call_param param(prm.txOption, prm.opt, prm.reason);
489
PJSUA2_CHECK_EXPR( pjsua_call_answer2(id, param.p_opt, prm.statusCode,
490
param.p_reason, param.p_msg_data) );
493
void Call::hangup(const CallOpParam &prm) throw(Error)
495
call_param param(prm.txOption, prm.opt, prm.reason);
497
PJSUA2_CHECK_EXPR( pjsua_call_hangup(id, prm.statusCode, param.p_reason,
501
void Call::setHold(const CallOpParam &prm) throw(Error)
503
call_param param(prm.txOption, prm.opt, prm.reason);
505
PJSUA2_CHECK_EXPR( pjsua_call_set_hold2(id, prm.options, param.p_msg_data));
508
void Call::reinvite(const CallOpParam &prm) throw(Error)
510
call_param param(prm.txOption, prm.opt, prm.reason);
512
PJSUA2_CHECK_EXPR( pjsua_call_reinvite2(id, param.p_opt, param.p_msg_data));
515
void Call::update(const CallOpParam &prm) throw(Error)
517
call_param param(prm.txOption, prm.opt, prm.reason);
519
PJSUA2_CHECK_EXPR( pjsua_call_update2(id, param.p_opt, param.p_msg_data) );
522
void Call::xfer(const string &dest, const CallOpParam &prm) throw(Error)
524
call_param param(prm.txOption);
525
pj_str_t pj_dest = str2Pj(dest);
527
PJSUA2_CHECK_EXPR( pjsua_call_xfer(id, &pj_dest, param.p_msg_data) );
530
void Call::xferReplaces(const Call& dest_call,
531
const CallOpParam &prm) throw(Error)
533
call_param param(prm.txOption);
535
PJSUA2_CHECK_EXPR(pjsua_call_xfer_replaces(id, dest_call.getId(),
536
prm.options, param.p_msg_data) );
539
void Call::processRedirect(pjsip_redirect_op cmd) throw(Error)
541
PJSUA2_CHECK_EXPR(pjsua_call_process_redirect(id, cmd));
544
void Call::dialDtmf(const string &digits) throw(Error)
546
pj_str_t pj_digits = str2Pj(digits);
548
PJSUA2_CHECK_EXPR(pjsua_call_dial_dtmf(id, &pj_digits));
551
void Call::sendInstantMessage(const SendInstantMessageParam& prm)
554
pj_str_t mime_type = str2Pj(prm.contentType);
555
pj_str_t content = str2Pj(prm.content);
556
call_param param(prm.txOption);
558
PJSUA2_CHECK_EXPR(pjsua_call_send_im(id, &mime_type, &content,
559
param.p_msg_data, prm.userData) );
562
void Call::sendTypingIndication(const SendTypingIndicationParam &prm)
565
call_param param(prm.txOption);
567
PJSUA2_CHECK_EXPR(pjsua_call_send_typing_ind(id,
573
void Call::sendRequest(const CallSendRequestParam &prm) throw(Error)
575
pj_str_t method = str2Pj(prm.method);
576
call_param param(prm.txOption);
578
PJSUA2_CHECK_EXPR(pjsua_call_send_request(id, &method, param.p_msg_data) );
581
string Call::dump(bool with_media, const string indent) throw(Error)
583
#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
584
char buffer[1024 * 10];
586
char buffer[1024 * 3];
589
PJSUA2_CHECK_EXPR(pjsua_call_dump(id, (with_media? PJ_TRUE: PJ_FALSE),
590
buffer, sizeof(buffer),
596
int Call::vidGetStreamIdx() const
599
return pjsua_call_get_vid_stream_idx(id);
601
return PJSUA_INVALID_ID;
605
bool Call::vidStreamIsRunning(int med_idx, pjmedia_dir dir) const
608
return (pjsua_call_vid_stream_is_running(id, med_idx, dir) == PJ_TRUE);
610
PJ_UNUSED_ARG(med_idx);
616
void Call::vidSetStream(pjsua_call_vid_strm_op op,
617
const CallVidSetStreamParam ¶m) throw(Error)
620
pjsua_call_vid_strm_op_param prm;
622
prm.med_idx = param.medIdx;
624
prm.cap_dev = param.capDev;
625
PJSUA2_CHECK_EXPR( pjsua_call_set_vid_strm(id, op, &prm) );
628
PJ_UNUSED_ARG(param);
629
PJSUA2_RAISE_ERROR(PJ_EINVALIDOP);
633
StreamInfo Call::getStreamInfo(unsigned med_idx) const throw(Error)
635
pjsua_stream_info pj_si;
638
PJSUA2_CHECK_EXPR( pjsua_call_get_stream_info(id, med_idx, &pj_si) );
643
StreamStat Call::getStreamStat(unsigned med_idx) const throw(Error)
645
pjsua_stream_stat pj_ss;
648
PJSUA2_CHECK_EXPR( pjsua_call_get_stream_stat(id, med_idx, &pj_ss) );
653
MediaTransportInfo Call::getMedTransportInfo(unsigned med_idx) const
656
pjmedia_transport_info pj_mti;
657
MediaTransportInfo mti;
659
PJSUA2_CHECK_EXPR( pjsua_call_get_med_transport_info(id, med_idx,
665
void Call::processMediaUpdate(OnCallMediaStateParam &prm)
667
pjsua_call_info pj_ci;
670
if (pjsua_call_get_info(id, &pj_ci) == PJ_SUCCESS) {
671
for (mi = 0; mi < pj_ci.media_cnt; mi++) {
672
if (mi >= medias.size()) {
673
if (pj_ci.media[mi].type == PJMEDIA_TYPE_AUDIO) {
674
medias.push_back(new CallAudioMedia);
676
medias.push_back(NULL);
680
if (pj_ci.media[mi].type == PJMEDIA_TYPE_AUDIO) {
681
CallAudioMedia *aud_med = (CallAudioMedia *)medias[mi];
683
aud_med->setPortId(pj_ci.media[mi].stream.aud.conf_slot);
684
/* Add media if the conference slot ID is valid. */
685
if (pj_ci.media[mi].stream.aud.conf_slot != PJSUA_INVALID_ID)
687
Endpoint::instance().mediaAdd((AudioMedia &)*aud_med);
689
Endpoint::instance().mediaRemove((AudioMedia &)*aud_med);
695
/* Call media state callback. */
696
onCallMediaState(prm);
699
void Call::processStateChange(OnCallStateParam &prm)
701
pjsua_call_info pj_ci;
704
if (pjsua_call_get_info(id, &pj_ci) == PJ_SUCCESS &&
705
pj_ci.state == PJSIP_INV_STATE_DISCONNECTED)
708
for (mi = 0; mi < medias.size(); mi++) {
716
/* If the state is DISCONNECTED, this call may have already been deleted
717
* by the application in the callback, so do not access it anymore here.