~ubuntu-branches/ubuntu/trusty/sflphone/trusty

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.0.1/pjsip-apps/src/vidgui/vidgui.cpp

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (4.3.4 sid)
  • Revision ID: package-import@ubuntu.com-20140128182336-jrsv0k9u6cawc068
Tags: 1.3.0-1
* New upstream release 
  - Fixes "New Upstream Release" (Closes: #735846)
  - Fixes "Ringtone does not stop" (Closes: #727164)
  - Fixes "[sflphone-kde] crash on startup" (Closes: #718178)
  - Fixes "sflphone GUI crashes when call is hung up" (Closes: #736583)
* Build-Depends: ensure GnuTLS 2.6
  - libucommon-dev (>= 6.0.7-1.1), libccrtp-dev (>= 2.0.6-3)
  - Fixes "FTBFS Build-Depends libgnutls{26,28}-dev" (Closes: #722040)
* Fix "boost 1.49 is going away" unversioned Build-Depends: (Closes: #736746)
* Add Build-Depends: libsndfile-dev, nepomuk-core-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* $Id: vidgui.cpp 4060 2012-04-17 09:55:30Z ming $ */
2
 
/*
3
 
 * Copyright (C) 2011-2011 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 "vidgui.h"
20
 
#include "vidwin.h"
21
 
 
22
 
#if defined(PJ_WIN32)
23
 
#   define SDL_MAIN_HANDLED
24
 
#endif
25
 
 
26
 
#include <SDL.h>
27
 
#include <assert.h>
28
 
#include <QMessageBox>
29
 
 
30
 
#define LOG_FILE                "vidgui.log"
31
 
#define THIS_FILE               "vidgui.cpp"
32
 
 
33
 
///////////////////////////////////////////////////////////////////////////
34
 
//
35
 
// SETTINGS
36
 
//
37
 
 
38
 
//
39
 
// These configure SIP registration
40
 
//
41
 
#define USE_REGISTRATION        0
42
 
#define SIP_DOMAIN              "pjsip.org"
43
 
#define SIP_USERNAME            "vidgui"
44
 
#define SIP_PASSWORD            "secret"
45
 
#define SIP_PORT                5080
46
 
#define SIP_TCP                 1
47
 
 
48
 
//
49
 
// NAT helper settings
50
 
//
51
 
#define USE_ICE                 1
52
 
#define USE_STUN                0
53
 
#define STUN_SRV                "stun.pjsip.org"
54
 
 
55
 
//
56
 
// Devices settings
57
 
//
58
 
#define DEFAULT_CAP_DEV         PJMEDIA_VID_DEFAULT_CAPTURE_DEV
59
 
//#define DEFAULT_CAP_DEV               1
60
 
#define DEFAULT_REND_DEV        PJMEDIA_VID_DEFAULT_RENDER_DEV
61
 
 
62
 
 
63
 
//
64
 
// End of Settings
65
 
///////////////////////////////////////////////////////////////////////////
66
 
 
67
 
 
68
 
MainWin *MainWin::theInstance_;
69
 
 
70
 
MainWin::MainWin(QWidget *parent)
71
 
: QWidget(parent), accountId_(-1), currentCall_(-1),
72
 
  preview_on(false), video_(NULL), video_prev_(NULL)
73
 
{
74
 
    theInstance_ = this;
75
 
 
76
 
    initLayout();
77
 
    emit signalCallReleased();
78
 
}
79
 
 
80
 
MainWin::~MainWin()
81
 
{
82
 
    quit();
83
 
    theInstance_ = NULL;
84
 
}
85
 
 
86
 
MainWin *MainWin::instance()
87
 
{
88
 
    return theInstance_;
89
 
}
90
 
 
91
 
void MainWin::initLayout()
92
 
{
93
 
    //statusBar_ = new QStatusBar(this);
94
 
 
95
 
    /* main layout */
96
 
    QHBoxLayout *hbox_main = new QHBoxLayout;
97
 
    //QVBoxLayout *vbox_left = new QVBoxLayout;
98
 
    vbox_left = new QVBoxLayout;
99
 
    QVBoxLayout *vbox_right = new QVBoxLayout;
100
 
    hbox_main->addLayout(vbox_left);
101
 
    hbox_main->addLayout(vbox_right);
102
 
 
103
 
    /* Left pane */
104
 
    QHBoxLayout *hbox_url = new QHBoxLayout;
105
 
    hbox_url->addWidget(new QLabel(tr("Url:")));
106
 
    hbox_url->addWidget(url_=new QLineEdit(tr("sip:")), 1);
107
 
    vbox_left->addLayout(hbox_url);
108
 
 
109
 
    /* Right pane */
110
 
    vbox_right->addWidget((localUri_ = new QLabel));
111
 
    vbox_right->addWidget((vidEnabled_ = new QCheckBox(tr("Enable &video"))));
112
 
    vbox_right->addWidget((previewButton_=new QPushButton(tr("Start &Preview"))));
113
 
    vbox_right->addWidget((callButton_=new QPushButton(tr("Call"))));
114
 
    vbox_right->addWidget((hangupButton_=new QPushButton(tr("Hangup"))));
115
 
    vbox_right->addWidget((quitButton_=new QPushButton(tr("Quit"))));
116
 
 
117
 
#if PJMEDIA_HAS_VIDEO
118
 
    vidEnabled_->setCheckState(Qt::Checked);
119
 
#else
120
 
    vidEnabled_->setCheckState(Qt::Unchecked);
121
 
    vidEnabled_->setEnabled(false);
122
 
#endif
123
 
 
124
 
    /* Outest layout */
125
 
    QVBoxLayout *vbox_outest = new QVBoxLayout;
126
 
    vbox_outest->addLayout(hbox_main);
127
 
    vbox_outest->addWidget((statusBar_ = new QLabel));
128
 
 
129
 
    setLayout(vbox_outest);
130
 
 
131
 
    connect(previewButton_, SIGNAL(clicked()), this, SLOT(preview()));
132
 
    connect(callButton_, SIGNAL(clicked()), this, SLOT(call()));
133
 
    connect(hangupButton_, SIGNAL(clicked()), this, SLOT(hangup()));
134
 
    connect(quitButton_, SIGNAL(clicked()), this, SLOT(quit()));
135
 
    //connect(this, SIGNAL(close()), this, SLOT(quit()));
136
 
    connect(vidEnabled_, SIGNAL(stateChanged(int)), this, SLOT(onVidEnabledChanged(int)));
137
 
 
138
 
    // UI updates must be done in the UI thread!
139
 
    connect(this, SIGNAL(signalNewCall(int, bool)),
140
 
            this, SLOT(onNewCall(int, bool)));
141
 
    connect(this, SIGNAL(signalCallReleased()),
142
 
            this, SLOT(onCallReleased()));
143
 
    connect(this, SIGNAL(signalInitVideoWindow()),
144
 
            this, SLOT(initVideoWindow()));
145
 
    connect(this, SIGNAL(signalShowStatus(const QString&)),
146
 
            this, SLOT(doShowStatus(const QString&)));
147
 
}
148
 
 
149
 
void MainWin::quit()
150
 
{
151
 
    delete video_prev_;
152
 
    video_prev_ = NULL;
153
 
    delete video_;
154
 
    video_ = NULL;
155
 
 
156
 
    pjsua_destroy();
157
 
    qApp->quit();
158
 
}
159
 
 
160
 
void MainWin::showStatus(const char *msg)
161
 
{
162
 
    PJ_LOG(3,(THIS_FILE, "%s", msg));
163
 
 
164
 
    QString msg_ = QString::fromUtf8(msg);
165
 
    emit signalShowStatus(msg_);
166
 
}
167
 
 
168
 
void MainWin::doShowStatus(const QString& msg)
169
 
{
170
 
    //statusBar_->showMessage(msg);
171
 
    statusBar_->setText(msg);
172
 
}
173
 
 
174
 
void MainWin::showError(const char *title, pj_status_t status)
175
 
{
176
 
    char errmsg[PJ_ERR_MSG_SIZE];
177
 
    char errline[120];
178
 
 
179
 
    pj_strerror(status, errmsg, sizeof(errmsg));
180
 
    snprintf(errline, sizeof(errline), "%s error: %s", title, errmsg);
181
 
    showStatus(errline);
182
 
}
183
 
 
184
 
void MainWin::onVidEnabledChanged(int state)
185
 
{
186
 
    pjsua_call_setting call_setting;
187
 
 
188
 
    if (currentCall_ == -1)
189
 
        return;
190
 
 
191
 
    pjsua_call_setting_default(&call_setting);
192
 
    call_setting.vid_cnt = (state == Qt::Checked);
193
 
 
194
 
    pjsua_call_reinvite2(currentCall_, &call_setting, NULL);
195
 
}
196
 
 
197
 
void MainWin::onNewCall(int cid, bool incoming)
198
 
{
199
 
    pjsua_call_info ci;
200
 
 
201
 
    pj_assert(currentCall_ == -1);
202
 
    currentCall_ = cid;
203
 
 
204
 
    pjsua_call_get_info(cid, &ci);
205
 
    url_->setText(ci.remote_info.ptr);
206
 
    url_->setEnabled(false);
207
 
    hangupButton_->setEnabled(true);
208
 
 
209
 
    if (incoming) {
210
 
        callButton_->setText(tr("Answer"));
211
 
        callButton_->setEnabled(true);
212
 
    } else {
213
 
        callButton_->setEnabled(false);
214
 
    }
215
 
 
216
 
    //video_->setText(ci.remote_contact.ptr);
217
 
    //video_->setWindowTitle(ci.remote_contact.ptr);
218
 
}
219
 
 
220
 
void MainWin::onCallReleased()
221
 
{
222
 
    url_->setEnabled(true);
223
 
    callButton_->setEnabled(true);
224
 
    callButton_->setText(tr("Call"));
225
 
    hangupButton_->setEnabled(false);
226
 
    currentCall_ = -1;
227
 
 
228
 
    delete video_;
229
 
    video_ = NULL;
230
 
}
231
 
 
232
 
void MainWin::preview()
233
 
{
234
 
    if (preview_on) {
235
 
        delete video_prev_;
236
 
        video_prev_ = NULL;
237
 
 
238
 
        pjsua_vid_preview_stop(DEFAULT_CAP_DEV);
239
 
 
240
 
        showStatus("Preview stopped");
241
 
        previewButton_->setText(tr("Start &Preview"));
242
 
    } else {
243
 
        pjsua_vid_win_id wid;
244
 
        pjsua_vid_win_info wi;
245
 
        pjsua_vid_preview_param pre_param;
246
 
        pj_status_t status;
247
 
 
248
 
        pjsua_vid_preview_param_default(&pre_param);
249
 
        pre_param.rend_id = DEFAULT_REND_DEV;
250
 
        pre_param.show = PJ_FALSE;
251
 
 
252
 
        status = pjsua_vid_preview_start(DEFAULT_CAP_DEV, &pre_param);
253
 
        if (status != PJ_SUCCESS) {
254
 
            char errmsg[PJ_ERR_MSG_SIZE];
255
 
            pj_strerror(status, errmsg, sizeof(errmsg));
256
 
            QMessageBox::critical(0, "Error creating preview", errmsg);
257
 
            return;
258
 
        }
259
 
        wid = pjsua_vid_preview_get_win(DEFAULT_CAP_DEV);
260
 
        pjsua_vid_win_get_info(wid, &wi);
261
 
 
262
 
        video_prev_ = new VidWin(&wi.hwnd);
263
 
        video_prev_->putIntoLayout(vbox_left);
264
 
        //Using this will cause SDL window to display blank
265
 
        //screen sometimes, probably because it's using different
266
 
        //X11 Display
267
 
        //status = pjsua_vid_win_set_show(wid, PJ_TRUE);
268
 
        //This is handled by VidWin now
269
 
        //video_prev_->show_sdl();
270
 
        showStatus("Preview started");
271
 
 
272
 
        previewButton_->setText(tr("Stop &Preview"));
273
 
    }
274
 
    preview_on = !preview_on;
275
 
}
276
 
 
277
 
 
278
 
void MainWin::call()
279
 
{
280
 
    if (callButton_->text() == "Answer") {
281
 
        pjsua_call_setting call_setting;
282
 
 
283
 
        pj_assert(currentCall_ != -1);
284
 
 
285
 
        pjsua_call_setting_default(&call_setting);
286
 
        call_setting.vid_cnt = (vidEnabled_->checkState()==Qt::Checked);
287
 
 
288
 
        pjsua_call_answer2(currentCall_, &call_setting, 200, NULL, NULL);
289
 
        callButton_->setEnabled(false);
290
 
    } else {
291
 
        pj_status_t status;
292
 
        QString dst = url_->text();
293
 
        char uri[256];
294
 
        pjsua_call_setting call_setting;
295
 
 
296
 
        pj_ansi_strncpy(uri, dst.toAscii().data(), sizeof(uri));
297
 
        pj_str_t uri2 = pj_str((char*)uri);
298
 
 
299
 
        pj_assert(currentCall_ == -1);
300
 
 
301
 
        pjsua_call_setting_default(&call_setting);
302
 
        call_setting.vid_cnt = (vidEnabled_->checkState()==Qt::Checked);
303
 
 
304
 
        status = pjsua_call_make_call(accountId_, &uri2, &call_setting,
305
 
                                      NULL, NULL, &currentCall_);
306
 
        if (status != PJ_SUCCESS) {
307
 
            showError("make call", status);
308
 
            return;
309
 
        }
310
 
    }
311
 
}
312
 
 
313
 
void MainWin::hangup()
314
 
{
315
 
    pj_assert(currentCall_ != -1);
316
 
    //pjsua_call_hangup(currentCall_, PJSIP_SC_BUSY_HERE, NULL, NULL);
317
 
    pjsua_call_hangup_all();
318
 
    emit signalCallReleased();
319
 
}
320
 
 
321
 
 
322
 
void MainWin::initVideoWindow()
323
 
{
324
 
    pjsua_call_info ci;
325
 
    unsigned i;
326
 
 
327
 
    if (currentCall_ == -1)
328
 
        return;
329
 
 
330
 
    delete video_;
331
 
    video_ = NULL;
332
 
 
333
 
    pjsua_call_get_info(currentCall_, &ci);
334
 
    for (i = 0; i < ci.media_cnt; ++i) {
335
 
        if ((ci.media[i].type == PJMEDIA_TYPE_VIDEO) &&
336
 
            (ci.media[i].dir & PJMEDIA_DIR_DECODING))
337
 
        {
338
 
            pjsua_vid_win_info wi;
339
 
            pjsua_vid_win_get_info(ci.media[i].stream.vid.win_in, &wi);
340
 
 
341
 
            video_= new VidWin(&wi.hwnd);
342
 
            video_->putIntoLayout(vbox_left);
343
 
 
344
 
            break;
345
 
        }
346
 
    }
347
 
}
348
 
 
349
 
void MainWin::on_reg_state(pjsua_acc_id acc_id)
350
 
{
351
 
    pjsua_acc_info info;
352
 
 
353
 
    pjsua_acc_get_info(acc_id, &info);
354
 
 
355
 
    char reg_status[80];
356
 
    char status[120];
357
 
 
358
 
    if (!info.has_registration) {
359
 
        pj_ansi_snprintf(reg_status, sizeof(reg_status), "%.*s",
360
 
                         (int)info.status_text.slen,
361
 
                         info.status_text.ptr);
362
 
 
363
 
    } else {
364
 
        pj_ansi_snprintf(reg_status, sizeof(reg_status),
365
 
                         "%d/%.*s (expires=%d)",
366
 
                         info.status,
367
 
                         (int)info.status_text.slen,
368
 
                         info.status_text.ptr,
369
 
                         info.expires);
370
 
 
371
 
    }
372
 
 
373
 
    snprintf(status, sizeof(status),
374
 
             "%.*s: %s\n",
375
 
             (int)info.acc_uri.slen, info.acc_uri.ptr,
376
 
             reg_status);
377
 
    showStatus(status);
378
 
}
379
 
 
380
 
void MainWin::on_call_state(pjsua_call_id call_id, pjsip_event *e)
381
 
{
382
 
    pjsua_call_info ci;
383
 
 
384
 
    PJ_UNUSED_ARG(e);
385
 
 
386
 
    pjsua_call_get_info(call_id, &ci);
387
 
 
388
 
    if (currentCall_ == -1 && ci.state < PJSIP_INV_STATE_DISCONNECTED &&
389
 
        ci.role == PJSIP_ROLE_UAC)
390
 
    {
391
 
        emit signalNewCall(call_id, false);
392
 
    }
393
 
 
394
 
    char status[80];
395
 
    if (ci.state == PJSIP_INV_STATE_DISCONNECTED) {
396
 
        snprintf(status, sizeof(status), "Call is %s (%s)",
397
 
                 ci.state_text.ptr,
398
 
                 ci.last_status_text.ptr);
399
 
        showStatus(status);
400
 
        emit signalCallReleased();
401
 
    } else {
402
 
        snprintf(status, sizeof(status), "Call is %s", pjsip_inv_state_name(ci.state));
403
 
        showStatus(status);
404
 
    }
405
 
}
406
 
 
407
 
void MainWin::on_incoming_call(pjsua_acc_id acc_id, pjsua_call_id call_id,
408
 
                               pjsip_rx_data *rdata)
409
 
{
410
 
    PJ_UNUSED_ARG(acc_id);
411
 
    PJ_UNUSED_ARG(rdata);
412
 
 
413
 
    if (currentCall_ != -1) {
414
 
        pjsua_call_answer(call_id, PJSIP_SC_BUSY_HERE, NULL, NULL);
415
 
        return;
416
 
    }
417
 
 
418
 
    emit signalNewCall(call_id, true);
419
 
 
420
 
    pjsua_call_info ci;
421
 
    char status[80];
422
 
 
423
 
    pjsua_call_get_info(call_id, &ci);
424
 
    snprintf(status, sizeof(status), "Incoming call from %.*s",
425
 
             (int)ci.remote_info.slen, ci.remote_info.ptr);
426
 
    showStatus(status);
427
 
}
428
 
 
429
 
void MainWin::on_call_media_state(pjsua_call_id call_id)
430
 
{
431
 
    pjsua_call_info ci;
432
 
 
433
 
    pjsua_call_get_info(call_id, &ci);
434
 
 
435
 
    for (unsigned i=0; i<ci.media_cnt; ++i) {
436
 
        if (ci.media[i].type == PJMEDIA_TYPE_AUDIO) {
437
 
            switch (ci.media[i].status) {
438
 
            case PJSUA_CALL_MEDIA_ACTIVE:
439
 
                pjsua_conf_connect(ci.media[i].stream.aud.conf_slot, 0);
440
 
                pjsua_conf_connect(0, ci.media[i].stream.aud.conf_slot);
441
 
                break;
442
 
            default:
443
 
                break;
444
 
            }
445
 
        } else if (ci.media[i].type == PJMEDIA_TYPE_VIDEO) {
446
 
            emit signalInitVideoWindow();
447
 
        }
448
 
    }
449
 
}
450
 
 
451
 
//
452
 
// pjsua callbacks
453
 
//
454
 
static void on_reg_state(pjsua_acc_id acc_id)
455
 
{
456
 
    MainWin::instance()->on_reg_state(acc_id);
457
 
}
458
 
 
459
 
static void on_call_state(pjsua_call_id call_id, pjsip_event *e)
460
 
{
461
 
    MainWin::instance()->on_call_state(call_id, e);
462
 
}
463
 
 
464
 
static void on_incoming_call(pjsua_acc_id acc_id, pjsua_call_id call_id,
465
 
                             pjsip_rx_data *rdata)
466
 
{
467
 
    MainWin::instance()->on_incoming_call(acc_id, call_id, rdata);
468
 
}
469
 
 
470
 
static void on_call_media_state(pjsua_call_id call_id)
471
 
{
472
 
    MainWin::instance()->on_call_media_state(call_id);
473
 
}
474
 
 
475
 
//
476
 
// initStack()
477
 
//
478
 
bool MainWin::initStack()
479
 
{
480
 
    pj_status_t status;
481
 
 
482
 
    //showStatus("Creating stack..");
483
 
    status = pjsua_create();
484
 
    if (status != PJ_SUCCESS) {
485
 
        showError("pjsua_create", status);
486
 
        return false;
487
 
    }
488
 
 
489
 
    showStatus("Initializing stack..");
490
 
 
491
 
    pjsua_config ua_cfg;
492
 
    pjsua_config_default(&ua_cfg);
493
 
    pjsua_callback ua_cb;
494
 
    pj_bzero(&ua_cb, sizeof(ua_cb));
495
 
    ua_cfg.cb.on_reg_state = &::on_reg_state;
496
 
    ua_cfg.cb.on_call_state = &::on_call_state;
497
 
    ua_cfg.cb.on_incoming_call = &::on_incoming_call;
498
 
    ua_cfg.cb.on_call_media_state = &::on_call_media_state;
499
 
#if USE_STUN
500
 
    ua_cfg.stun_srv_cnt = 1;
501
 
    ua_cfg.stun_srv[0] = pj_str((char*)STUN_SRV);
502
 
#endif
503
 
 
504
 
    pjsua_logging_config log_cfg;
505
 
    pjsua_logging_config_default(&log_cfg);
506
 
    log_cfg.log_filename = pj_str((char*)LOG_FILE);
507
 
 
508
 
    pjsua_media_config med_cfg;
509
 
    pjsua_media_config_default(&med_cfg);
510
 
    med_cfg.enable_ice = USE_ICE;
511
 
 
512
 
    status = pjsua_init(&ua_cfg, &log_cfg, &med_cfg);
513
 
    if (status != PJ_SUCCESS) {
514
 
        showError("pjsua_init", status);
515
 
        goto on_error;
516
 
    }
517
 
 
518
 
    //
519
 
    // Create UDP and TCP transports
520
 
    //
521
 
    pjsua_transport_config udp_cfg;
522
 
    pjsua_transport_id udp_id;
523
 
    pjsua_transport_config_default(&udp_cfg);
524
 
    udp_cfg.port = SIP_PORT;
525
 
 
526
 
    status = pjsua_transport_create(PJSIP_TRANSPORT_UDP,
527
 
                                    &udp_cfg, &udp_id);
528
 
    if (status != PJ_SUCCESS) {
529
 
        showError("UDP transport creation", status);
530
 
        goto on_error;
531
 
    }
532
 
 
533
 
    pjsua_transport_info udp_info;
534
 
    status = pjsua_transport_get_info(udp_id, &udp_info);
535
 
    if (status != PJ_SUCCESS) {
536
 
        showError("UDP transport info", status);
537
 
        goto on_error;
538
 
    }
539
 
 
540
 
#if SIP_TCP
541
 
    pjsua_transport_config tcp_cfg;
542
 
    pjsua_transport_config_default(&tcp_cfg);
543
 
    tcp_cfg.port = 0;
544
 
 
545
 
    status = pjsua_transport_create(PJSIP_TRANSPORT_TCP,
546
 
                                    &tcp_cfg, NULL);
547
 
    if (status != PJ_SUCCESS) {
548
 
        showError("TCP transport creation", status);
549
 
        goto on_error;
550
 
    }
551
 
#endif
552
 
 
553
 
    //
554
 
    // Create account
555
 
    //
556
 
    pjsua_acc_config acc_cfg;
557
 
    pjsua_acc_config_default(&acc_cfg);
558
 
#if USE_REGISTRATION
559
 
    acc_cfg.id = pj_str( (char*)"<sip:" SIP_USERNAME "@" SIP_DOMAIN ">");
560
 
    acc_cfg.reg_uri = pj_str((char*) ("sip:" SIP_DOMAIN));
561
 
    acc_cfg.cred_count = 1;
562
 
    acc_cfg.cred_info[0].realm = pj_str((char*)"*");
563
 
    acc_cfg.cred_info[0].scheme = pj_str((char*)"digest");
564
 
    acc_cfg.cred_info[0].username = pj_str((char*)SIP_USERNAME);
565
 
    acc_cfg.cred_info[0].data = pj_str((char*)SIP_PASSWORD);
566
 
 
567
 
# if SIP_TCP
568
 
    acc_cfg.proxy[acc_cfg.proxy_cnt++] = pj_str((char*) "<sip:" SIP_DOMAIN ";transport=tcp>");
569
 
# endif
570
 
 
571
 
#else
572
 
    char sip_id[80];
573
 
    snprintf(sip_id, sizeof(sip_id),
574
 
             "sip:%s@%.*s:%u", SIP_USERNAME,
575
 
             (int)udp_info.local_name.host.slen,
576
 
             udp_info.local_name.host.ptr,
577
 
             udp_info.local_name.port);
578
 
    acc_cfg.id = pj_str(sip_id);
579
 
#endif
580
 
 
581
 
    acc_cfg.vid_cap_dev = DEFAULT_CAP_DEV;
582
 
    acc_cfg.vid_rend_dev = DEFAULT_REND_DEV;
583
 
    acc_cfg.vid_in_auto_show = PJ_TRUE;
584
 
    acc_cfg.vid_out_auto_transmit = PJ_TRUE;
585
 
 
586
 
    status = pjsua_acc_add(&acc_cfg, PJ_TRUE, &accountId_);
587
 
    if (status != PJ_SUCCESS) {
588
 
        showError("Account creation", status);
589
 
        goto on_error;
590
 
    }
591
 
 
592
 
    localUri_->setText(acc_cfg.id.ptr);
593
 
 
594
 
    //
595
 
    // Start pjsua!
596
 
    //
597
 
    showStatus("Starting stack..");
598
 
    status = pjsua_start();
599
 
    if (status != PJ_SUCCESS) {
600
 
        showError("pjsua_start", status);
601
 
        goto on_error;
602
 
    }
603
 
 
604
 
    showStatus("Ready");
605
 
 
606
 
    return true;
607
 
 
608
 
on_error:
609
 
    pjsua_destroy();
610
 
    return false;
611
 
}
612
 
 
613
 
/*
614
 
 * A simple registrar, invoked by default_mod_on_rx_request()
615
 
 */
616
 
static void simple_registrar(pjsip_rx_data *rdata)
617
 
{
618
 
    pjsip_tx_data *tdata;
619
 
    const pjsip_expires_hdr *exp;
620
 
    const pjsip_hdr *h;
621
 
    unsigned cnt = 0;
622
 
    pjsip_generic_string_hdr *srv;
623
 
    pj_status_t status;
624
 
 
625
 
    status = pjsip_endpt_create_response(pjsua_get_pjsip_endpt(),
626
 
                                 rdata, 200, NULL, &tdata);
627
 
    if (status != PJ_SUCCESS)
628
 
        return;
629
 
 
630
 
    exp = (pjsip_expires_hdr*)
631
 
          pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL);
632
 
 
633
 
    h = rdata->msg_info.msg->hdr.next;
634
 
    while (h != &rdata->msg_info.msg->hdr) {
635
 
        if (h->type == PJSIP_H_CONTACT) {
636
 
            const pjsip_contact_hdr *c = (const pjsip_contact_hdr*)h;
637
 
            int e = c->expires;
638
 
 
639
 
            if (e < 0) {
640
 
                if (exp)
641
 
                    e = exp->ivalue;
642
 
                else
643
 
                    e = 3600;
644
 
            }
645
 
 
646
 
            if (e > 0) {
647
 
                pjsip_contact_hdr *nc = (pjsip_contact_hdr*)
648
 
                                        pjsip_hdr_clone(tdata->pool, h);
649
 
                nc->expires = e;
650
 
                pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)nc);
651
 
                ++cnt;
652
 
            }
653
 
        }
654
 
        h = h->next;
655
 
    }
656
 
 
657
 
    srv = pjsip_generic_string_hdr_create(tdata->pool, NULL, NULL);
658
 
    srv->name = pj_str((char*)"Server");
659
 
    srv->hvalue = pj_str((char*)"pjsua simple registrar");
660
 
    pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)srv);
661
 
 
662
 
    pjsip_endpt_send_response2(pjsua_get_pjsip_endpt(),
663
 
                               rdata, tdata, NULL, NULL);
664
 
}
665
 
 
666
 
/* Notification on incoming request */
667
 
static pj_bool_t default_mod_on_rx_request(pjsip_rx_data *rdata)
668
 
{
669
 
    /* Simple registrar */
670
 
    if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method,
671
 
                         &pjsip_register_method) == 0)
672
 
    {
673
 
        simple_registrar(rdata);
674
 
        return PJ_TRUE;
675
 
    }
676
 
 
677
 
    return PJ_FALSE;
678
 
}
679
 
 
680
 
/* The module instance. */
681
 
static pjsip_module mod_default_handler =
682
 
{
683
 
    NULL, NULL,                         /* prev, next.          */
684
 
    { (char*)"mod-default-handler", 19 },       /* Name.                */
685
 
    -1,                                 /* Id                   */
686
 
    PJSIP_MOD_PRIORITY_APPLICATION+99,  /* Priority             */
687
 
    NULL,                               /* load()               */
688
 
    NULL,                               /* start()              */
689
 
    NULL,                               /* stop()               */
690
 
    NULL,                               /* unload()             */
691
 
    &default_mod_on_rx_request,         /* on_rx_request()      */
692
 
    NULL,                               /* on_rx_response()     */
693
 
    NULL,                               /* on_tx_request.       */
694
 
    NULL,                               /* on_tx_response()     */
695
 
    NULL,                               /* on_tsx_state()       */
696
 
 
697
 
};
698
 
 
699
 
int main(int argc, char *argv[])
700
 
{
701
 
    /* At least on Linux, we have to initialize SDL video subsystem prior to
702
 
     * creating/initializing QApplication, otherwise we'll segfault miserably
703
 
     * in SDL_CreateWindow(). Here's a stack trace if you're interested:
704
 
 
705
 
        Thread [7] (Suspended: Signal 'SIGSEGV' received. Description: Segmentation fault.)
706
 
        13 XCreateIC()
707
 
        12 SetupWindowData()
708
 
        11 X11_CreateWindow()
709
 
        10 SDL_CreateWindow()
710
 
        ..
711
 
     */
712
 
    if ( SDL_InitSubSystem(SDL_INIT_VIDEO) < 0 ) {
713
 
        printf("Unable to init SDL: %s\n", SDL_GetError());
714
 
        return 1;
715
 
    }
716
 
 
717
 
    QApplication app(argc, argv);
718
 
 
719
 
    MainWin win;
720
 
    win.show();
721
 
 
722
 
    if (!win.initStack()) {
723
 
        win.quit();
724
 
        return 1;
725
 
    }
726
 
 
727
 
    /* We want to be registrar too! */
728
 
    if (pjsua_get_pjsip_endpt()) {
729
 
        pjsip_endpt_register_module(pjsua_get_pjsip_endpt(),
730
 
                                    &mod_default_handler);
731
 
    }
732
 
 
733
 
    return app.exec();
734
 
}