1
/* $Id: endpoint.cpp 4776 2014-03-04 04:25:31Z ming $ */
3
* Copyright (C) 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/endpoint.hpp>
20
#include <pjsua2/account.hpp>
21
#include <pjsua2/call.hpp>
22
#include <pjsua2/presence.hpp>
29
#include <pjsua2/account.hpp>
30
#include <pjsua2/call.hpp>
32
#define THIS_FILE "endpoint.cpp"
33
#define MAX_STUN_SERVERS 32
34
#define TIMER_SIGNATURE 0x600D878A
35
#define MAX_CODEC_NUM 64
39
pj_uint32_t signature;
44
Endpoint *Endpoint::instance_;
46
///////////////////////////////////////////////////////////////////////////////
52
pjsua_config_default(&ua_cfg);
56
void UaConfig::fromPj(const pjsua_config &ua_cfg)
60
this->maxCalls = ua_cfg.max_calls;
61
this->threadCnt = ua_cfg.thread_cnt;
62
this->userAgent = pj2Str(ua_cfg.user_agent);
64
for (i=0; i<ua_cfg.nameserver_count; ++i) {
65
this->nameserver.push_back(pj2Str(ua_cfg.nameserver[i]));
68
for (i=0; i<ua_cfg.stun_srv_cnt; ++i) {
69
this->stunServer.push_back(pj2Str(ua_cfg.stun_srv[i]));
72
this->stunIgnoreFailure = PJ2BOOL(ua_cfg.stun_ignore_failure);
73
this->natTypeInSdp = ua_cfg.nat_type_in_sdp;
74
this->mwiUnsolicitedEnabled = PJ2BOOL(ua_cfg.enable_unsolicited_mwi);
77
pjsua_config UaConfig::toPj() const
82
pjsua_config_default(&pua_cfg);
84
pua_cfg.max_calls = this->maxCalls;
85
pua_cfg.thread_cnt = this->threadCnt;
86
pua_cfg.user_agent = str2Pj(this->userAgent);
88
for (i=0; i<this->nameserver.size() && i<PJ_ARRAY_SIZE(pua_cfg.nameserver);
91
pua_cfg.nameserver[i] = str2Pj(this->nameserver[i]);
93
pua_cfg.nameserver_count = i;
95
for (i=0; i<this->stunServer.size() && i<PJ_ARRAY_SIZE(pua_cfg.stun_srv);
98
pua_cfg.stun_srv[i] = str2Pj(this->stunServer[i]);
100
pua_cfg.stun_srv_cnt = i;
102
pua_cfg.nat_type_in_sdp = this->natTypeInSdp;
103
pua_cfg.enable_unsolicited_mwi = this->mwiUnsolicitedEnabled;
108
void UaConfig::readObject(const ContainerNode &node) throw(Error)
110
ContainerNode this_node = node.readContainer("UaConfig");
112
NODE_READ_UNSIGNED( this_node, maxCalls);
113
NODE_READ_UNSIGNED( this_node, threadCnt);
114
NODE_READ_BOOL ( this_node, mainThreadOnly);
115
NODE_READ_STRINGV ( this_node, nameserver);
116
NODE_READ_STRING ( this_node, userAgent);
117
NODE_READ_STRINGV ( this_node, stunServer);
118
NODE_READ_BOOL ( this_node, stunIgnoreFailure);
119
NODE_READ_INT ( this_node, natTypeInSdp);
120
NODE_READ_BOOL ( this_node, mwiUnsolicitedEnabled);
123
void UaConfig::writeObject(ContainerNode &node) const throw(Error)
125
ContainerNode this_node = node.writeNewContainer("UaConfig");
127
NODE_WRITE_UNSIGNED( this_node, maxCalls);
128
NODE_WRITE_UNSIGNED( this_node, threadCnt);
129
NODE_WRITE_BOOL ( this_node, mainThreadOnly);
130
NODE_WRITE_STRINGV ( this_node, nameserver);
131
NODE_WRITE_STRING ( this_node, userAgent);
132
NODE_WRITE_STRINGV ( this_node, stunServer);
133
NODE_WRITE_BOOL ( this_node, stunIgnoreFailure);
134
NODE_WRITE_INT ( this_node, natTypeInSdp);
135
NODE_WRITE_BOOL ( this_node, mwiUnsolicitedEnabled);
138
///////////////////////////////////////////////////////////////////////////////
140
LogConfig::LogConfig()
142
pjsua_logging_config lc;
144
pjsua_logging_config_default(&lc);
148
void LogConfig::fromPj(const pjsua_logging_config &lc)
150
this->msgLogging = lc.msg_logging;
151
this->level = lc.level;
152
this->consoleLevel = lc.console_level;
153
this->decor = lc.decor;
154
this->filename = pj2Str(lc.log_filename);
155
this->fileFlags = lc.log_file_flags;
159
pjsua_logging_config LogConfig::toPj() const
161
pjsua_logging_config lc;
163
pjsua_logging_config_default(&lc);
165
lc.msg_logging = this->msgLogging;
166
lc.level = this->level;
167
lc.console_level = this->consoleLevel;
168
lc.decor = this->decor;
169
lc.log_file_flags = this->fileFlags;
170
lc.log_filename = str2Pj(this->filename);
175
void LogConfig::readObject(const ContainerNode &node) throw(Error)
177
ContainerNode this_node = node.readContainer("LogConfig");
179
NODE_READ_UNSIGNED( this_node, msgLogging);
180
NODE_READ_UNSIGNED( this_node, level);
181
NODE_READ_UNSIGNED( this_node, consoleLevel);
182
NODE_READ_UNSIGNED( this_node, decor);
183
NODE_READ_STRING ( this_node, filename);
184
NODE_READ_UNSIGNED( this_node, fileFlags);
187
void LogConfig::writeObject(ContainerNode &node) const throw(Error)
189
ContainerNode this_node = node.writeNewContainer("LogConfig");
191
NODE_WRITE_UNSIGNED( this_node, msgLogging);
192
NODE_WRITE_UNSIGNED( this_node, level);
193
NODE_WRITE_UNSIGNED( this_node, consoleLevel);
194
NODE_WRITE_UNSIGNED( this_node, decor);
195
NODE_WRITE_STRING ( this_node, filename);
196
NODE_WRITE_UNSIGNED( this_node, fileFlags);
199
///////////////////////////////////////////////////////////////////////////////
201
MediaConfig::MediaConfig()
203
pjsua_media_config mc;
205
pjsua_media_config_default(&mc);
209
void MediaConfig::fromPj(const pjsua_media_config &mc)
211
this->clockRate = mc.clock_rate;
212
this->sndClockRate = mc.snd_clock_rate;
213
this->channelCount = mc.channel_count;
214
this->audioFramePtime = mc.audio_frame_ptime;
215
this->maxMediaPorts = mc.max_media_ports;
216
this->hasIoqueue = PJ2BOOL(mc.has_ioqueue);
217
this->threadCnt = mc.thread_cnt;
218
this->quality = mc.quality;
219
this->ptime = mc.ptime;
220
this->noVad = PJ2BOOL(mc.no_vad);
221
this->ilbcMode = mc.ilbc_mode;
222
this->txDropPct = mc.tx_drop_pct;
223
this->rxDropPct = mc.rx_drop_pct;
224
this->ecOptions = mc.ec_options;
225
this->ecTailLen = mc.ec_tail_len;
226
this->sndRecLatency = mc.snd_rec_latency;
227
this->sndPlayLatency = mc.snd_play_latency;
228
this->jbInit = mc.jb_init;
229
this->jbMinPre = mc.jb_min_pre;
230
this->jbMaxPre = mc.jb_max_pre;
231
this->jbMax = mc.jb_max;
232
this->sndAutoCloseTime = mc.snd_auto_close_time;
233
this->vidPreviewEnableNative = PJ2BOOL(mc.vid_preview_enable_native);
236
pjsua_media_config MediaConfig::toPj() const
238
pjsua_media_config mcfg;
240
pjsua_media_config_default(&mcfg);
242
mcfg.clock_rate = this->clockRate;
243
mcfg.snd_clock_rate = this->sndClockRate;
244
mcfg.channel_count = this->channelCount;
245
mcfg.audio_frame_ptime = this->audioFramePtime;
246
mcfg.max_media_ports = this->maxMediaPorts;
247
mcfg.has_ioqueue = this->hasIoqueue;
248
mcfg.thread_cnt = this->threadCnt;
249
mcfg.quality = this->quality;
250
mcfg.ptime = this->ptime;
251
mcfg.no_vad = this->noVad;
252
mcfg.ilbc_mode = this->ilbcMode;
253
mcfg.tx_drop_pct = this->txDropPct;
254
mcfg.rx_drop_pct = this->rxDropPct;
255
mcfg.ec_options = this->ecOptions;
256
mcfg.ec_tail_len = this->ecTailLen;
257
mcfg.snd_rec_latency = this->sndRecLatency;
258
mcfg.snd_play_latency = this->sndPlayLatency;
259
mcfg.jb_init = this->jbInit;
260
mcfg.jb_min_pre = this->jbMinPre;
261
mcfg.jb_max_pre = this->jbMaxPre;
262
mcfg.jb_max = this->jbMax;
263
mcfg.snd_auto_close_time = this->sndAutoCloseTime;
264
mcfg.vid_preview_enable_native = this->vidPreviewEnableNative;
269
void MediaConfig::readObject(const ContainerNode &node) throw(Error)
271
ContainerNode this_node = node.readContainer("MediaConfig");
273
NODE_READ_UNSIGNED( this_node, clockRate);
274
NODE_READ_UNSIGNED( this_node, sndClockRate);
275
NODE_READ_UNSIGNED( this_node, channelCount);
276
NODE_READ_UNSIGNED( this_node, audioFramePtime);
277
NODE_READ_UNSIGNED( this_node, maxMediaPorts);
278
NODE_READ_BOOL ( this_node, hasIoqueue);
279
NODE_READ_UNSIGNED( this_node, threadCnt);
280
NODE_READ_UNSIGNED( this_node, quality);
281
NODE_READ_UNSIGNED( this_node, ptime);
282
NODE_READ_BOOL ( this_node, noVad);
283
NODE_READ_UNSIGNED( this_node, ilbcMode);
284
NODE_READ_UNSIGNED( this_node, txDropPct);
285
NODE_READ_UNSIGNED( this_node, rxDropPct);
286
NODE_READ_UNSIGNED( this_node, ecOptions);
287
NODE_READ_UNSIGNED( this_node, ecTailLen);
288
NODE_READ_UNSIGNED( this_node, sndRecLatency);
289
NODE_READ_UNSIGNED( this_node, sndPlayLatency);
290
NODE_READ_INT ( this_node, jbInit);
291
NODE_READ_INT ( this_node, jbMinPre);
292
NODE_READ_INT ( this_node, jbMaxPre);
293
NODE_READ_INT ( this_node, jbMax);
294
NODE_READ_INT ( this_node, sndAutoCloseTime);
295
NODE_READ_BOOL ( this_node, vidPreviewEnableNative);
298
void MediaConfig::writeObject(ContainerNode &node) const throw(Error)
300
ContainerNode this_node = node.writeNewContainer("MediaConfig");
302
NODE_WRITE_UNSIGNED( this_node, clockRate);
303
NODE_WRITE_UNSIGNED( this_node, sndClockRate);
304
NODE_WRITE_UNSIGNED( this_node, channelCount);
305
NODE_WRITE_UNSIGNED( this_node, audioFramePtime);
306
NODE_WRITE_UNSIGNED( this_node, maxMediaPorts);
307
NODE_WRITE_BOOL ( this_node, hasIoqueue);
308
NODE_WRITE_UNSIGNED( this_node, threadCnt);
309
NODE_WRITE_UNSIGNED( this_node, quality);
310
NODE_WRITE_UNSIGNED( this_node, ptime);
311
NODE_WRITE_BOOL ( this_node, noVad);
312
NODE_WRITE_UNSIGNED( this_node, ilbcMode);
313
NODE_WRITE_UNSIGNED( this_node, txDropPct);
314
NODE_WRITE_UNSIGNED( this_node, rxDropPct);
315
NODE_WRITE_UNSIGNED( this_node, ecOptions);
316
NODE_WRITE_UNSIGNED( this_node, ecTailLen);
317
NODE_WRITE_UNSIGNED( this_node, sndRecLatency);
318
NODE_WRITE_UNSIGNED( this_node, sndPlayLatency);
319
NODE_WRITE_INT ( this_node, jbInit);
320
NODE_WRITE_INT ( this_node, jbMinPre);
321
NODE_WRITE_INT ( this_node, jbMaxPre);
322
NODE_WRITE_INT ( this_node, jbMax);
323
NODE_WRITE_INT ( this_node, sndAutoCloseTime);
324
NODE_WRITE_BOOL ( this_node, vidPreviewEnableNative);
327
///////////////////////////////////////////////////////////////////////////////
329
void EpConfig::readObject(const ContainerNode &node) throw(Error)
331
ContainerNode this_node = node.readContainer("EpConfig");
332
NODE_READ_OBJ( this_node, uaConfig);
333
NODE_READ_OBJ( this_node, logConfig);
334
NODE_READ_OBJ( this_node, medConfig);
337
void EpConfig::writeObject(ContainerNode &node) const throw(Error)
339
ContainerNode this_node = node.writeNewContainer("EpConfig");
340
NODE_WRITE_OBJ( this_node, uaConfig);
341
NODE_WRITE_OBJ( this_node, logConfig);
342
NODE_WRITE_OBJ( this_node, medConfig);
345
///////////////////////////////////////////////////////////////////////////////
346
/* Class to post log to main thread */
347
struct PendingLog : public PendingJob
350
virtual void execute(bool is_pending)
352
PJ_UNUSED_ARG(is_pending);
353
Endpoint::instance().utilLogWrite(entry);
357
///////////////////////////////////////////////////////////////////////////////
362
: writer(NULL), mainThreadOnly(false), mainThread(NULL), pendingJobSize(0)
365
PJSUA2_RAISE_ERROR(PJ_EEXISTS);
371
Endpoint& Endpoint::instance() throw(Error)
374
PJSUA2_RAISE_ERROR(PJ_ENOTFOUND);
379
Endpoint::~Endpoint()
381
while (!pendingJobs.empty()) {
382
delete pendingJobs.front();
383
pendingJobs.pop_front();
386
while(mediaList.size() > 0) {
387
AudioMedia *cur_media = mediaList[0];
388
delete cur_media; /* this will remove itself from the list */
391
clearCodecInfoList();
395
} catch (Error &err) {
403
void Endpoint::utilAddPendingJob(PendingJob *job)
406
MAX_PENDING_JOBS = 1024
409
/* See if we can execute immediately */
410
if (!mainThreadOnly || pj_thread_this()==mainThread) {
416
if (pendingJobSize > MAX_PENDING_JOBS) {
417
enum { NUMBER_TO_DISCARD = 5 };
419
pj_enter_critical_section();
420
for (unsigned i=0; i<NUMBER_TO_DISCARD; ++i) {
421
delete pendingJobs.back();
422
pendingJobs.pop_back();
425
pendingJobSize -= NUMBER_TO_DISCARD;
426
pj_leave_critical_section();
428
utilLogWrite(1, THIS_FILE,
429
"*** ERROR: Job queue full!! Jobs discarded!!! ***");
432
pj_enter_critical_section();
433
pendingJobs.push_back(job);
435
pj_leave_critical_section();
438
/* Handle log callback */
439
void Endpoint::utilLogWrite(LogEntry &entry)
441
if (mainThreadOnly && pj_thread_this() != mainThread) {
442
PendingLog *job = new PendingLog;
444
utilAddPendingJob(job);
446
writer->write(entry);
450
/* Run pending jobs only in main thread */
451
void Endpoint::performPendingJobs()
453
if (pj_thread_this() != mainThread)
456
if (pendingJobSize == 0)
460
PendingJob *job = NULL;
462
pj_enter_critical_section();
463
if (pendingJobSize != 0) {
464
job = pendingJobs.front();
465
pendingJobs.pop_front();
468
pj_leave_critical_section();
478
///////////////////////////////////////////////////////////////////////////////
480
* Endpoint static callbacks
482
void Endpoint::logFunc(int level, const char *data, int len)
484
Endpoint &ep = Endpoint::instance();
491
entry.msg = string(data, len);
492
entry.threadId = (long)pj_thread_this();
493
entry.threadName = string(pj_thread_get_name(pj_thread_this()));
495
ep.utilLogWrite(entry);
498
void Endpoint::stun_resolve_cb(const pj_stun_resolve_result *res)
500
Endpoint &ep = Endpoint::instance();
505
OnNatCheckStunServersCompleteParam prm;
507
prm.userData = res->token;
508
prm.status = res->status;
509
if (res->status == PJ_SUCCESS) {
510
char straddr[PJ_INET6_ADDRSTRLEN+10];
512
prm.name = string(res->name.ptr, res->name.slen);
513
pj_sockaddr_print(&res->addr, straddr, sizeof(straddr), 3);
517
ep.onNatCheckStunServersComplete(prm);
520
void Endpoint::on_timer(pj_timer_heap_t *timer_heap,
521
pj_timer_entry *entry)
523
PJ_UNUSED_ARG(timer_heap);
525
Endpoint &ep = Endpoint::instance();
526
UserTimer *ut = (UserTimer*) entry->user_data;
528
if (ut->signature != TIMER_SIGNATURE)
534
void Endpoint::on_nat_detect(const pj_stun_nat_detect_result *res)
536
Endpoint &ep = Endpoint::instance();
541
OnNatDetectionCompleteParam prm;
543
prm.status = res->status;
544
prm.reason = res->status_text;
545
prm.natType = res->nat_type;
546
prm.natTypeName = res->nat_type_name;
548
ep.onNatDetectionComplete(prm);
551
void Endpoint::on_transport_state( pjsip_transport *tp,
552
pjsip_transport_state state,
553
const pjsip_transport_state_info *info)
555
Endpoint &ep = Endpoint::instance();
557
OnTransportStateParam prm;
559
prm.hnd = (TransportHandle)tp;
561
prm.lastError = info ? info->status : PJ_SUCCESS;
563
ep.onTransportState(prm);
566
///////////////////////////////////////////////////////////////////////////////
568
* Account static callbacks
571
Account *Endpoint::lookupAcc(int acc_id, const char *op)
573
Account *acc = Account::lookup(acc_id);
576
"Error: cannot find Account instance for account id %d in "
583
Call *Endpoint::lookupCall(int call_id, const char *op)
585
Call *call = Call::lookup(call_id);
588
"Error: cannot find Call instance for call id %d in "
595
void Endpoint::on_incoming_call(pjsua_acc_id acc_id, pjsua_call_id call_id,
596
pjsip_rx_data *rdata)
598
Account *acc = lookupAcc(acc_id, "on_incoming_call()");
600
pjsua_call_hangup(call_id, PJSIP_SC_INTERNAL_SERVER_ERROR, NULL, NULL);
605
OnIncomingCallParam prm;
606
prm.callId = call_id;
607
prm.rdata.fromPj(*rdata);
609
acc->onIncomingCall(prm);
611
/* disconnect if callback doesn't handle the call */
614
pjsua_call_get_info(call_id, &ci);
615
if (!pjsua_call_get_user_data(call_id) &&
616
ci.state != PJSIP_INV_STATE_DISCONNECTED)
618
pjsua_call_hangup(call_id, PJSIP_SC_INTERNAL_SERVER_ERROR, NULL, NULL);
622
void Endpoint::on_reg_started(pjsua_acc_id acc_id, pj_bool_t renew)
624
Account *acc = lookupAcc(acc_id, "on_reg_started()");
629
OnRegStartedParam prm;
630
prm.renew = PJ2BOOL(renew);
631
acc->onRegStarted(prm);
634
void Endpoint::on_reg_state2(pjsua_acc_id acc_id, pjsua_reg_info *info)
636
Account *acc = lookupAcc(acc_id, "on_reg_state2()");
642
prm.status = info->cbparam->status;
643
prm.code = (pjsip_status_code) info->cbparam->code;
644
prm.reason = pj2Str(info->cbparam->reason);
645
if (info->cbparam->rdata)
646
prm.rdata.fromPj(*info->cbparam->rdata);
647
prm.expiration = info->cbparam->expiration;
649
acc->onRegState(prm);
652
void Endpoint::on_incoming_subscribe(pjsua_acc_id acc_id,
653
pjsua_srv_pres *srv_pres,
654
pjsua_buddy_id buddy_id,
655
const pj_str_t *from,
656
pjsip_rx_data *rdata,
657
pjsip_status_code *code,
659
pjsua_msg_data *msg_data)
661
PJ_UNUSED_ARG(buddy_id);
662
PJ_UNUSED_ARG(srv_pres);
664
Account *acc = lookupAcc(acc_id, "on_incoming_subscribe()");
666
/* default behavior should apply */
670
OnIncomingSubscribeParam prm;
671
prm.srvPres = srv_pres;
672
prm.fromUri = pj2Str(*from);
673
prm.rdata.fromPj(*rdata);
675
prm.reason = pj2Str(*reason);
676
prm.txOption.fromPj(*msg_data);
678
acc->onIncomingSubscribe(prm);
681
acc->tmpReason = prm.reason;
682
*reason = str2Pj(acc->tmpReason);
683
prm.txOption.toPj(*msg_data);
686
void Endpoint::on_pager2(pjsua_call_id call_id,
687
const pj_str_t *from,
689
const pj_str_t *contact,
690
const pj_str_t *mime_type,
691
const pj_str_t *body,
692
pjsip_rx_data *rdata,
695
OnInstantMessageParam prm;
696
prm.fromUri = pj2Str(*from);
697
prm.toUri = pj2Str(*to);
698
prm.contactUri = pj2Str(*contact);
699
prm.contentType = pj2Str(*mime_type);
700
prm.msgBody = pj2Str(*body);
701
prm.rdata.fromPj(*rdata);
703
if (call_id != PJSUA_INVALID_ID) {
704
Call *call = lookupCall(call_id, "on_pager2()");
710
call->onInstantMessage(prm);
712
Account *acc = lookupAcc(acc_id, "on_pager2()");
718
acc->onInstantMessage(prm);
722
void Endpoint::on_pager_status2( pjsua_call_id call_id,
724
const pj_str_t *body,
726
pjsip_status_code status,
727
const pj_str_t *reason,
728
pjsip_tx_data *tdata,
729
pjsip_rx_data *rdata,
732
PJ_UNUSED_ARG(tdata);
734
OnInstantMessageStatusParam prm;
735
prm.userData = user_data;
736
prm.toUri = pj2Str(*to);
737
prm.msgBody = pj2Str(*body);
739
prm.reason = pj2Str(*reason);
741
prm.rdata.fromPj(*rdata);
743
if (call_id != PJSUA_INVALID_ID) {
744
Call *call = lookupCall(call_id, "on_pager_status2()");
750
call->onInstantMessageStatus(prm);
752
Account *acc = lookupAcc(acc_id, "on_pager_status2()");
758
acc->onInstantMessageStatus(prm);
762
void Endpoint::on_typing2( pjsua_call_id call_id,
763
const pj_str_t *from,
765
const pj_str_t *contact,
767
pjsip_rx_data *rdata,
770
OnTypingIndicationParam prm;
771
prm.fromUri = pj2Str(*from);
772
prm.toUri = pj2Str(*to);
773
prm.contactUri = pj2Str(*contact);
774
prm.isTyping = is_typing != 0;
775
prm.rdata.fromPj(*rdata);
777
if (call_id != PJSUA_INVALID_ID) {
778
Call *call = lookupCall(call_id, "on_typing2()");
784
call->onTypingIndication(prm);
786
Account *acc = lookupAcc(acc_id, "on_typing2()");
792
acc->onTypingIndication(prm);
796
void Endpoint::on_mwi_info(pjsua_acc_id acc_id,
797
pjsua_mwi_info *mwi_info)
800
prm.state = pjsip_evsub_get_state(mwi_info->evsub);
801
prm.rdata.fromPj(*mwi_info->rdata);
803
Account *acc = lookupAcc(acc_id, "on_mwi_info()");
812
void Endpoint::on_buddy_state(pjsua_buddy_id buddy_id)
814
Buddy *buddy = (Buddy*)pjsua_buddy_get_user_data(buddy_id);
815
if (!buddy || !buddy->isValid()) {
820
buddy->onBuddyState();
824
void Endpoint::on_call_state(pjsua_call_id call_id, pjsip_event *e)
826
Call *call = Call::lookup(call_id);
831
OnCallStateParam prm;
834
call->processStateChange(prm);
835
/* If the state is DISCONNECTED, call may have already been deleted
836
* by the application in the callback, so do not access it anymore here.
840
void Endpoint::on_call_tsx_state(pjsua_call_id call_id,
841
pjsip_transaction *tsx,
846
Call *call = Call::lookup(call_id);
851
OnCallTsxStateParam prm;
854
call->onCallTsxState(prm);
857
void Endpoint::on_call_media_state(pjsua_call_id call_id)
859
Call *call = Call::lookup(call_id);
864
OnCallMediaStateParam prm;
865
call->processMediaUpdate(prm);
868
void Endpoint::on_call_sdp_created(pjsua_call_id call_id,
869
pjmedia_sdp_session *sdp,
871
const pjmedia_sdp_session *rem_sdp)
873
Call *call = Call::lookup(call_id);
878
OnCallSdpCreatedParam prm;
881
prm.sdp.fromPj(*sdp);
882
orig_sdp = prm.sdp.wholeSdp;
884
prm.remSdp.fromPj(*rem_sdp);
886
call->onCallSdpCreated(prm);
888
/* Check if application modifies the SDP */
889
if (orig_sdp != prm.sdp.wholeSdp) {
890
pjmedia_sdp_parse(pool, (char*)prm.sdp.wholeSdp.c_str(),
891
prm.sdp.wholeSdp.size(), &sdp);
895
void Endpoint::on_stream_created(pjsua_call_id call_id,
896
pjmedia_stream *strm,
898
pjmedia_port **p_port)
900
Call *call = Call::lookup(call_id);
905
OnStreamCreatedParam prm;
907
prm.streamIdx = stream_idx;
908
prm.pPort = (void *)*p_port;
910
call->onStreamCreated(prm);
912
if (prm.pPort != (void *)*p_port)
913
*p_port = (pjmedia_port *)prm.pPort;
916
void Endpoint::on_stream_destroyed(pjsua_call_id call_id,
917
pjmedia_stream *strm,
920
Call *call = Call::lookup(call_id);
925
OnStreamDestroyedParam prm;
927
prm.streamIdx = stream_idx;
929
call->onStreamDestroyed(prm);
932
struct PendingOnDtmfDigitCallback : public PendingJob
935
OnDtmfDigitParam prm;
937
virtual void execute(bool is_pending)
939
PJ_UNUSED_ARG(is_pending);
941
Call *call = Call::lookup(call_id);
945
call->onDtmfDigit(prm);
949
void Endpoint::on_dtmf_digit(pjsua_call_id call_id, int digit)
951
Call *call = Call::lookup(call_id);
956
PendingOnDtmfDigitCallback *job = new PendingOnDtmfDigitCallback;
957
job->call_id = call_id;
959
pj_ansi_sprintf(buf, "%c", digit);
960
job->prm.digit = (string)buf;
962
Endpoint::instance().utilAddPendingJob(job);
965
void Endpoint::on_call_transfer_request2(pjsua_call_id call_id,
967
pjsip_status_code *code,
968
pjsua_call_setting *opt)
970
Call *call = Call::lookup(call_id);
975
OnCallTransferRequestParam prm;
976
prm.dstUri = pj2Str(*dst);
977
prm.statusCode = *code;
978
prm.opt.fromPj(*opt);
980
call->onCallTransferRequest(prm);
982
*code = prm.statusCode;
983
*opt = prm.opt.toPj();
986
void Endpoint::on_call_transfer_status(pjsua_call_id call_id,
988
const pj_str_t *st_text,
992
Call *call = Call::lookup(call_id);
997
OnCallTransferStatusParam prm;
998
prm.statusCode = (pjsip_status_code)st_code;
999
prm.reason = pj2Str(*st_text);
1000
prm.finalNotify = PJ2BOOL(final);
1001
prm.cont = PJ2BOOL(*p_cont);
1003
call->onCallTransferStatus(prm);
1008
void Endpoint::on_call_replace_request2(pjsua_call_id call_id,
1009
pjsip_rx_data *rdata,
1012
pjsua_call_setting *opt)
1014
Call *call = Call::lookup(call_id);
1019
OnCallReplaceRequestParam prm;
1020
prm.rdata.fromPj(*rdata);
1021
prm.statusCode = (pjsip_status_code)*st_code;
1022
prm.reason = pj2Str(*st_text);
1023
prm.opt.fromPj(*opt);
1025
call->onCallReplaceRequest(prm);
1027
*st_code = prm.statusCode;
1028
*st_text = str2Pj(prm.reason);
1029
*opt = prm.opt.toPj();
1032
void Endpoint::on_call_replaced(pjsua_call_id old_call_id,
1033
pjsua_call_id new_call_id)
1035
Call *call = Call::lookup(old_call_id);
1040
OnCallReplacedParam prm;
1041
prm.newCallId = new_call_id;
1043
call->onCallReplaced(prm);
1046
void Endpoint::on_call_rx_offer(pjsua_call_id call_id,
1047
const pjmedia_sdp_session *offer,
1049
pjsip_status_code *code,
1050
pjsua_call_setting *opt)
1052
PJ_UNUSED_ARG(reserved);
1054
Call *call = Call::lookup(call_id);
1059
OnCallRxOfferParam prm;
1060
prm.offer.fromPj(*offer);
1061
prm.statusCode = *code;
1062
prm.opt.fromPj(*opt);
1064
call->onCallRxOffer(prm);
1066
*code = prm.statusCode;
1067
*opt = prm.opt.toPj();
1070
pjsip_redirect_op Endpoint::on_call_redirected(pjsua_call_id call_id,
1071
const pjsip_uri *target,
1072
const pjsip_event *e)
1074
Call *call = Call::lookup(call_id);
1076
return PJSIP_REDIRECT_STOP;
1079
OnCallRedirectedParam prm;
1080
char uristr[PJSIP_MAX_URL_SIZE];
1081
int len = pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, target, uristr,
1084
pj_ansi_strcpy(uristr, "--URI too long--");
1086
prm.targetUri = string(uristr);
1090
prm.e.type = PJSIP_EVENT_UNKNOWN;
1092
return call->onCallRedirected(prm);
1096
struct PendingOnMediaTransportCallback : public PendingJob
1099
OnCallMediaTransportStateParam prm;
1101
virtual void execute(bool is_pending)
1103
PJ_UNUSED_ARG(is_pending);
1105
Call *call = Call::lookup(call_id);
1109
call->onCallMediaTransportState(prm);
1114
Endpoint::on_call_media_transport_state(pjsua_call_id call_id,
1115
const pjsua_med_tp_state_info *info)
1117
Call *call = Call::lookup(call_id);
1122
PendingOnMediaTransportCallback *job = new PendingOnMediaTransportCallback;
1124
job->call_id = call_id;
1125
job->prm.medIdx = info->med_idx;
1126
job->prm.state = info->state;
1127
job->prm.status = info->status;
1128
job->prm.sipErrorCode = info->sip_err_code;
1130
Endpoint::instance().utilAddPendingJob(job);
1135
struct PendingOnMediaEventCallback : public PendingJob
1138
OnCallMediaEventParam prm;
1140
virtual void execute(bool is_pending)
1142
Call *call = Call::lookup(call_id);
1147
/* Can't do this anymore, pointer is invalid */
1148
prm.ev.pjMediaEvent = NULL;
1151
call->onCallMediaEvent(prm);
1155
void Endpoint::on_call_media_event(pjsua_call_id call_id,
1157
pjmedia_event *event)
1159
Call *call = Call::lookup(call_id);
1164
PendingOnMediaEventCallback *job = new PendingOnMediaEventCallback;
1166
job->call_id = call_id;
1167
job->prm.medIdx = med_idx;
1168
job->prm.ev.fromPj(*event);
1170
Endpoint::instance().utilAddPendingJob(job);
1174
Endpoint::on_create_media_transport(pjsua_call_id call_id,
1176
pjmedia_transport *base_tp,
1179
Call *call = Call::lookup(call_id);
1184
OnCreateMediaTransportParam prm;
1185
prm.mediaIdx = media_idx;
1186
prm.mediaTp = base_tp;
1189
call->onCreateMediaTransport(prm);
1191
return (pjmedia_transport *)prm.mediaTp;
1194
///////////////////////////////////////////////////////////////////////////////
1196
* Endpoint library operations
1198
Version Endpoint::libVersion() const
1201
ver.major = PJ_VERSION_NUM_MAJOR;
1202
ver.minor = PJ_VERSION_NUM_MINOR;
1203
ver.rev = PJ_VERSION_NUM_REV;
1204
ver.suffix = PJ_VERSION_NUM_EXTRA;
1205
ver.full = pj_get_version();
1206
ver.numeric = PJ_VERSION_NUM;
1210
void Endpoint::libCreate() throw(Error)
1212
PJSUA2_CHECK_EXPR( pjsua_create() );
1213
mainThread = pj_thread_this();
1216
pjsua_state Endpoint::libGetState() const
1218
return pjsua_get_state();
1221
void Endpoint::libInit(const EpConfig &prmEpConfig) throw(Error)
1223
pjsua_config ua_cfg;
1224
pjsua_logging_config log_cfg;
1225
pjsua_media_config med_cfg;
1227
ua_cfg = prmEpConfig.uaConfig.toPj();
1228
log_cfg = prmEpConfig.logConfig.toPj();
1229
med_cfg = prmEpConfig.medConfig.toPj();
1231
/* Setup log callback */
1232
if (prmEpConfig.logConfig.writer) {
1233
this->writer = prmEpConfig.logConfig.writer;
1234
log_cfg.cb = &Endpoint::logFunc;
1236
mainThreadOnly = prmEpConfig.uaConfig.mainThreadOnly;
1238
/* Setup UA callbacks */
1239
pj_bzero(&ua_cfg.cb, sizeof(ua_cfg.cb));
1240
ua_cfg.cb.on_nat_detect = &Endpoint::on_nat_detect;
1241
ua_cfg.cb.on_transport_state = &Endpoint::on_transport_state;
1243
ua_cfg.cb.on_incoming_call = &Endpoint::on_incoming_call;
1244
ua_cfg.cb.on_reg_started = &Endpoint::on_reg_started;
1245
ua_cfg.cb.on_reg_state2 = &Endpoint::on_reg_state2;
1246
ua_cfg.cb.on_incoming_subscribe = &Endpoint::on_incoming_subscribe;
1247
ua_cfg.cb.on_pager2 = &Endpoint::on_pager2;
1248
ua_cfg.cb.on_pager_status2 = &Endpoint::on_pager_status2;
1249
ua_cfg.cb.on_typing2 = &Endpoint::on_typing2;
1250
ua_cfg.cb.on_mwi_info = &Endpoint::on_mwi_info;
1251
ua_cfg.cb.on_buddy_state = &Endpoint::on_buddy_state;
1253
/* Call callbacks */
1254
ua_cfg.cb.on_call_state = &Endpoint::on_call_state;
1255
ua_cfg.cb.on_call_tsx_state = &Endpoint::on_call_tsx_state;
1256
ua_cfg.cb.on_call_media_state = &Endpoint::on_call_media_state;
1257
ua_cfg.cb.on_call_sdp_created = &Endpoint::on_call_sdp_created;
1258
ua_cfg.cb.on_stream_created = &Endpoint::on_stream_created;
1259
ua_cfg.cb.on_stream_destroyed = &Endpoint::on_stream_destroyed;
1260
ua_cfg.cb.on_dtmf_digit = &Endpoint::on_dtmf_digit;
1261
ua_cfg.cb.on_call_transfer_request2 = &Endpoint::on_call_transfer_request2;
1262
ua_cfg.cb.on_call_transfer_status = &Endpoint::on_call_transfer_status;
1263
ua_cfg.cb.on_call_replace_request2 = &Endpoint::on_call_replace_request2;
1264
ua_cfg.cb.on_call_replaced = &Endpoint::on_call_replaced;
1265
ua_cfg.cb.on_call_rx_offer = &Endpoint::on_call_rx_offer;
1266
ua_cfg.cb.on_call_redirected = &Endpoint::on_call_redirected;
1267
ua_cfg.cb.on_call_media_transport_state =
1268
&Endpoint::on_call_media_transport_state;
1269
ua_cfg.cb.on_call_media_event = &Endpoint::on_call_media_event;
1270
ua_cfg.cb.on_create_media_transport = &Endpoint::on_create_media_transport;
1273
PJSUA2_CHECK_EXPR( pjsua_init(&ua_cfg, &log_cfg, &med_cfg) );
1276
void Endpoint::libStart() throw(Error)
1278
PJSUA2_CHECK_EXPR(pjsua_start());
1281
void Endpoint::libRegisterWorkerThread(const string &name) throw(Error)
1283
PJSUA2_CHECK_EXPR(pjsua_register_worker_thread(name.c_str()));
1286
void Endpoint::libStopWorkerThreads()
1288
pjsua_stop_worker_threads();
1291
int Endpoint::libHandleEvents(unsigned msec_timeout)
1293
performPendingJobs();
1294
return pjsua_handle_events(msec_timeout);
1297
void Endpoint::libDestroy(unsigned flags) throw(Error)
1301
status = pjsua_destroy2(flags);
1303
delete this->writer;
1304
this->writer = NULL;
1306
if (pj_log_get_log_func() == &Endpoint::logFunc) {
1307
pj_log_set_log_func(NULL);
1310
PJSUA2_CHECK_RAISE_ERROR(status);
1313
///////////////////////////////////////////////////////////////////////////////
1315
* Endpoint Utilities
1317
string Endpoint::utilStrError(pj_status_t prmErr)
1319
char errmsg[PJ_ERR_MSG_SIZE];
1320
pj_strerror(prmErr, errmsg, sizeof(errmsg));
1324
static void ept_log_write(int level, const char *sender,
1325
const char *format, ...)
1328
va_start(arg, format);
1329
pj_log(sender, level, format, arg );
1333
void Endpoint::utilLogWrite(int prmLevel,
1334
const string &prmSender,
1335
const string &prmMsg)
1337
ept_log_write(prmLevel, prmSender.c_str(), "%s", prmMsg.c_str());
1340
pj_status_t Endpoint::utilVerifySipUri(const string &prmUri)
1342
return pjsua_verify_sip_url(prmUri.c_str());
1345
pj_status_t Endpoint::utilVerifyUri(const string &prmUri)
1347
return pjsua_verify_url(prmUri.c_str());
1350
Token Endpoint::utilTimerSchedule(unsigned prmMsecDelay,
1351
Token prmUserData) throw (Error)
1358
ut->signature = TIMER_SIGNATURE;
1359
ut->prm.msecDelay = prmMsecDelay;
1360
ut->prm.userData = prmUserData;
1361
pj_timer_entry_init(&ut->entry, 1, ut, &Endpoint::on_timer);
1364
delay.msec = prmMsecDelay;
1365
pj_time_val_normalize(&delay);
1367
status = pjsua_schedule_timer(&ut->entry, &delay);
1368
if (status != PJ_SUCCESS) {
1370
PJSUA2_CHECK_RAISE_ERROR(status);
1376
void Endpoint::utilTimerCancel(Token prmTimerToken)
1378
UserTimer *ut = (UserTimer*)(void*)prmTimerToken;
1380
if (ut->signature != TIMER_SIGNATURE) {
1381
PJ_LOG(1,(THIS_FILE,
1382
"Invalid timer token in Endpoint::utilTimerCancel()"));
1387
ut->signature = 0xFFFFFFFE;
1388
pjsua_cancel_timer(&ut->entry);
1393
IntVector Endpoint::utilSslGetAvailableCiphers() throw (Error)
1396
pj_ssl_cipher ciphers[64];
1397
unsigned count = PJ_ARRAY_SIZE(ciphers);
1399
PJSUA2_CHECK_EXPR( pj_ssl_cipher_get_availables(ciphers, &count) );
1401
return IntVector(ciphers, ciphers + count);
1407
///////////////////////////////////////////////////////////////////////////////
1409
* Endpoint NAT operations
1411
void Endpoint::natDetectType(void) throw(Error)
1413
PJSUA2_CHECK_EXPR( pjsua_detect_nat_type() );
1416
pj_stun_nat_type Endpoint::natGetType() throw(Error)
1418
pj_stun_nat_type type;
1420
PJSUA2_CHECK_EXPR( pjsua_get_nat_type(&type) );
1425
void Endpoint::natCheckStunServers(const StringVector &servers,
1427
Token token) throw(Error)
1429
pj_str_t srv[MAX_STUN_SERVERS];
1430
unsigned i, count = 0;
1432
for (i=0; i<servers.size() && i<MAX_STUN_SERVERS; ++i) {
1433
srv[count].ptr = (char*)servers[i].c_str();
1434
srv[count].slen = servers[i].size();
1438
PJSUA2_CHECK_EXPR(pjsua_resolve_stun_servers(count, srv, wait, token,
1439
&Endpoint::stun_resolve_cb) );
1442
void Endpoint::natCancelCheckStunServers(Token token,
1443
bool notify_cb) throw(Error)
1445
PJSUA2_CHECK_EXPR( pjsua_cancel_stun_resolution(token, notify_cb) );
1448
///////////////////////////////////////////////////////////////////////////////
1452
TransportId Endpoint::transportCreate(pjsip_transport_type_e type,
1453
const TransportConfig &cfg) throw(Error)
1455
pjsua_transport_config tcfg;
1456
pjsua_transport_id tid;
1459
PJSUA2_CHECK_EXPR( pjsua_transport_create(type,
1465
IntVector Endpoint::transportEnum() throw(Error)
1467
pjsua_transport_id tids[32];
1468
unsigned count = PJ_ARRAY_SIZE(tids);
1470
PJSUA2_CHECK_EXPR( pjsua_enum_transports(tids, &count) );
1472
return IntVector(tids, tids+count);
1475
TransportInfo Endpoint::transportGetInfo(TransportId id) throw(Error)
1477
pjsua_transport_info pj_tinfo;
1478
TransportInfo tinfo;
1480
PJSUA2_CHECK_EXPR( pjsua_transport_get_info(id, &pj_tinfo) );
1481
tinfo.fromPj(pj_tinfo);
1486
void Endpoint::transportSetEnable(TransportId id, bool enabled) throw(Error)
1488
PJSUA2_CHECK_EXPR( pjsua_transport_set_enable(id, enabled) );
1491
void Endpoint::transportClose(TransportId id) throw(Error)
1493
PJSUA2_CHECK_EXPR( pjsua_transport_close(id, PJ_FALSE) );
1496
///////////////////////////////////////////////////////////////////////////////
1501
void Endpoint::hangupAllCalls(void)
1503
pjsua_call_hangup_all();
1506
///////////////////////////////////////////////////////////////////////////////
1510
unsigned Endpoint::mediaMaxPorts() const
1512
return pjsua_conf_get_max_ports();
1515
unsigned Endpoint::mediaActivePorts() const
1517
return pjsua_conf_get_active_ports();
1520
const AudioMediaVector &Endpoint::mediaEnumPorts() const throw(Error)
1525
void Endpoint::mediaAdd(AudioMedia &media)
1527
if (mediaExists(media))
1530
mediaList.push_back(&media);
1533
void Endpoint::mediaRemove(AudioMedia &media)
1535
AudioMediaVector::iterator it = std::find(mediaList.begin(),
1539
if (it != mediaList.end())
1540
mediaList.erase(it);
1544
bool Endpoint::mediaExists(const AudioMedia &media) const
1546
AudioMediaVector::const_iterator it = std::find(mediaList.begin(),
1550
return (it != mediaList.end());
1553
AudDevManager &Endpoint::audDevManager()
1561
const CodecInfoVector &Endpoint::codecEnum() throw(Error)
1563
pjsua_codec_info pj_codec[MAX_CODEC_NUM];
1564
unsigned count = MAX_CODEC_NUM;
1566
PJSUA2_CHECK_EXPR( pjsua_enum_codecs(pj_codec, &count) );
1568
pj_enter_critical_section();
1569
clearCodecInfoList();
1570
for (unsigned i=0; i<count; ++i) {
1571
CodecInfo *codec_info = new CodecInfo;
1573
codec_info->fromPj(pj_codec[i]);
1574
codecInfoList.push_back(codec_info);
1576
pj_leave_critical_section();
1577
return codecInfoList;
1580
void Endpoint::codecSetPriority(const string &codec_id,
1581
pj_uint8_t priority) throw(Error)
1583
pj_str_t codec_str = str2Pj(codec_id);
1584
PJSUA2_CHECK_EXPR( pjsua_codec_set_priority(&codec_str, priority) );
1587
CodecParam Endpoint::codecGetParam(const string &codec_id) const throw(Error)
1589
pjmedia_codec_param *pj_param = NULL;
1590
pj_str_t codec_str = str2Pj(codec_id);
1592
PJSUA2_CHECK_EXPR( pjsua_codec_get_param(&codec_str, pj_param) );
1597
void Endpoint::codecSetParam(const string &codec_id,
1598
const CodecParam param) throw(Error)
1600
pj_str_t codec_str = str2Pj(codec_id);
1601
pjmedia_codec_param *pj_param = (pjmedia_codec_param*)param;
1603
PJSUA2_CHECK_EXPR( pjsua_codec_set_param(&codec_str, pj_param) );
1606
void Endpoint::clearCodecInfoList()
1608
for (unsigned i=0;i<codecInfoList.size();++i) {
1609
delete codecInfoList[i];
1611
codecInfoList.clear();