~ubuntu-branches/ubuntu/wily/sflphone/wily

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.2.1/pjsip/src/pjsua2/endpoint.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2015-01-07 14:51:16 UTC
  • mfrom: (4.3.5 sid)
  • Revision ID: package-import@ubuntu.com-20150107145116-yxnafinf4lrdvrmx
Tags: 1.4.1-0.1ubuntu1
* Merge with Debian, remaining changes:
 - Drop soprano, nepomuk build-dep
* Drop ubuntu patches, now upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: endpoint.cpp 4776 2014-03-04 04:25:31Z ming $ */
 
2
/* 
 
3
 * Copyright (C) 2013 Teluu Inc. (http://www.teluu.com)
 
4
 *
 
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.
 
9
 *
 
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.
 
14
 *
 
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 
 
18
 */
 
19
#include <pjsua2/endpoint.hpp>
 
20
#include <pjsua2/account.hpp>
 
21
#include <pjsua2/call.hpp>
 
22
#include <pjsua2/presence.hpp>
 
23
#include <algorithm>
 
24
#include "util.hpp"
 
25
 
 
26
using namespace pj;
 
27
using namespace std;
 
28
 
 
29
#include <pjsua2/account.hpp>
 
30
#include <pjsua2/call.hpp>
 
31
 
 
32
#define THIS_FILE               "endpoint.cpp"
 
33
#define MAX_STUN_SERVERS        32
 
34
#define TIMER_SIGNATURE         0x600D878A
 
35
#define MAX_CODEC_NUM           64
 
36
 
 
37
struct UserTimer
 
38
{
 
39
    pj_uint32_t         signature;
 
40
    OnTimerParam        prm;
 
41
    pj_timer_entry      entry;
 
42
};
 
43
 
 
44
Endpoint *Endpoint::instance_;
 
45
 
 
46
///////////////////////////////////////////////////////////////////////////////
 
47
 
 
48
UaConfig::UaConfig()
 
49
{
 
50
    pjsua_config ua_cfg;
 
51
 
 
52
    pjsua_config_default(&ua_cfg);
 
53
    fromPj(ua_cfg);
 
54
}
 
55
 
 
56
void UaConfig::fromPj(const pjsua_config &ua_cfg)
 
57
{
 
58
    unsigned i;
 
59
 
 
60
    this->maxCalls = ua_cfg.max_calls;
 
61
    this->threadCnt = ua_cfg.thread_cnt;
 
62
    this->userAgent = pj2Str(ua_cfg.user_agent);
 
63
 
 
64
    for (i=0; i<ua_cfg.nameserver_count; ++i) {
 
65
        this->nameserver.push_back(pj2Str(ua_cfg.nameserver[i]));
 
66
    }
 
67
 
 
68
    for (i=0; i<ua_cfg.stun_srv_cnt; ++i) {
 
69
        this->stunServer.push_back(pj2Str(ua_cfg.stun_srv[i]));
 
70
    }
 
71
 
 
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);
 
75
}
 
76
 
 
77
pjsua_config UaConfig::toPj() const
 
78
{
 
79
    unsigned i;
 
80
    pjsua_config pua_cfg;
 
81
 
 
82
    pjsua_config_default(&pua_cfg);
 
83
 
 
84
    pua_cfg.max_calls = this->maxCalls;
 
85
    pua_cfg.thread_cnt = this->threadCnt;
 
86
    pua_cfg.user_agent = str2Pj(this->userAgent);
 
87
 
 
88
    for (i=0; i<this->nameserver.size() && i<PJ_ARRAY_SIZE(pua_cfg.nameserver);
 
89
         ++i)
 
90
    {
 
91
        pua_cfg.nameserver[i] = str2Pj(this->nameserver[i]);
 
92
    }
 
93
    pua_cfg.nameserver_count = i;
 
94
 
 
95
    for (i=0; i<this->stunServer.size() && i<PJ_ARRAY_SIZE(pua_cfg.stun_srv);
 
96
         ++i)
 
97
    {
 
98
        pua_cfg.stun_srv[i] = str2Pj(this->stunServer[i]);
 
99
    }
 
100
    pua_cfg.stun_srv_cnt = i;
 
101
 
 
102
    pua_cfg.nat_type_in_sdp = this->natTypeInSdp;
 
103
    pua_cfg.enable_unsolicited_mwi = this->mwiUnsolicitedEnabled;
 
104
 
 
105
    return pua_cfg;
 
106
}
 
107
 
 
108
void UaConfig::readObject(const ContainerNode &node) throw(Error)
 
109
{
 
110
    ContainerNode this_node = node.readContainer("UaConfig");
 
111
 
 
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);
 
121
}
 
122
 
 
123
void UaConfig::writeObject(ContainerNode &node) const throw(Error)
 
124
{
 
125
    ContainerNode this_node = node.writeNewContainer("UaConfig");
 
126
 
 
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);
 
136
}
 
137
 
 
138
///////////////////////////////////////////////////////////////////////////////
 
139
 
 
140
LogConfig::LogConfig()
 
141
{
 
142
    pjsua_logging_config lc;
 
143
 
 
144
    pjsua_logging_config_default(&lc);
 
145
    fromPj(lc);
 
146
}
 
147
 
 
148
void LogConfig::fromPj(const pjsua_logging_config &lc)
 
149
{
 
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;
 
156
    this->writer = NULL;
 
157
}
 
158
 
 
159
pjsua_logging_config LogConfig::toPj() const
 
160
{
 
161
    pjsua_logging_config lc;
 
162
 
 
163
    pjsua_logging_config_default(&lc);
 
164
 
 
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);
 
171
 
 
172
    return lc;
 
173
}
 
174
 
 
175
void LogConfig::readObject(const ContainerNode &node) throw(Error)
 
176
{
 
177
    ContainerNode this_node = node.readContainer("LogConfig");
 
178
 
 
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);
 
185
}
 
186
 
 
187
void LogConfig::writeObject(ContainerNode &node) const throw(Error)
 
188
{
 
189
    ContainerNode this_node = node.writeNewContainer("LogConfig");
 
190
 
 
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);
 
197
}
 
198
 
 
199
///////////////////////////////////////////////////////////////////////////////
 
200
 
 
201
MediaConfig::MediaConfig()
 
202
{
 
203
    pjsua_media_config mc;
 
204
 
 
205
    pjsua_media_config_default(&mc);
 
206
    fromPj(mc);
 
207
}
 
208
 
 
209
void MediaConfig::fromPj(const pjsua_media_config &mc)
 
210
{
 
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);
 
234
}
 
235
 
 
236
pjsua_media_config MediaConfig::toPj() const
 
237
{
 
238
    pjsua_media_config mcfg;
 
239
 
 
240
    pjsua_media_config_default(&mcfg);
 
241
 
 
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;
 
265
 
 
266
    return mcfg;
 
267
}
 
268
 
 
269
void MediaConfig::readObject(const ContainerNode &node) throw(Error)
 
270
{
 
271
    ContainerNode this_node = node.readContainer("MediaConfig");
 
272
 
 
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);
 
296
}
 
297
 
 
298
void MediaConfig::writeObject(ContainerNode &node) const throw(Error)
 
299
{
 
300
    ContainerNode this_node = node.writeNewContainer("MediaConfig");
 
301
 
 
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);
 
325
}
 
326
 
 
327
///////////////////////////////////////////////////////////////////////////////
 
328
 
 
329
void EpConfig::readObject(const ContainerNode &node) throw(Error)
 
330
{
 
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);
 
335
}
 
336
 
 
337
void EpConfig::writeObject(ContainerNode &node) const throw(Error)
 
338
{
 
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);
 
343
}
 
344
 
 
345
///////////////////////////////////////////////////////////////////////////////
 
346
/* Class to post log to main thread */
 
347
struct PendingLog : public PendingJob
 
348
{
 
349
    LogEntry entry;
 
350
    virtual void execute(bool is_pending)
 
351
    {
 
352
        PJ_UNUSED_ARG(is_pending);
 
353
        Endpoint::instance().utilLogWrite(entry);
 
354
    }
 
355
};
 
356
 
 
357
///////////////////////////////////////////////////////////////////////////////
 
358
/*
 
359
 * Endpoint instance
 
360
 */
 
361
Endpoint::Endpoint()
 
362
: writer(NULL), mainThreadOnly(false), mainThread(NULL), pendingJobSize(0)
 
363
{
 
364
    if (instance_) {
 
365
        PJSUA2_RAISE_ERROR(PJ_EEXISTS);
 
366
    }
 
367
 
 
368
    instance_ = this;
 
369
}
 
370
 
 
371
Endpoint& Endpoint::instance() throw(Error)
 
372
{
 
373
    if (!instance_) {
 
374
        PJSUA2_RAISE_ERROR(PJ_ENOTFOUND);
 
375
    }
 
376
    return *instance_;
 
377
}
 
378
 
 
379
Endpoint::~Endpoint()
 
380
{
 
381
    while (!pendingJobs.empty()) {
 
382
        delete pendingJobs.front();
 
383
        pendingJobs.pop_front();
 
384
    }
 
385
 
 
386
    while(mediaList.size() > 0) {
 
387
        AudioMedia *cur_media = mediaList[0];
 
388
        delete cur_media; /* this will remove itself from the list */
 
389
    }
 
390
 
 
391
    clearCodecInfoList();
 
392
 
 
393
    try {
 
394
        libDestroy();
 
395
    } catch (Error &err) {
 
396
        // Ignore
 
397
        PJ_UNUSED_ARG(err);
 
398
    }
 
399
 
 
400
    instance_ = NULL;
 
401
}
 
402
 
 
403
void Endpoint::utilAddPendingJob(PendingJob *job)
 
404
{
 
405
    enum {
 
406
        MAX_PENDING_JOBS = 1024
 
407
    };
 
408
 
 
409
    /* See if we can execute immediately */
 
410
    if (!mainThreadOnly || pj_thread_this()==mainThread) {
 
411
        job->execute(false);
 
412
        delete job;
 
413
        return;
 
414
    }
 
415
 
 
416
    if (pendingJobSize > MAX_PENDING_JOBS) {
 
417
        enum { NUMBER_TO_DISCARD = 5 };
 
418
 
 
419
        pj_enter_critical_section();
 
420
        for (unsigned i=0; i<NUMBER_TO_DISCARD; ++i) {
 
421
            delete pendingJobs.back();
 
422
            pendingJobs.pop_back();
 
423
        }
 
424
 
 
425
        pendingJobSize -= NUMBER_TO_DISCARD;
 
426
        pj_leave_critical_section();
 
427
 
 
428
        utilLogWrite(1, THIS_FILE,
 
429
                     "*** ERROR: Job queue full!! Jobs discarded!!! ***");
 
430
    }
 
431
 
 
432
    pj_enter_critical_section();
 
433
    pendingJobs.push_back(job);
 
434
    pendingJobSize++;
 
435
    pj_leave_critical_section();
 
436
}
 
437
 
 
438
/* Handle log callback */
 
439
void Endpoint::utilLogWrite(LogEntry &entry)
 
440
{
 
441
    if (mainThreadOnly && pj_thread_this() != mainThread) {
 
442
        PendingLog *job = new PendingLog;
 
443
        job->entry = entry;
 
444
        utilAddPendingJob(job);
 
445
    } else {
 
446
        writer->write(entry);
 
447
    }
 
448
}
 
449
 
 
450
/* Run pending jobs only in main thread */
 
451
void Endpoint::performPendingJobs()
 
452
{
 
453
    if (pj_thread_this() != mainThread)
 
454
        return;
 
455
 
 
456
    if (pendingJobSize == 0)
 
457
        return;
 
458
 
 
459
    for (;;) {
 
460
        PendingJob *job = NULL;
 
461
 
 
462
        pj_enter_critical_section();
 
463
        if (pendingJobSize != 0) {
 
464
            job = pendingJobs.front();
 
465
            pendingJobs.pop_front();
 
466
            pendingJobSize--;
 
467
        }
 
468
        pj_leave_critical_section();
 
469
 
 
470
        if (job) {
 
471
            job->execute(true);
 
472
            delete job;
 
473
        } else
 
474
            break;
 
475
    }
 
476
}
 
477
 
 
478
///////////////////////////////////////////////////////////////////////////////
 
479
/*
 
480
 * Endpoint static callbacks
 
481
 */
 
482
void Endpoint::logFunc(int level, const char *data, int len)
 
483
{
 
484
    Endpoint &ep = Endpoint::instance();
 
485
 
 
486
    if (!ep.writer)
 
487
        return;
 
488
 
 
489
    LogEntry entry;
 
490
    entry.level = level;
 
491
    entry.msg = string(data, len);
 
492
    entry.threadId = (long)pj_thread_this();
 
493
    entry.threadName = string(pj_thread_get_name(pj_thread_this()));
 
494
 
 
495
    ep.utilLogWrite(entry);
 
496
}
 
497
 
 
498
void Endpoint::stun_resolve_cb(const pj_stun_resolve_result *res)
 
499
{
 
500
    Endpoint &ep = Endpoint::instance();
 
501
 
 
502
    if (!res)
 
503
        return;
 
504
 
 
505
    OnNatCheckStunServersCompleteParam prm;
 
506
 
 
507
    prm.userData = res->token;
 
508
    prm.status = res->status;
 
509
    if (res->status == PJ_SUCCESS) {
 
510
        char straddr[PJ_INET6_ADDRSTRLEN+10];
 
511
 
 
512
        prm.name = string(res->name.ptr, res->name.slen);
 
513
        pj_sockaddr_print(&res->addr, straddr, sizeof(straddr), 3);
 
514
        prm.addr = straddr;
 
515
    }
 
516
 
 
517
    ep.onNatCheckStunServersComplete(prm);
 
518
}
 
519
 
 
520
void Endpoint::on_timer(pj_timer_heap_t *timer_heap,
 
521
                        pj_timer_entry *entry)
 
522
{
 
523
    PJ_UNUSED_ARG(timer_heap);
 
524
 
 
525
    Endpoint &ep = Endpoint::instance();
 
526
    UserTimer *ut = (UserTimer*) entry->user_data;
 
527
 
 
528
    if (ut->signature != TIMER_SIGNATURE)
 
529
        return;
 
530
 
 
531
    ep.onTimer(ut->prm);
 
532
}
 
533
 
 
534
void Endpoint::on_nat_detect(const pj_stun_nat_detect_result *res)
 
535
{
 
536
    Endpoint &ep = Endpoint::instance();
 
537
 
 
538
    if (!res)
 
539
        return;
 
540
 
 
541
    OnNatDetectionCompleteParam prm;
 
542
 
 
543
    prm.status = res->status;
 
544
    prm.reason = res->status_text;
 
545
    prm.natType = res->nat_type;
 
546
    prm.natTypeName = res->nat_type_name;
 
547
 
 
548
    ep.onNatDetectionComplete(prm);
 
549
}
 
550
 
 
551
void Endpoint::on_transport_state( pjsip_transport *tp,
 
552
                                   pjsip_transport_state state,
 
553
                                   const pjsip_transport_state_info *info)
 
554
{
 
555
    Endpoint &ep = Endpoint::instance();
 
556
 
 
557
    OnTransportStateParam prm;
 
558
 
 
559
    prm.hnd = (TransportHandle)tp;
 
560
    prm.state = state;
 
561
    prm.lastError = info ? info->status : PJ_SUCCESS;
 
562
 
 
563
    ep.onTransportState(prm);
 
564
}
 
565
 
 
566
///////////////////////////////////////////////////////////////////////////////
 
567
/*
 
568
 * Account static callbacks
 
569
 */
 
570
 
 
571
Account *Endpoint::lookupAcc(int acc_id, const char *op)
 
572
{
 
573
    Account *acc = Account::lookup(acc_id);
 
574
    if (!acc) {
 
575
        PJ_LOG(1,(THIS_FILE,
 
576
                  "Error: cannot find Account instance for account id %d in "
 
577
                  "%s", acc_id, op));
 
578
    }
 
579
 
 
580
    return acc;
 
581
}
 
582
 
 
583
Call *Endpoint::lookupCall(int call_id, const char *op)
 
584
{
 
585
    Call *call = Call::lookup(call_id);
 
586
    if (!call) {
 
587
        PJ_LOG(1,(THIS_FILE,
 
588
                  "Error: cannot find Call instance for call id %d in "
 
589
                  "%s", call_id, op));
 
590
    }
 
591
 
 
592
    return call;
 
593
}
 
594
 
 
595
void Endpoint::on_incoming_call(pjsua_acc_id acc_id, pjsua_call_id call_id,
 
596
                                pjsip_rx_data *rdata)
 
597
{
 
598
    Account *acc = lookupAcc(acc_id, "on_incoming_call()");
 
599
    if (!acc) {
 
600
        pjsua_call_hangup(call_id, PJSIP_SC_INTERNAL_SERVER_ERROR, NULL, NULL);
 
601
        return;
 
602
    }
 
603
 
 
604
    /* call callback */
 
605
    OnIncomingCallParam prm;
 
606
    prm.callId = call_id;
 
607
    prm.rdata.fromPj(*rdata);
 
608
 
 
609
    acc->onIncomingCall(prm);
 
610
 
 
611
    /* disconnect if callback doesn't handle the call */
 
612
    pjsua_call_info ci;
 
613
 
 
614
    pjsua_call_get_info(call_id, &ci);
 
615
    if (!pjsua_call_get_user_data(call_id) &&
 
616
        ci.state != PJSIP_INV_STATE_DISCONNECTED)
 
617
    {
 
618
        pjsua_call_hangup(call_id, PJSIP_SC_INTERNAL_SERVER_ERROR, NULL, NULL);
 
619
    }
 
620
}
 
621
 
 
622
void Endpoint::on_reg_started(pjsua_acc_id acc_id, pj_bool_t renew)
 
623
{
 
624
    Account *acc = lookupAcc(acc_id, "on_reg_started()");
 
625
    if (!acc) {
 
626
        return;
 
627
    }
 
628
 
 
629
    OnRegStartedParam prm;
 
630
    prm.renew = PJ2BOOL(renew);
 
631
    acc->onRegStarted(prm);
 
632
}
 
633
 
 
634
void Endpoint::on_reg_state2(pjsua_acc_id acc_id, pjsua_reg_info *info)
 
635
{
 
636
    Account *acc = lookupAcc(acc_id, "on_reg_state2()");
 
637
    if (!acc) {
 
638
        return;
 
639
    }
 
640
 
 
641
    OnRegStateParam prm;
 
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;
 
648
 
 
649
    acc->onRegState(prm);
 
650
}
 
651
 
 
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,
 
658
                                     pj_str_t *reason,
 
659
                                     pjsua_msg_data *msg_data)
 
660
{
 
661
    PJ_UNUSED_ARG(buddy_id);
 
662
    PJ_UNUSED_ARG(srv_pres);
 
663
 
 
664
    Account *acc = lookupAcc(acc_id, "on_incoming_subscribe()");
 
665
    if (!acc) {
 
666
        /* default behavior should apply */
 
667
        return;
 
668
    }
 
669
 
 
670
    OnIncomingSubscribeParam prm;
 
671
    prm.srvPres         = srv_pres;
 
672
    prm.fromUri         = pj2Str(*from);
 
673
    prm.rdata.fromPj(*rdata);
 
674
    prm.code            = *code;
 
675
    prm.reason          = pj2Str(*reason);
 
676
    prm.txOption.fromPj(*msg_data);
 
677
 
 
678
    acc->onIncomingSubscribe(prm);
 
679
 
 
680
    *code = prm.code;
 
681
    acc->tmpReason = prm.reason;
 
682
    *reason = str2Pj(acc->tmpReason);
 
683
    prm.txOption.toPj(*msg_data);
 
684
}
 
685
 
 
686
void Endpoint::on_pager2(pjsua_call_id call_id,
 
687
                         const pj_str_t *from,
 
688
                         const pj_str_t *to,
 
689
                         const pj_str_t *contact,
 
690
                         const pj_str_t *mime_type,
 
691
                         const pj_str_t *body,
 
692
                         pjsip_rx_data *rdata,
 
693
                         pjsua_acc_id acc_id)
 
694
{
 
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);
 
702
 
 
703
    if (call_id != PJSUA_INVALID_ID) {
 
704
        Call *call = lookupCall(call_id, "on_pager2()");
 
705
        if (!call) {
 
706
            /* Ignored */
 
707
            return;
 
708
        }
 
709
 
 
710
        call->onInstantMessage(prm);
 
711
    } else {
 
712
        Account *acc = lookupAcc(acc_id, "on_pager2()");
 
713
        if (!acc) {
 
714
            /* Ignored */
 
715
            return;
 
716
        }
 
717
 
 
718
        acc->onInstantMessage(prm);
 
719
    }
 
720
}
 
721
 
 
722
void Endpoint::on_pager_status2( pjsua_call_id call_id,
 
723
                                 const pj_str_t *to,
 
724
                                 const pj_str_t *body,
 
725
                                 void *user_data,
 
726
                                 pjsip_status_code status,
 
727
                                 const pj_str_t *reason,
 
728
                                 pjsip_tx_data *tdata,
 
729
                                 pjsip_rx_data *rdata,
 
730
                                 pjsua_acc_id acc_id)
 
731
{
 
732
    PJ_UNUSED_ARG(tdata);
 
733
 
 
734
    OnInstantMessageStatusParam prm;
 
735
    prm.userData        = user_data;
 
736
    prm.toUri           = pj2Str(*to);
 
737
    prm.msgBody         = pj2Str(*body);
 
738
    prm.code            = status;
 
739
    prm.reason          = pj2Str(*reason);
 
740
    if (rdata)
 
741
        prm.rdata.fromPj(*rdata);
 
742
 
 
743
    if (call_id != PJSUA_INVALID_ID) {
 
744
        Call *call = lookupCall(call_id, "on_pager_status2()");
 
745
        if (!call) {
 
746
            /* Ignored */
 
747
            return;
 
748
        }
 
749
 
 
750
        call->onInstantMessageStatus(prm);
 
751
    } else {
 
752
        Account *acc = lookupAcc(acc_id, "on_pager_status2()");
 
753
        if (!acc) {
 
754
            /* Ignored */
 
755
            return;
 
756
        }
 
757
 
 
758
        acc->onInstantMessageStatus(prm);
 
759
    }
 
760
}
 
761
 
 
762
void Endpoint::on_typing2( pjsua_call_id call_id,
 
763
                           const pj_str_t *from,
 
764
                           const pj_str_t *to,
 
765
                           const pj_str_t *contact,
 
766
                           pj_bool_t is_typing,
 
767
                           pjsip_rx_data *rdata,
 
768
                           pjsua_acc_id acc_id)
 
769
{
 
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);
 
776
 
 
777
    if (call_id != PJSUA_INVALID_ID) {
 
778
        Call *call = lookupCall(call_id, "on_typing2()");
 
779
        if (!call) {
 
780
            /* Ignored */
 
781
            return;
 
782
        }
 
783
 
 
784
        call->onTypingIndication(prm);
 
785
    } else {
 
786
        Account *acc = lookupAcc(acc_id, "on_typing2()");
 
787
        if (!acc) {
 
788
            /* Ignored */
 
789
            return;
 
790
        }
 
791
 
 
792
        acc->onTypingIndication(prm);
 
793
    }
 
794
}
 
795
 
 
796
void Endpoint::on_mwi_info(pjsua_acc_id acc_id,
 
797
                           pjsua_mwi_info *mwi_info)
 
798
{
 
799
    OnMwiInfoParam prm;
 
800
    prm.state   = pjsip_evsub_get_state(mwi_info->evsub);
 
801
    prm.rdata.fromPj(*mwi_info->rdata);
 
802
 
 
803
    Account *acc = lookupAcc(acc_id, "on_mwi_info()");
 
804
    if (!acc) {
 
805
        /* Ignored */
 
806
        return;
 
807
    }
 
808
 
 
809
    acc->onMwiInfo(prm);
 
810
}
 
811
 
 
812
void Endpoint::on_buddy_state(pjsua_buddy_id buddy_id)
 
813
{
 
814
    Buddy *buddy = (Buddy*)pjsua_buddy_get_user_data(buddy_id);
 
815
    if (!buddy || !buddy->isValid()) {
 
816
        /* Ignored */
 
817
        return;
 
818
    }
 
819
 
 
820
    buddy->onBuddyState();
 
821
}
 
822
 
 
823
// Call callbacks
 
824
void Endpoint::on_call_state(pjsua_call_id call_id, pjsip_event *e)
 
825
{
 
826
    Call *call = Call::lookup(call_id);
 
827
    if (!call) {
 
828
        return;
 
829
    }
 
830
    
 
831
    OnCallStateParam prm;
 
832
    prm.e.fromPj(*e);
 
833
    
 
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.
 
837
     */
 
838
}
 
839
 
 
840
void Endpoint::on_call_tsx_state(pjsua_call_id call_id,
 
841
                                 pjsip_transaction *tsx,
 
842
                                 pjsip_event *e)
 
843
{
 
844
    PJ_UNUSED_ARG(tsx);
 
845
 
 
846
    Call *call = Call::lookup(call_id);
 
847
    if (!call) {
 
848
        return;
 
849
    }
 
850
    
 
851
    OnCallTsxStateParam prm;
 
852
    prm.e.fromPj(*e);
 
853
    
 
854
    call->onCallTsxState(prm);
 
855
}
 
856
 
 
857
void Endpoint::on_call_media_state(pjsua_call_id call_id)
 
858
{
 
859
    Call *call = Call::lookup(call_id);
 
860
    if (!call) {
 
861
        return;
 
862
    }
 
863
 
 
864
    OnCallMediaStateParam prm;
 
865
    call->processMediaUpdate(prm);
 
866
}
 
867
 
 
868
void Endpoint::on_call_sdp_created(pjsua_call_id call_id,
 
869
                                   pjmedia_sdp_session *sdp,
 
870
                                   pj_pool_t *pool,
 
871
                                   const pjmedia_sdp_session *rem_sdp)
 
872
{
 
873
    Call *call = Call::lookup(call_id);
 
874
    if (!call) {
 
875
        return;
 
876
    }
 
877
    
 
878
    OnCallSdpCreatedParam prm;
 
879
    string orig_sdp;
 
880
    
 
881
    prm.sdp.fromPj(*sdp);
 
882
    orig_sdp = prm.sdp.wholeSdp;
 
883
    if (rem_sdp)
 
884
        prm.remSdp.fromPj(*rem_sdp);
 
885
    
 
886
    call->onCallSdpCreated(prm);
 
887
    
 
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);
 
892
    }
 
893
}
 
894
 
 
895
void Endpoint::on_stream_created(pjsua_call_id call_id,
 
896
                                 pjmedia_stream *strm,
 
897
                                 unsigned stream_idx,
 
898
                                 pjmedia_port **p_port)
 
899
{
 
900
    Call *call = Call::lookup(call_id);
 
901
    if (!call) {
 
902
        return;
 
903
    }
 
904
    
 
905
    OnStreamCreatedParam prm;
 
906
    prm.stream = strm;
 
907
    prm.streamIdx = stream_idx;
 
908
    prm.pPort = (void *)*p_port;
 
909
    
 
910
    call->onStreamCreated(prm);
 
911
    
 
912
    if (prm.pPort != (void *)*p_port)
 
913
        *p_port = (pjmedia_port *)prm.pPort;
 
914
}
 
915
 
 
916
void Endpoint::on_stream_destroyed(pjsua_call_id call_id,
 
917
                                   pjmedia_stream *strm,
 
918
                                   unsigned stream_idx)
 
919
{
 
920
    Call *call = Call::lookup(call_id);
 
921
    if (!call) {
 
922
        return;
 
923
    }
 
924
    
 
925
    OnStreamDestroyedParam prm;
 
926
    prm.stream = strm;
 
927
    prm.streamIdx = stream_idx;
 
928
    
 
929
    call->onStreamDestroyed(prm);
 
930
}
 
931
 
 
932
struct PendingOnDtmfDigitCallback : public PendingJob
 
933
{
 
934
    int call_id;
 
935
    OnDtmfDigitParam prm;
 
936
 
 
937
    virtual void execute(bool is_pending)
 
938
    {
 
939
        PJ_UNUSED_ARG(is_pending);
 
940
 
 
941
        Call *call = Call::lookup(call_id);
 
942
        if (!call)
 
943
            return;
 
944
 
 
945
        call->onDtmfDigit(prm);
 
946
    }
 
947
};
 
948
 
 
949
void Endpoint::on_dtmf_digit(pjsua_call_id call_id, int digit)
 
950
{
 
951
    Call *call = Call::lookup(call_id);
 
952
    if (!call) {
 
953
        return;
 
954
    }
 
955
    
 
956
    PendingOnDtmfDigitCallback *job = new PendingOnDtmfDigitCallback;
 
957
    job->call_id = call_id;
 
958
    char buf[10];
 
959
    pj_ansi_sprintf(buf, "%c", digit);
 
960
    job->prm.digit = (string)buf;
 
961
    
 
962
    Endpoint::instance().utilAddPendingJob(job);
 
963
}
 
964
 
 
965
void Endpoint::on_call_transfer_request2(pjsua_call_id call_id,
 
966
                                         const pj_str_t *dst,
 
967
                                         pjsip_status_code *code,
 
968
                                         pjsua_call_setting *opt)
 
969
{
 
970
    Call *call = Call::lookup(call_id);
 
971
    if (!call) {
 
972
        return;
 
973
    }
 
974
    
 
975
    OnCallTransferRequestParam prm;
 
976
    prm.dstUri = pj2Str(*dst);
 
977
    prm.statusCode = *code;
 
978
    prm.opt.fromPj(*opt);
 
979
    
 
980
    call->onCallTransferRequest(prm);
 
981
    
 
982
    *code = prm.statusCode;
 
983
    *opt = prm.opt.toPj();
 
984
}
 
985
 
 
986
void Endpoint::on_call_transfer_status(pjsua_call_id call_id,
 
987
                                       int st_code,
 
988
                                       const pj_str_t *st_text,
 
989
                                       pj_bool_t final,
 
990
                                       pj_bool_t *p_cont)
 
991
{
 
992
    Call *call = Call::lookup(call_id);
 
993
    if (!call) {
 
994
        return;
 
995
    }
 
996
    
 
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);
 
1002
    
 
1003
    call->onCallTransferStatus(prm);
 
1004
    
 
1005
    *p_cont = prm.cont;
 
1006
}
 
1007
 
 
1008
void Endpoint::on_call_replace_request2(pjsua_call_id call_id,
 
1009
                                        pjsip_rx_data *rdata,
 
1010
                                        int *st_code,
 
1011
                                        pj_str_t *st_text,
 
1012
                                        pjsua_call_setting *opt)
 
1013
{
 
1014
    Call *call = Call::lookup(call_id);
 
1015
    if (!call) {
 
1016
        return;
 
1017
    }
 
1018
    
 
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);
 
1024
    
 
1025
    call->onCallReplaceRequest(prm);
 
1026
    
 
1027
    *st_code = prm.statusCode;
 
1028
    *st_text = str2Pj(prm.reason);
 
1029
    *opt = prm.opt.toPj();
 
1030
}
 
1031
 
 
1032
void Endpoint::on_call_replaced(pjsua_call_id old_call_id,
 
1033
                                pjsua_call_id new_call_id)
 
1034
{
 
1035
    Call *call = Call::lookup(old_call_id);
 
1036
    if (!call) {
 
1037
        return;
 
1038
    }
 
1039
    
 
1040
    OnCallReplacedParam prm;
 
1041
    prm.newCallId = new_call_id;
 
1042
    
 
1043
    call->onCallReplaced(prm);
 
1044
}
 
1045
 
 
1046
void Endpoint::on_call_rx_offer(pjsua_call_id call_id,
 
1047
                                const pjmedia_sdp_session *offer,
 
1048
                                void *reserved,
 
1049
                                pjsip_status_code *code,
 
1050
                                pjsua_call_setting *opt)
 
1051
{
 
1052
    PJ_UNUSED_ARG(reserved);
 
1053
 
 
1054
    Call *call = Call::lookup(call_id);
 
1055
    if (!call) {
 
1056
        return;
 
1057
    }
 
1058
    
 
1059
    OnCallRxOfferParam prm;
 
1060
    prm.offer.fromPj(*offer);
 
1061
    prm.statusCode = *code;
 
1062
    prm.opt.fromPj(*opt);
 
1063
    
 
1064
    call->onCallRxOffer(prm);
 
1065
    
 
1066
    *code = prm.statusCode;
 
1067
    *opt = prm.opt.toPj();
 
1068
}
 
1069
 
 
1070
pjsip_redirect_op Endpoint::on_call_redirected(pjsua_call_id call_id,
 
1071
                                               const pjsip_uri *target,
 
1072
                                               const pjsip_event *e)
 
1073
{
 
1074
    Call *call = Call::lookup(call_id);
 
1075
    if (!call) {
 
1076
        return PJSIP_REDIRECT_STOP;
 
1077
    }
 
1078
    
 
1079
    OnCallRedirectedParam prm;
 
1080
    char uristr[PJSIP_MAX_URL_SIZE];
 
1081
    int len = pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, target, uristr,
 
1082
                              sizeof(uristr));
 
1083
    if (len < 1) {
 
1084
        pj_ansi_strcpy(uristr, "--URI too long--");
 
1085
    }
 
1086
    prm.targetUri = string(uristr);
 
1087
    if (e)
 
1088
        prm.e.fromPj(*e);
 
1089
    else
 
1090
        prm.e.type = PJSIP_EVENT_UNKNOWN;
 
1091
    
 
1092
    return call->onCallRedirected(prm);
 
1093
}
 
1094
 
 
1095
 
 
1096
struct PendingOnMediaTransportCallback : public PendingJob
 
1097
{
 
1098
    int call_id;
 
1099
    OnCallMediaTransportStateParam prm;
 
1100
 
 
1101
    virtual void execute(bool is_pending)
 
1102
    {
 
1103
        PJ_UNUSED_ARG(is_pending);
 
1104
 
 
1105
        Call *call = Call::lookup(call_id);
 
1106
        if (!call)
 
1107
            return;
 
1108
 
 
1109
        call->onCallMediaTransportState(prm);
 
1110
    }
 
1111
};
 
1112
 
 
1113
pj_status_t
 
1114
Endpoint::on_call_media_transport_state(pjsua_call_id call_id,
 
1115
                                        const pjsua_med_tp_state_info *info)
 
1116
{
 
1117
    Call *call = Call::lookup(call_id);
 
1118
    if (!call) {
 
1119
        return PJ_SUCCESS;
 
1120
    }
 
1121
 
 
1122
    PendingOnMediaTransportCallback *job = new PendingOnMediaTransportCallback;
 
1123
    
 
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;
 
1129
    
 
1130
    Endpoint::instance().utilAddPendingJob(job);
 
1131
 
 
1132
    return PJ_SUCCESS;
 
1133
}
 
1134
 
 
1135
struct PendingOnMediaEventCallback : public PendingJob
 
1136
{
 
1137
    int call_id;
 
1138
    OnCallMediaEventParam prm;
 
1139
 
 
1140
    virtual void execute(bool is_pending)
 
1141
    {
 
1142
        Call *call = Call::lookup(call_id);
 
1143
        if (!call)
 
1144
            return;
 
1145
 
 
1146
        if (is_pending) {
 
1147
            /* Can't do this anymore, pointer is invalid */
 
1148
            prm.ev.pjMediaEvent = NULL;
 
1149
        }
 
1150
 
 
1151
        call->onCallMediaEvent(prm);
 
1152
    }
 
1153
};
 
1154
 
 
1155
void Endpoint::on_call_media_event(pjsua_call_id call_id,
 
1156
                                   unsigned med_idx,
 
1157
                                   pjmedia_event *event)
 
1158
{
 
1159
    Call *call = Call::lookup(call_id);
 
1160
    if (!call) {
 
1161
        return;
 
1162
    }
 
1163
    
 
1164
    PendingOnMediaEventCallback *job = new PendingOnMediaEventCallback;
 
1165
 
 
1166
    job->call_id = call_id;
 
1167
    job->prm.medIdx = med_idx;
 
1168
    job->prm.ev.fromPj(*event);
 
1169
    
 
1170
    Endpoint::instance().utilAddPendingJob(job);
 
1171
}
 
1172
 
 
1173
pjmedia_transport*
 
1174
Endpoint::on_create_media_transport(pjsua_call_id call_id,
 
1175
                                    unsigned media_idx,
 
1176
                                    pjmedia_transport *base_tp,
 
1177
                                    unsigned flags)
 
1178
{
 
1179
    Call *call = Call::lookup(call_id);
 
1180
    if (!call) {
 
1181
        return base_tp;
 
1182
    }
 
1183
    
 
1184
    OnCreateMediaTransportParam prm;
 
1185
    prm.mediaIdx = media_idx;
 
1186
    prm.mediaTp = base_tp;
 
1187
    prm.flags = flags;
 
1188
    
 
1189
    call->onCreateMediaTransport(prm);
 
1190
    
 
1191
    return (pjmedia_transport *)prm.mediaTp;
 
1192
}
 
1193
 
 
1194
///////////////////////////////////////////////////////////////////////////////
 
1195
/*
 
1196
 * Endpoint library operations
 
1197
 */
 
1198
Version Endpoint::libVersion() const
 
1199
{
 
1200
    Version ver;
 
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;
 
1207
    return ver;
 
1208
}
 
1209
 
 
1210
void Endpoint::libCreate() throw(Error)
 
1211
{
 
1212
    PJSUA2_CHECK_EXPR( pjsua_create() );
 
1213
    mainThread = pj_thread_this();
 
1214
}
 
1215
 
 
1216
pjsua_state Endpoint::libGetState() const
 
1217
{
 
1218
    return pjsua_get_state();
 
1219
}
 
1220
 
 
1221
void Endpoint::libInit(const EpConfig &prmEpConfig) throw(Error)
 
1222
{
 
1223
    pjsua_config ua_cfg;
 
1224
    pjsua_logging_config log_cfg;
 
1225
    pjsua_media_config med_cfg;
 
1226
 
 
1227
    ua_cfg = prmEpConfig.uaConfig.toPj();
 
1228
    log_cfg = prmEpConfig.logConfig.toPj();
 
1229
    med_cfg = prmEpConfig.medConfig.toPj();
 
1230
 
 
1231
    /* Setup log callback */
 
1232
    if (prmEpConfig.logConfig.writer) {
 
1233
        this->writer = prmEpConfig.logConfig.writer;
 
1234
        log_cfg.cb = &Endpoint::logFunc;
 
1235
    }
 
1236
    mainThreadOnly = prmEpConfig.uaConfig.mainThreadOnly;
 
1237
 
 
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;
 
1242
 
 
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;
 
1252
 
 
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;
 
1271
 
 
1272
    /* Init! */
 
1273
    PJSUA2_CHECK_EXPR( pjsua_init(&ua_cfg, &log_cfg, &med_cfg) );
 
1274
}
 
1275
 
 
1276
void Endpoint::libStart() throw(Error)
 
1277
{
 
1278
    PJSUA2_CHECK_EXPR(pjsua_start());
 
1279
}
 
1280
 
 
1281
void Endpoint::libRegisterWorkerThread(const string &name) throw(Error)
 
1282
{
 
1283
    PJSUA2_CHECK_EXPR(pjsua_register_worker_thread(name.c_str()));
 
1284
}
 
1285
 
 
1286
void Endpoint::libStopWorkerThreads()
 
1287
{
 
1288
    pjsua_stop_worker_threads();
 
1289
}
 
1290
 
 
1291
int Endpoint::libHandleEvents(unsigned msec_timeout)
 
1292
{
 
1293
    performPendingJobs();
 
1294
    return pjsua_handle_events(msec_timeout);
 
1295
}
 
1296
 
 
1297
void Endpoint::libDestroy(unsigned flags) throw(Error)
 
1298
{
 
1299
    pj_status_t status;
 
1300
 
 
1301
    status = pjsua_destroy2(flags);
 
1302
 
 
1303
    delete this->writer;
 
1304
    this->writer = NULL;
 
1305
 
 
1306
    if (pj_log_get_log_func() == &Endpoint::logFunc) {
 
1307
        pj_log_set_log_func(NULL);
 
1308
    }
 
1309
 
 
1310
    PJSUA2_CHECK_RAISE_ERROR(status);
 
1311
}
 
1312
 
 
1313
///////////////////////////////////////////////////////////////////////////////
 
1314
/*
 
1315
 * Endpoint Utilities
 
1316
 */
 
1317
string Endpoint::utilStrError(pj_status_t prmErr)
 
1318
{
 
1319
    char errmsg[PJ_ERR_MSG_SIZE];
 
1320
    pj_strerror(prmErr, errmsg, sizeof(errmsg));
 
1321
    return errmsg;
 
1322
}
 
1323
 
 
1324
static void ept_log_write(int level, const char *sender,
 
1325
                          const char *format, ...)
 
1326
{
 
1327
    va_list arg;
 
1328
    va_start(arg, format);
 
1329
    pj_log(sender, level, format, arg );
 
1330
    va_end(arg);
 
1331
}
 
1332
 
 
1333
void Endpoint::utilLogWrite(int prmLevel,
 
1334
                            const string &prmSender,
 
1335
                            const string &prmMsg)
 
1336
{
 
1337
    ept_log_write(prmLevel, prmSender.c_str(), "%s", prmMsg.c_str());
 
1338
}
 
1339
 
 
1340
pj_status_t Endpoint::utilVerifySipUri(const string &prmUri)
 
1341
{
 
1342
    return pjsua_verify_sip_url(prmUri.c_str());
 
1343
}
 
1344
 
 
1345
pj_status_t Endpoint::utilVerifyUri(const string &prmUri)
 
1346
{
 
1347
    return pjsua_verify_url(prmUri.c_str());
 
1348
}
 
1349
 
 
1350
Token Endpoint::utilTimerSchedule(unsigned prmMsecDelay,
 
1351
                                  Token prmUserData) throw (Error)
 
1352
{
 
1353
    UserTimer *ut;
 
1354
    pj_time_val delay;
 
1355
    pj_status_t status;
 
1356
 
 
1357
    ut = new UserTimer;
 
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);
 
1362
 
 
1363
    delay.sec = 0;
 
1364
    delay.msec = prmMsecDelay;
 
1365
    pj_time_val_normalize(&delay);
 
1366
 
 
1367
    status = pjsua_schedule_timer(&ut->entry, &delay);
 
1368
    if (status != PJ_SUCCESS) {
 
1369
        delete ut;
 
1370
        PJSUA2_CHECK_RAISE_ERROR(status);
 
1371
    }
 
1372
 
 
1373
    return (Token)ut;
 
1374
}
 
1375
 
 
1376
void Endpoint::utilTimerCancel(Token prmTimerToken)
 
1377
{
 
1378
    UserTimer *ut = (UserTimer*)(void*)prmTimerToken;
 
1379
 
 
1380
    if (ut->signature != TIMER_SIGNATURE) {
 
1381
        PJ_LOG(1,(THIS_FILE,
 
1382
                  "Invalid timer token in Endpoint::utilTimerCancel()"));
 
1383
        return;
 
1384
    }
 
1385
 
 
1386
    ut->entry.id = 0;
 
1387
    ut->signature = 0xFFFFFFFE;
 
1388
    pjsua_cancel_timer(&ut->entry);
 
1389
 
 
1390
    delete ut;
 
1391
}
 
1392
 
 
1393
IntVector Endpoint::utilSslGetAvailableCiphers() throw (Error)
 
1394
{
 
1395
#if PJ_HAS_SSL_SOCK
 
1396
    pj_ssl_cipher ciphers[64];
 
1397
    unsigned count = PJ_ARRAY_SIZE(ciphers);
 
1398
 
 
1399
    PJSUA2_CHECK_EXPR( pj_ssl_cipher_get_availables(ciphers, &count) );
 
1400
 
 
1401
    return IntVector(ciphers, ciphers + count);
 
1402
#else
 
1403
    return IntVector();
 
1404
#endif
 
1405
}
 
1406
 
 
1407
///////////////////////////////////////////////////////////////////////////////
 
1408
/*
 
1409
 * Endpoint NAT operations
 
1410
 */
 
1411
void Endpoint::natDetectType(void) throw(Error)
 
1412
{
 
1413
    PJSUA2_CHECK_EXPR( pjsua_detect_nat_type() );
 
1414
}
 
1415
 
 
1416
pj_stun_nat_type Endpoint::natGetType() throw(Error)
 
1417
{
 
1418
    pj_stun_nat_type type;
 
1419
 
 
1420
    PJSUA2_CHECK_EXPR( pjsua_get_nat_type(&type) );
 
1421
 
 
1422
    return type;
 
1423
}
 
1424
 
 
1425
void Endpoint::natCheckStunServers(const StringVector &servers,
 
1426
                                   bool wait,
 
1427
                                   Token token) throw(Error)
 
1428
{
 
1429
    pj_str_t srv[MAX_STUN_SERVERS];
 
1430
    unsigned i, count = 0;
 
1431
 
 
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();
 
1435
        ++count;
 
1436
    }
 
1437
 
 
1438
    PJSUA2_CHECK_EXPR(pjsua_resolve_stun_servers(count, srv, wait, token,
 
1439
                                                 &Endpoint::stun_resolve_cb) );
 
1440
}
 
1441
 
 
1442
void Endpoint::natCancelCheckStunServers(Token token,
 
1443
                                         bool notify_cb) throw(Error)
 
1444
{
 
1445
    PJSUA2_CHECK_EXPR( pjsua_cancel_stun_resolution(token, notify_cb) );
 
1446
}
 
1447
 
 
1448
///////////////////////////////////////////////////////////////////////////////
 
1449
/*
 
1450
 * Transport API
 
1451
 */
 
1452
TransportId Endpoint::transportCreate(pjsip_transport_type_e type,
 
1453
                                      const TransportConfig &cfg) throw(Error)
 
1454
{
 
1455
    pjsua_transport_config tcfg;
 
1456
    pjsua_transport_id tid;
 
1457
 
 
1458
    tcfg = cfg.toPj();
 
1459
    PJSUA2_CHECK_EXPR( pjsua_transport_create(type,
 
1460
                                              &tcfg, &tid) );
 
1461
 
 
1462
    return tid;
 
1463
}
 
1464
 
 
1465
IntVector Endpoint::transportEnum() throw(Error)
 
1466
{
 
1467
    pjsua_transport_id tids[32];
 
1468
    unsigned count = PJ_ARRAY_SIZE(tids);
 
1469
 
 
1470
    PJSUA2_CHECK_EXPR( pjsua_enum_transports(tids, &count) );
 
1471
 
 
1472
    return IntVector(tids, tids+count);
 
1473
}
 
1474
 
 
1475
TransportInfo Endpoint::transportGetInfo(TransportId id) throw(Error)
 
1476
{
 
1477
    pjsua_transport_info pj_tinfo;
 
1478
    TransportInfo tinfo;
 
1479
 
 
1480
    PJSUA2_CHECK_EXPR( pjsua_transport_get_info(id, &pj_tinfo) );
 
1481
    tinfo.fromPj(pj_tinfo);
 
1482
 
 
1483
    return tinfo;
 
1484
}
 
1485
 
 
1486
void Endpoint::transportSetEnable(TransportId id, bool enabled) throw(Error)
 
1487
{
 
1488
    PJSUA2_CHECK_EXPR( pjsua_transport_set_enable(id, enabled) );
 
1489
}
 
1490
 
 
1491
void Endpoint::transportClose(TransportId id) throw(Error)
 
1492
{
 
1493
    PJSUA2_CHECK_EXPR( pjsua_transport_close(id, PJ_FALSE) );
 
1494
}
 
1495
 
 
1496
///////////////////////////////////////////////////////////////////////////////
 
1497
/*
 
1498
 * Call operations
 
1499
 */
 
1500
 
 
1501
void Endpoint::hangupAllCalls(void)
 
1502
{
 
1503
    pjsua_call_hangup_all();
 
1504
}
 
1505
 
 
1506
///////////////////////////////////////////////////////////////////////////////
 
1507
/*
 
1508
 * Media API
 
1509
 */
 
1510
unsigned Endpoint::mediaMaxPorts() const
 
1511
{
 
1512
    return pjsua_conf_get_max_ports();
 
1513
}
 
1514
 
 
1515
unsigned Endpoint::mediaActivePorts() const
 
1516
{
 
1517
    return pjsua_conf_get_active_ports();
 
1518
}
 
1519
 
 
1520
const AudioMediaVector &Endpoint::mediaEnumPorts() const throw(Error)
 
1521
{
 
1522
    return mediaList;
 
1523
}
 
1524
 
 
1525
void Endpoint::mediaAdd(AudioMedia &media)
 
1526
{
 
1527
    if (mediaExists(media))
 
1528
        return;
 
1529
 
 
1530
    mediaList.push_back(&media);
 
1531
}
 
1532
 
 
1533
void Endpoint::mediaRemove(AudioMedia &media)
 
1534
{
 
1535
    AudioMediaVector::iterator it = std::find(mediaList.begin(),
 
1536
                                              mediaList.end(),
 
1537
                                              &media);
 
1538
 
 
1539
    if (it != mediaList.end())
 
1540
        mediaList.erase(it);
 
1541
 
 
1542
}
 
1543
 
 
1544
bool Endpoint::mediaExists(const AudioMedia &media) const
 
1545
{
 
1546
    AudioMediaVector::const_iterator it = std::find(mediaList.begin(),
 
1547
                                                    mediaList.end(),
 
1548
                                                    &media);
 
1549
 
 
1550
    return (it != mediaList.end());
 
1551
}
 
1552
 
 
1553
AudDevManager &Endpoint::audDevManager()
 
1554
{
 
1555
    return audioDevMgr;
 
1556
}
 
1557
 
 
1558
/*
 
1559
 * Codec operations.
 
1560
 */
 
1561
const CodecInfoVector &Endpoint::codecEnum() throw(Error)
 
1562
{
 
1563
    pjsua_codec_info pj_codec[MAX_CODEC_NUM];
 
1564
    unsigned count = MAX_CODEC_NUM;
 
1565
 
 
1566
    PJSUA2_CHECK_EXPR( pjsua_enum_codecs(pj_codec, &count) );
 
1567
 
 
1568
    pj_enter_critical_section();
 
1569
    clearCodecInfoList();
 
1570
    for (unsigned i=0; i<count; ++i) {
 
1571
        CodecInfo *codec_info = new CodecInfo;
 
1572
 
 
1573
        codec_info->fromPj(pj_codec[i]);
 
1574
        codecInfoList.push_back(codec_info);
 
1575
    }
 
1576
    pj_leave_critical_section();
 
1577
    return codecInfoList;
 
1578
}
 
1579
 
 
1580
void Endpoint::codecSetPriority(const string &codec_id,
 
1581
                                pj_uint8_t priority) throw(Error)
 
1582
{
 
1583
    pj_str_t codec_str = str2Pj(codec_id);
 
1584
    PJSUA2_CHECK_EXPR( pjsua_codec_set_priority(&codec_str, priority) );
 
1585
}
 
1586
 
 
1587
CodecParam Endpoint::codecGetParam(const string &codec_id) const throw(Error)
 
1588
{
 
1589
    pjmedia_codec_param *pj_param = NULL;
 
1590
    pj_str_t codec_str = str2Pj(codec_id);
 
1591
 
 
1592
    PJSUA2_CHECK_EXPR( pjsua_codec_get_param(&codec_str, pj_param) );
 
1593
 
 
1594
    return pj_param;
 
1595
}
 
1596
 
 
1597
void Endpoint::codecSetParam(const string &codec_id,
 
1598
                             const CodecParam param) throw(Error)
 
1599
{
 
1600
    pj_str_t codec_str = str2Pj(codec_id);
 
1601
    pjmedia_codec_param *pj_param = (pjmedia_codec_param*)param;
 
1602
 
 
1603
    PJSUA2_CHECK_EXPR( pjsua_codec_set_param(&codec_str, pj_param) );
 
1604
}
 
1605
 
 
1606
void Endpoint::clearCodecInfoList()
 
1607
{
 
1608
    for (unsigned i=0;i<codecInfoList.size();++i) {
 
1609
        delete codecInfoList[i];
 
1610
    }
 
1611
    codecInfoList.clear();
 
1612
}