~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/call.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: call.cpp 4719 2014-01-29 08:10:22Z nanang $ */
 
2
/*
 
3
 * Copyright (C) 2012-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/account.hpp>
 
20
#include <pjsua2/call.hpp>
 
21
#include <pjsua2/endpoint.hpp>
 
22
#include <pj/ctype.h>
 
23
#include "util.hpp"
 
24
 
 
25
using namespace pj;
 
26
using namespace std;
 
27
 
 
28
#define THIS_FILE               "call.cpp"
 
29
 
 
30
///////////////////////////////////////////////////////////////////////////////
 
31
 
 
32
#define SDP_BUFFER_SIZE 1024
 
33
 
 
34
MathStat::MathStat()
 
35
: n(0), max(0), min(0), last(0), mean(0)
 
36
{
 
37
}
 
38
 
 
39
void MathStat::fromPj(const pj_math_stat &prm)
 
40
{
 
41
    this->n    = prm.n;
 
42
    this->max  = prm.max;
 
43
    this->min  = prm.min;
 
44
    this->last = prm.last;
 
45
    this->mean = prm.mean;
 
46
}
 
47
 
 
48
void RtcpStreamStat::fromPj(const pjmedia_rtcp_stream_stat &prm)
 
49
{
 
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;
 
57
    this->dup             = prm.dup;
 
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);
 
62
}
 
63
 
 
64
void RtcpSdes::fromPj(const pjmedia_rtcp_sdes &prm)
 
65
{
 
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);
 
73
}
 
74
 
 
75
void RtcpStat::fromPj(const pjmedia_rtcp_stat &prm)
 
76
{
 
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);
 
85
#endif
 
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);
 
89
#endif
 
90
    this->peerSdes.fromPj(prm.peer_sdes);
 
91
}
 
92
 
 
93
void JbufState::fromPj(const pjmedia_jb_state &prm)
 
94
{
 
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;
 
109
}
 
110
 
 
111
void SdpSession::fromPj(const pjmedia_sdp_session &sdp)
 
112
{
 
113
    char buf[SDP_BUFFER_SIZE];
 
114
    int len;
 
115
 
 
116
    len = pjmedia_sdp_print(&sdp, buf, sizeof(buf));
 
117
    wholeSdp = (len > -1? string(buf, len): "");
 
118
    pjSdpSession = (void *)&sdp;
 
119
}
 
120
 
 
121
void MediaEvent::fromPj(const pjmedia_event &ev)
 
122
{
 
123
    type = ev.type;
 
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;
 
127
    }
 
128
    pjMediaEvent = (void *)&ev;
 
129
}
 
130
 
 
131
void MediaTransportInfo::fromPj(const pjmedia_transport_info &info)
 
132
{
 
133
    char straddr[PJ_INET6_ADDRSTRLEN+10];
 
134
    
 
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;
 
139
}
 
140
 
 
141
//////////////////////////////////////////////////////////////////////////////
 
142
 
 
143
/* Call Audio Media. */
 
144
class CallAudioMedia : public AudioMedia
 
145
{
 
146
public:
 
147
    /*
 
148
     * Set the conference port identification associated with the
 
149
     * call audio media.
 
150
     */
 
151
    void setPortId(int id);
 
152
};
 
153
 
 
154
 
 
155
void CallAudioMedia::setPortId(int id)
 
156
{
 
157
    this->id = id;
 
158
}
 
159
 
 
160
CallOpParam::CallOpParam(bool useDefaultCallSetting)
 
161
: statusCode(pjsip_status_code(0)), reason(""), options(0)
 
162
{
 
163
    if (useDefaultCallSetting)
 
164
        opt = CallSetting(true);
 
165
}
 
166
 
 
167
CallSendRequestParam::CallSendRequestParam()
 
168
: method("")
 
169
{
 
170
}
 
171
 
 
172
CallVidSetStreamParam::CallVidSetStreamParam()
 
173
{
 
174
#if PJSUA_HAS_VIDEO
 
175
    pjsua_call_vid_strm_op_param prm;
 
176
    
 
177
    pjsua_call_vid_strm_op_param_default(&prm);
 
178
    this->medIdx = prm.med_idx;
 
179
    this->dir    = prm.dir;
 
180
    this->capDev = prm.cap_dev;
 
181
#endif
 
182
}
 
183
 
 
184
CallSetting::CallSetting(pj_bool_t useDefaultValues)
 
185
{
 
186
    if (useDefaultValues) {
 
187
        pjsua_call_setting setting;
 
188
    
 
189
        pjsua_call_setting_default(&setting);
 
190
        fromPj(setting);
 
191
    } else {
 
192
        flag                = 0;
 
193
        reqKeyframeMethod   = 0;
 
194
        audioCount          = 0;
 
195
        videoCount          = 0;
 
196
    }
 
197
}
 
198
 
 
199
bool CallSetting::isEmpty() const
 
200
{
 
201
    return (flag == 0 && reqKeyframeMethod == 0 && audioCount == 0 &&
 
202
            videoCount == 0);
 
203
}
 
204
 
 
205
void CallSetting::fromPj(const pjsua_call_setting &prm)
 
206
{
 
207
    this->flag              = prm.flag;
 
208
    this->reqKeyframeMethod = prm.req_keyframe_method;
 
209
    this->audioCount        = prm.aud_cnt;
 
210
    this->videoCount        = prm.vid_cnt;
 
211
}
 
212
 
 
213
pjsua_call_setting CallSetting::toPj() const
 
214
{
 
215
    pjsua_call_setting setting;
 
216
 
 
217
    setting.flag                = this->flag;
 
218
    setting.req_keyframe_method = this->reqKeyframeMethod;
 
219
    setting.aud_cnt             = this->audioCount;
 
220
    setting.vid_cnt             = this->videoCount;
 
221
    
 
222
    return setting;
 
223
}
 
224
 
 
225
 
 
226
CallMediaInfo::CallMediaInfo()
 
227
{
 
228
}
 
229
 
 
230
void CallMediaInfo::fromPj(const pjsua_call_media_info &prm)
 
231
{
 
232
    this->index                     = prm.index;
 
233
    this->type                      = prm.type;
 
234
    this->dir                       = prm.dir;
 
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;
 
241
    }
 
242
}
 
243
 
 
244
void CallInfo::fromPj(const pjsua_call_info &pci)
 
245
{
 
246
    unsigned mi;
 
247
    
 
248
    id                  = pci.id;
 
249
    role                = pci.role;
 
250
    accId               = pci.acc_id;
 
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);
 
257
    state               = pci.state;
 
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;
 
266
    
 
267
    for (mi = 0; mi < pci.media_cnt; mi++) {
 
268
        CallMediaInfo med;
 
269
        
 
270
        med.fromPj(pci.media[mi]);
 
271
        media.push_back(med);
 
272
    }
 
273
    for (mi = 0; mi < pci.prov_media_cnt; mi++) {
 
274
        CallMediaInfo med;
 
275
        
 
276
        med.fromPj(pci.prov_media[mi]);
 
277
        provMedia.push_back(med);
 
278
    }
 
279
}
 
280
 
 
281
void StreamInfo::fromPj(const pjsua_stream_info &info)
 
282
{
 
283
    char straddr[PJ_INET6_ADDRSTRLEN+10];
 
284
 
 
285
    type = info.type;
 
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;
 
310
    }
 
311
}
 
312
 
 
313
void StreamStat::fromPj(const pjsua_stream_stat &prm)
 
314
{
 
315
    rtcp.fromPj(prm.rtcp);
 
316
    jbuf.fromPj(prm.jbuf);
 
317
}
 
318
 
 
319
///////////////////////////////////////////////////////////////////////////////
 
320
 
 
321
struct call_param
 
322
{
 
323
    pjsua_msg_data      msg_data;
 
324
    pjsua_msg_data     *p_msg_data;
 
325
    pjsua_call_setting  opt;
 
326
    pjsua_call_setting *p_opt;
 
327
    pj_str_t            reason;
 
328
    pj_str_t           *p_reason;
 
329
 
 
330
public:
 
331
    /**
 
332
     * Default constructors with specified parameters.
 
333
     */
 
334
    call_param(const SipTxOption &tx_option);
 
335
    call_param(const SipTxOption &tx_option, const CallSetting &setting,
 
336
               const string &reason_str);
 
337
};
 
338
 
 
339
call_param::call_param(const SipTxOption &tx_option)
 
340
{
 
341
    if (tx_option.isEmpty()) {
 
342
        p_msg_data = NULL;
 
343
    } else {
 
344
        tx_option.toPj(msg_data);
 
345
        p_msg_data = &msg_data;
 
346
    }
 
347
    
 
348
    p_opt = NULL;
 
349
    p_reason = NULL;
 
350
}
 
351
 
 
352
call_param::call_param(const SipTxOption &tx_option, const CallSetting &setting,
 
353
                       const string &reason_str)
 
354
{
 
355
    if (tx_option.isEmpty()) {
 
356
        p_msg_data = NULL;
 
357
    } else {
 
358
        tx_option.toPj(msg_data);
 
359
        p_msg_data = &msg_data;
 
360
    }
 
361
    
 
362
    if (setting.isEmpty()) {
 
363
        p_opt = NULL;
 
364
    } else {
 
365
        opt = setting.toPj();
 
366
        p_opt = &opt;
 
367
    }
 
368
    
 
369
    reason = str2Pj(reason_str);
 
370
    p_reason = (reason.slen == 0? NULL: &reason);
 
371
}
 
372
 
 
373
Call::Call(Account& account, int call_id)
 
374
: acc(account), id(call_id)
 
375
{
 
376
    if (call_id != PJSUA_INVALID_ID)
 
377
        pjsua_call_set_user_data(call_id, this);
 
378
}
 
379
 
 
380
Call::~Call()
 
381
{
 
382
    /**
 
383
     * If this instance is deleted, also hangup the corresponding call in
 
384
     * PJSUA library.
 
385
     */
 
386
    if (id != PJSUA_INVALID_ID && pjsua_get_state() < PJSUA_STATE_CLOSING) {
 
387
        pjsua_call_set_user_data(id, NULL);
 
388
        if (isActive()) {
 
389
            CallOpParam prm;
 
390
            hangup(prm);
 
391
        }
 
392
    }
 
393
}
 
394
 
 
395
CallInfo Call::getInfo() const throw(Error)
 
396
{
 
397
    pjsua_call_info pj_ci;
 
398
    CallInfo ci;
 
399
    
 
400
    PJSUA2_CHECK_EXPR( pjsua_call_get_info(id, &pj_ci) );
 
401
    ci.fromPj(pj_ci);
 
402
    return ci;
 
403
}
 
404
 
 
405
bool Call::isActive() const
 
406
{
 
407
    if (id == PJSUA_INVALID_ID)
 
408
        return false;
 
409
    
 
410
    return (pjsua_call_is_active(id) != 0);
 
411
}
 
412
 
 
413
int Call::getId() const
 
414
{
 
415
    return id;
 
416
}
 
417
 
 
418
Call *Call::lookup(int call_id)
 
419
{
 
420
    Call *call = (Call*)pjsua_call_get_user_data(call_id);
 
421
    if (call)
 
422
        call->id = call_id;
 
423
    return call;
 
424
}
 
425
 
 
426
bool Call::hasMedia() const
 
427
{
 
428
    return (pjsua_call_has_media(id) != 0);
 
429
}
 
430
 
 
431
Media *Call::getMedia(unsigned med_idx) const
 
432
{
 
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))
 
437
    {
 
438
        return NULL;
 
439
    }
 
440
    
 
441
    return medias[med_idx];
 
442
}
 
443
 
 
444
pjsip_dialog_cap_status Call::remoteHasCap(int htype,
 
445
                                           const string &hname,
 
446
                                           const string &token) const
 
447
{
 
448
    pj_str_t pj_hname = str2Pj(hname);
 
449
    pj_str_t pj_token = str2Pj(token);
 
450
    
 
451
    return pjsua_call_remote_has_cap(id, htype,
 
452
                                     (htype == PJSIP_H_OTHER)? &pj_hname: NULL,
 
453
                                     &pj_token);
 
454
}
 
455
 
 
456
void Call::setUserData(Token user_data)
 
457
{
 
458
    userData = user_data;
 
459
}
 
460
 
 
461
Token Call::getUserData() const
 
462
{
 
463
    return userData;
 
464
}
 
465
 
 
466
pj_stun_nat_type Call::getRemNatType() throw(Error)
 
467
{
 
468
    pj_stun_nat_type nat;
 
469
    
 
470
    PJSUA2_CHECK_EXPR( pjsua_call_get_rem_nat_type(id, &nat) );
 
471
    
 
472
    return nat;
 
473
}
 
474
 
 
475
void Call::makeCall(const string &dst_uri, const CallOpParam &prm) throw(Error)
 
476
{
 
477
    pj_str_t pj_dst_uri = str2Pj(dst_uri);
 
478
    call_param param(prm.txOption, prm.opt, prm.reason);
 
479
    
 
480
    PJSUA2_CHECK_EXPR( pjsua_call_make_call(acc.getId(), &pj_dst_uri,
 
481
                                            param.p_opt, this,
 
482
                                            param.p_msg_data, &id) );
 
483
}
 
484
 
 
485
void Call::answer(const CallOpParam &prm) throw(Error)
 
486
{
 
487
    call_param param(prm.txOption, prm.opt, prm.reason);
 
488
    
 
489
    PJSUA2_CHECK_EXPR( pjsua_call_answer2(id, param.p_opt, prm.statusCode,
 
490
                                          param.p_reason, param.p_msg_data) );
 
491
}
 
492
 
 
493
void Call::hangup(const CallOpParam &prm) throw(Error)
 
494
{
 
495
    call_param param(prm.txOption, prm.opt, prm.reason);
 
496
    
 
497
    PJSUA2_CHECK_EXPR( pjsua_call_hangup(id, prm.statusCode, param.p_reason,
 
498
                                         param.p_msg_data) );
 
499
}
 
500
 
 
501
void Call::setHold(const CallOpParam &prm) throw(Error)
 
502
{
 
503
    call_param param(prm.txOption, prm.opt, prm.reason);
 
504
    
 
505
    PJSUA2_CHECK_EXPR( pjsua_call_set_hold2(id, prm.options, param.p_msg_data));
 
506
}
 
507
 
 
508
void Call::reinvite(const CallOpParam &prm) throw(Error)
 
509
{
 
510
    call_param param(prm.txOption, prm.opt, prm.reason);
 
511
 
 
512
    PJSUA2_CHECK_EXPR( pjsua_call_reinvite2(id, param.p_opt, param.p_msg_data));
 
513
}
 
514
 
 
515
void Call::update(const CallOpParam &prm) throw(Error)
 
516
{
 
517
    call_param param(prm.txOption, prm.opt, prm.reason);
 
518
    
 
519
    PJSUA2_CHECK_EXPR( pjsua_call_update2(id, param.p_opt, param.p_msg_data) );
 
520
}
 
521
 
 
522
void Call::xfer(const string &dest, const CallOpParam &prm) throw(Error)
 
523
{
 
524
    call_param param(prm.txOption);
 
525
    pj_str_t pj_dest = str2Pj(dest);
 
526
    
 
527
    PJSUA2_CHECK_EXPR( pjsua_call_xfer(id, &pj_dest, param.p_msg_data) );
 
528
}
 
529
 
 
530
void Call::xferReplaces(const Call& dest_call,
 
531
                  const CallOpParam &prm) throw(Error)
 
532
{
 
533
    call_param param(prm.txOption);
 
534
    
 
535
    PJSUA2_CHECK_EXPR(pjsua_call_xfer_replaces(id, dest_call.getId(),
 
536
                                               prm.options, param.p_msg_data) );
 
537
}
 
538
 
 
539
void Call::processRedirect(pjsip_redirect_op cmd) throw(Error)
 
540
{
 
541
    PJSUA2_CHECK_EXPR(pjsua_call_process_redirect(id, cmd));
 
542
}
 
543
 
 
544
void Call::dialDtmf(const string &digits) throw(Error)
 
545
{
 
546
    pj_str_t pj_digits = str2Pj(digits);
 
547
    
 
548
    PJSUA2_CHECK_EXPR(pjsua_call_dial_dtmf(id, &pj_digits));
 
549
}
 
550
 
 
551
void Call::sendInstantMessage(const SendInstantMessageParam& prm)
 
552
    throw(Error)
 
553
{
 
554
    pj_str_t mime_type = str2Pj(prm.contentType);
 
555
    pj_str_t content = str2Pj(prm.content);
 
556
    call_param param(prm.txOption);
 
557
 
 
558
    PJSUA2_CHECK_EXPR(pjsua_call_send_im(id, &mime_type, &content,
 
559
                                         param.p_msg_data, prm.userData) );
 
560
}
 
561
 
 
562
void Call::sendTypingIndication(const SendTypingIndicationParam &prm)
 
563
    throw(Error)
 
564
{
 
565
    call_param param(prm.txOption);
 
566
    
 
567
    PJSUA2_CHECK_EXPR(pjsua_call_send_typing_ind(id,
 
568
                                                 (prm.isTyping?
 
569
                                                  PJ_TRUE: PJ_FALSE),
 
570
                                                 param.p_msg_data) );
 
571
}
 
572
 
 
573
void Call::sendRequest(const CallSendRequestParam &prm) throw(Error)
 
574
{
 
575
    pj_str_t method = str2Pj(prm.method);
 
576
    call_param param(prm.txOption);
 
577
    
 
578
    PJSUA2_CHECK_EXPR(pjsua_call_send_request(id, &method, param.p_msg_data) );
 
579
}
 
580
 
 
581
string Call::dump(bool with_media, const string indent) throw(Error)
 
582
{
 
583
#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
 
584
    char buffer[1024 * 10];
 
585
#else
 
586
    char buffer[1024 * 3];
 
587
#endif
 
588
 
 
589
    PJSUA2_CHECK_EXPR(pjsua_call_dump(id, (with_media? PJ_TRUE: PJ_FALSE),
 
590
                                      buffer, sizeof(buffer),
 
591
                                      indent.c_str()));
 
592
    
 
593
    return buffer;
 
594
}
 
595
 
 
596
int Call::vidGetStreamIdx() const
 
597
{
 
598
#if PJSUA_HAS_VIDEO
 
599
    return pjsua_call_get_vid_stream_idx(id);
 
600
#else
 
601
    return PJSUA_INVALID_ID;
 
602
#endif
 
603
}
 
604
 
 
605
bool Call::vidStreamIsRunning(int med_idx, pjmedia_dir dir) const
 
606
{
 
607
#if PJSUA_HAS_VIDEO
 
608
    return (pjsua_call_vid_stream_is_running(id, med_idx, dir) == PJ_TRUE);
 
609
#else
 
610
    PJ_UNUSED_ARG(med_idx);
 
611
    PJ_UNUSED_ARG(dir);
 
612
    return false;
 
613
#endif
 
614
}
 
615
 
 
616
void Call::vidSetStream(pjsua_call_vid_strm_op op,
 
617
                        const CallVidSetStreamParam &param) throw(Error)
 
618
{
 
619
#if PJSUA_HAS_VIDEO
 
620
    pjsua_call_vid_strm_op_param prm;
 
621
    
 
622
    prm.med_idx = param.medIdx;
 
623
    prm.dir = param.dir;
 
624
    prm.cap_dev = param.capDev;
 
625
    PJSUA2_CHECK_EXPR( pjsua_call_set_vid_strm(id, op, &prm) );
 
626
#else
 
627
    PJ_UNUSED_ARG(op);
 
628
    PJ_UNUSED_ARG(param);
 
629
    PJSUA2_RAISE_ERROR(PJ_EINVALIDOP);
 
630
#endif
 
631
}
 
632
 
 
633
StreamInfo Call::getStreamInfo(unsigned med_idx) const throw(Error)
 
634
{
 
635
    pjsua_stream_info pj_si;
 
636
    StreamInfo si;
 
637
    
 
638
    PJSUA2_CHECK_EXPR( pjsua_call_get_stream_info(id, med_idx, &pj_si) );
 
639
    si.fromPj(pj_si);
 
640
    return si;
 
641
}
 
642
 
 
643
StreamStat Call::getStreamStat(unsigned med_idx) const throw(Error)
 
644
{
 
645
    pjsua_stream_stat pj_ss;
 
646
    StreamStat ss;
 
647
    
 
648
    PJSUA2_CHECK_EXPR( pjsua_call_get_stream_stat(id, med_idx, &pj_ss) );
 
649
    ss.fromPj(pj_ss);
 
650
    return ss;
 
651
}
 
652
 
 
653
MediaTransportInfo Call::getMedTransportInfo(unsigned med_idx) const
 
654
    throw(Error)
 
655
{
 
656
    pjmedia_transport_info pj_mti;
 
657
    MediaTransportInfo mti;
 
658
    
 
659
    PJSUA2_CHECK_EXPR( pjsua_call_get_med_transport_info(id, med_idx,
 
660
                                                         &pj_mti) );
 
661
    mti.fromPj(pj_mti);
 
662
    return mti;
 
663
}
 
664
 
 
665
void Call::processMediaUpdate(OnCallMediaStateParam &prm)
 
666
{
 
667
    pjsua_call_info pj_ci;
 
668
    unsigned mi;
 
669
    
 
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);
 
675
                } else {
 
676
                    medias.push_back(NULL);
 
677
                }
 
678
            }
 
679
            
 
680
            if (pj_ci.media[mi].type == PJMEDIA_TYPE_AUDIO) {
 
681
                CallAudioMedia *aud_med = (CallAudioMedia *)medias[mi];
 
682
                
 
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)
 
686
                {
 
687
                    Endpoint::instance().mediaAdd((AudioMedia &)*aud_med);
 
688
                } else {
 
689
                    Endpoint::instance().mediaRemove((AudioMedia &)*aud_med);
 
690
                }
 
691
            }
 
692
        }
 
693
    }
 
694
    
 
695
    /* Call media state callback. */
 
696
    onCallMediaState(prm);
 
697
}
 
698
 
 
699
void Call::processStateChange(OnCallStateParam &prm)
 
700
{
 
701
    pjsua_call_info pj_ci;
 
702
    unsigned mi;
 
703
    
 
704
    if (pjsua_call_get_info(id, &pj_ci) == PJ_SUCCESS &&
 
705
        pj_ci.state == PJSIP_INV_STATE_DISCONNECTED)
 
706
    {
 
707
        /* Clear medias. */
 
708
        for (mi = 0; mi < medias.size(); mi++) {
 
709
            if (medias[mi])
 
710
                delete medias[mi];
 
711
        }
 
712
        medias.clear();
 
713
    }
 
714
    
 
715
    onCallState(prm);
 
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.
 
718
     */
 
719
}