managerimpl.cpp 81 KB
Newer Older
jpbl's avatar
jpbl committed
1
/*
2 3
 *  Copyright (C) 2004-2007 Savoir-Faire Linux inc.
 *  Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com>
jpbl's avatar
jpbl committed
4
 *  Author: Yan Morin <yan.morin@savoirfairelinux.com>
5
 *  Author: Laurielle Lea <laurielle.lea@savoirfairelinux.com>
6
 *  Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
7
 *  Author: Guillaume Carmel-Archambault <guillaume.carmel-archambault@savoirfairelinux.com>
8
 *
jpbl's avatar
jpbl committed
9 10
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
11
 *  the Free Software Foundation; either version 3 of the License, or
jpbl's avatar
jpbl committed
12
 *  (at your option) any later version.
13
 *
jpbl's avatar
jpbl committed
14 15 16 17
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
18
 *
jpbl's avatar
jpbl committed
19 20 21 22 23 24 25 26 27 28
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <errno.h>
#include <time.h>
#include <cstdlib>
#include <iostream>
#include <fstream>
29
#include <sstream>
jpbl's avatar
jpbl committed
30 31 32 33 34 35 36 37 38
#include <sys/types.h> // mkdir(2)
#include <sys/stat.h>	// mkdir(2)

#include <cc++/socket.h>   // why do I need this here?
#include <ccrtp/channel.h> // why do I need this here?
#include <ccrtp/rtp.h>     // why do I need this here?
#include <cc++/file.h>

#include "manager.h"
39
#include "account.h"
40
#include "sipaccount.h"
jpbl's avatar
jpbl committed
41
#include "audio/audiolayer.h"
42 43
#include "audio/alsalayer.h"
#include "audio/pulselayer.h"
jpbl's avatar
jpbl committed
44 45
#include "audio/tonelist.h"

46
#include "accountcreator.h" // create new account
47 48
#include "sipvoiplink.h"

jpbl's avatar
jpbl committed
49 50 51 52 53 54 55
#include "user_cfg.h"

#define fill_config_str(name, value) \
  (_config.addConfigTreeItem(section, Conf::ConfigTreeItem(std::string(name), std::string(value), type_str)))
#define fill_config_int(name, value) \
  (_config.addConfigTreeItem(section, Conf::ConfigTreeItem(std::string(name), std::string(value), type_int)))

56
ManagerImpl::ManagerImpl (void)
57
        : _hasTriedToRegister (false)
Yun Liu's avatar
Yun Liu committed
58
        , _config()
59
        , _currentCallId2()
60
        , _currentCallMutex()
61 62 63
        , _codecBuilder (NULL)
        , _audiodriver (NULL)
        , _dtmfKey (NULL)
Yun Liu's avatar
Yun Liu committed
64
        , _codecDescriptorMap()
65
        , _toneMutex()
66
        , _telephoneTone (NULL)
Yun Liu's avatar
Yun Liu committed
67
        , _audiofile()
68 69
        , _spkr_volume (0)
        , _mic_volume (0)
70
        , _mutex()
71
        , _dbus (NULL)
Yun Liu's avatar
Yun Liu committed
72
        , _waitingCall()
73
        , _waitingCallMutex()
74 75 76 77
        , _nbIncomingWaitingCall (0)
        , _path ("")
        , _exist (0)
        , _setupLoaded (false)
Yun Liu's avatar
Yun Liu committed
78
        , _firewallPort()
79 80
        , _firewallAddr ("")
        , _hasZeroconf (false)
Yun Liu's avatar
Yun Liu committed
81
        , _callAccountMap()
82
        , _callAccountMapMutex()
83
        , _callConfigMap()
Yun Liu's avatar
Yun Liu committed
84
        , _accountMap()
85
        , _cleaner (NULL)
86
        , _history (NULL)
jpbl's avatar
jpbl committed
87
{
88

89
    // initialize random generator for call id
90
    srand (time (NULL));
91

92
    _cleaner = new NumberCleaner ();
93
    _history = new HistoryManager ();
94

95
#ifdef TEST
96 97 98 99
    testAccountMap();
    loadAccountMap();
    testCallAccountMap();
    unloadAccountMap();
100 101
#endif

102 103
    // should be call before initConfigFile
    // loadAccountMap();, called in init() now.
jpbl's avatar
jpbl committed
104 105 106
}

// never call if we use only the singleton...
107
ManagerImpl::~ManagerImpl (void)
jpbl's avatar
jpbl committed
108
{
109
    // terminate();
110 111 112
    delete _cleaner;
    _cleaner=0;
    _debug ("%s stop correctly.\n", PROGNAME);
jpbl's avatar
jpbl committed
113 114
}

115
void
116
ManagerImpl::init()
jpbl's avatar
jpbl committed
117
{
118 119
    // Load accounts, init map
    loadAccountMap();
120

121
    initVolume();
122

123
    if (_exist == 0) {
124
        _debug ("Cannot create config file in your home directory\n");
125
    }
126

127
    initAudioDriver();
128

129
    selectAudioDriver();
jpbl's avatar
jpbl committed
130

131 132
    // Initialize the list of supported audio codecs
    initAudioCodec();
133

134
    AudioLayer *audiolayer = getAudioDriver();
135

136
    if (audiolayer != 0) {
137
        unsigned int sampleRate = audiolayer->getSampleRate();
jpbl's avatar
jpbl committed
138

139 140 141
        _debugInit ("Load Telephone Tone");
        std::string country = getConfigString (PREFERENCES, ZONE_TONE);
        _telephoneTone = new TelephoneTone (country, sampleRate);
jpbl's avatar
jpbl committed
142

143 144
        _debugInit ("Loading DTMF key");
        _dtmfKey = new DTMF (sampleRate);
145
    }
146 147

    if (audiolayer == 0)
148
        audiolayer->stopStream();
149 150 151


    // Load the history
152
    _history->load_history (getConfigInt (PREFERENCES, CONFIG_HISTORY_LIMIT));
jpbl's avatar
jpbl committed
153 154 155 156
}

void ManagerImpl::terminate()
{
157
    _debug ("ManagerImpl::terminate \n");
158
    saveConfig();
jpbl's avatar
jpbl committed
159

160
    unloadAccountMap();
161

162
    _debug ("Unload DTMF Key \n");
163
    delete _dtmfKey;
jpbl's avatar
jpbl committed
164

165 166 167
    _debug ("Unload Audio Driver \n");
    delete _audiodriver;
    _audiodriver = NULL;
jpbl's avatar
jpbl committed
168

169 170 171
    _debug ("Unload Telephone Tone \n");
    delete _telephoneTone;
    _telephoneTone = NULL;
172

173
    _debug ("Unload Audio Codecs \n");
174
    _codecDescriptorMap.deleteHandlePointer();
175

jpbl's avatar
jpbl committed
176 177
}

yanmorin's avatar
yanmorin committed
178
bool
179 180 181
ManagerImpl::isCurrentCall (const CallID& callId)
{
    return (_currentCallId2 == callId ? true : false);
jpbl's avatar
jpbl committed
182 183
}

yanmorin's avatar
yanmorin committed
184
bool
185 186 187 188 189 190 191 192 193
ManagerImpl::hasCurrentCall()
{
    _debug ("Current call ID = %s\n", _currentCallId2.c_str());

    if (_currentCallId2 != "") {
        return true;
    }

    return false;
jpbl's avatar
jpbl committed
194 195
}

196
const CallID&
197 198 199
ManagerImpl::getCurrentCallId()
{
    return _currentCallId2;
jpbl's avatar
jpbl committed
200 201 202
}

void
203 204 205 206
ManagerImpl::switchCall (const CallID& id)
{
    ost::MutexLock m (_currentCallMutex);
    _currentCallId2 = id;
jpbl's avatar
jpbl committed
207 208 209 210 211 212
}


///////////////////////////////////////////////////////////////////////////////
// Management of events' IP-phone user
///////////////////////////////////////////////////////////////////////////////
213
/* Main Thread */
214

215 216
bool
ManagerImpl::outgoingCall (const std::string& accountid, const CallID& id, const std::string& to)
yanmorin's avatar
yanmorin committed
217
{
218
    std::string pattern, to_cleaned;
219 220
    Call::CallConfiguration callConfig;
    SIPVoIPLink *siplink;
221

222
    _debug ("ManagerImpl::outgoingCall() method \n");
223

224 225
    if (getConfigString (HOOKS, PHONE_NUMBER_HOOK_ENABLED) ==  "1")
        _cleaner->set_phone_number_prefix (getConfigString (HOOKS, PHONE_NUMBER_HOOK_ADD_PREFIX));
226 227
    else
        _cleaner->set_phone_number_prefix ("");
228

229
    to_cleaned = _cleaner->clean (to);
230 231

    /* Check what kind of call we are dealing with */
232
    check_call_configuration (id, to_cleaned, &callConfig);
233

234 235 236
    if (callConfig == Call::IPtoIP) {
        _debug ("Start IP to IP call\n");
        /* We need to retrieve the sip voiplink instance */
237 238
        siplink = SIPVoIPLink::instance ("");

239
        if (siplink->new_ip_to_ip_call (id, to_cleaned)) {
240 241
            switchCall (id);
            return true;
242
        } else {
243 244
            callFailure (id);
        }
245

246
        return false;
247
    }
248

249 250
    if (!accountExists (accountid)) {
        _debug ("! Manager Error: Outgoing Call: account doesn't exist\n");
251 252
        return false;
    }
253

254 255
    if (getAccountFromCall (id) != AccountNULL) {
        _debug ("! Manager Error: Outgoing Call: call id already exists\n");
256 257
        return false;
    }
258

259
    if (hasCurrentCall()) {
260 261
        _debug ("* Manager Info: there is currently a call, try to hold it\n");
        onHoldCall (getCurrentCallId());
262
    }
263

264 265 266 267 268 269
    _debug ("- Manager Action: Adding Outgoing Call %s on account %s\n", id.data(), accountid.data());

    associateCallToAccount (id, accountid);

    if (getAccountLink (accountid)->newOutgoingCall (id, to_cleaned)) {
        switchCall (id);
270 271
        return true;
    } else {
272 273
        callFailure (id);
        _debug ("! Manager Error: An error occur, the call was not created\n");
274
    }
275

276
    return false;
jpbl's avatar
jpbl committed
277 278
}

yanmorin's avatar
yanmorin committed
279
//THREAD=Main : for outgoing Call
280 281
bool
ManagerImpl::answerCall (const CallID& id)
jpbl's avatar
jpbl committed
282
{
283 284 285
    bool isActive = false;

    stopTone (true);
286

287 288
    AccountID currentaccountid = getAccountFromCall (id);
    Call* currentcall = getAccountLink (currentaccountid)->getCall (getCurrentCallId());
289

290 291
    if (currentcall->getState() == 1)
        isActive = true;
292

293 294
    // stopTone(false);
    _debug ("Try to answer call: %s\n", id.data());
295

296
    AccountID accountid = getAccountFromCall (id);
297

298 299 300 301
    if (accountid == AccountNULL) {
        _debug ("Answering Call: Call doesn't exists\n");
        //return false;
    }
302

303 304 305
    //  if (id != getCurrentCallId()) {
    if (isActive) {
        _debug ("* Manager Info: there is currently a call, try to hold it\n");
Yun Liu's avatar
Yun Liu committed
306

307 308 309 310 311 312 313 314
        onHoldCall (getCurrentCallId());
    }

    if (!getAccountLink (accountid)->answer (id)) {
        // error when receiving...
        removeCallAccount (id);
        return false;
    }
Alexandre Savard's avatar
Alexandre Savard committed
315

316 317
    // if it was waiting, it's waiting no more
    if (_dbus) _dbus->getCallManager()->callStateChanged (id, "CURRENT");
318

319
    removeWaitingCall (id);
320

321 322 323 324 325 326 327
    switchCall (id);

    // std::string codecName = getCurrentCodecName(id);
    // _debug("ManagerImpl::hangupCall(): broadcast codec name %s \n",codecName.c_str());
    // if (_dbus) _dbus->getCallManager()->currentSelectedCodec(id,codecName.c_str());

    return true;
jpbl's avatar
jpbl committed
328 329
}

yanmorin's avatar
yanmorin committed
330
//THREAD=Main
331 332
bool
ManagerImpl::hangupCall (const CallID& id)
jpbl's avatar
jpbl committed
333
{
334
    _debug ("ManagerImpl::hangupCall()\n");
335 336 337
    PulseLayer *pulselayer;
    AccountID accountid;
    bool returnValue;
338
    AudioLayer *audiolayer;
Emmanuel Milou's avatar
Emmanuel Milou committed
339

340
    stopTone (false);
yanmorin's avatar
yanmorin committed
341

342
    /* Broadcast a signal over DBus */
343

344 345 346 347
    if (_dbus) _dbus->getCallManager()->callStateChanged (id, "HUNGUP");

    _debug ("Stop audio stream\n");

348
    audiolayer = getAudioDriver();
349 350 351

    int nbCalls = getCallList().size();

pierre-luc's avatar
pierre-luc committed
352
    _debug ("hangupCall: callList is of size %i call(s)\n", nbCalls);
353

354 355
    // stop stream
    if (! (nbCalls > 1))
356
        audiolayer->stopStream();
357

358 359
    /* Direct IP to IP call */
    if (getConfigFromCall (id) == Call::IPtoIP) {
360
        returnValue = SIPVoIPLink::instance (AccountNULL)->hangup (id);
361
    }
362

363
    /* Classic call, attached to an account */
364
    else {
365 366
        accountid = getAccountFromCall (id);

367
        if (accountid == AccountNULL) {
368
            _debug ("! Manager Hangup Call: Call doesn't exists\n");
369 370
            return false;
        }
371 372 373 374

        returnValue = getAccountLink (accountid)->hangup (id);

        removeCallAccount (id);
375
    }
376

377
    switchCall ("");
378

379
    if (_audiodriver->getLayerType() == PULSEAUDIO && getConfigInt (PREFERENCES , CONFIG_PA_VOLUME_CTRL)) {
380
        pulselayer = dynamic_cast<PulseLayer *> (getAudioDriver());
381 382

        if (pulselayer)  pulselayer->restorePulseAppsVolume();
383
    }
384

385

386

387
    return returnValue;
jpbl's avatar
jpbl committed
388 389
}

yanmorin's avatar
yanmorin committed
390
//THREAD=Main
391
bool
yanmorin's avatar
yanmorin committed
392
ManagerImpl::cancelCall (const CallID& id)
jpbl's avatar
jpbl committed
393
{
394 395
    AccountID accountid;
    bool returnValue;
yanmorin's avatar
yanmorin committed
396

397
    stopTone (true);
398

399
    /* Direct IP to IP call */
400

401
    if (getConfigFromCall (id) == Call::IPtoIP) {
402
        returnValue = SIPVoIPLink::instance (AccountNULL)->cancel (id);
403 404 405
    }

    /* Classic call, attached to an account */
406
    else {
407 408
        accountid = getAccountFromCall (id);

409
        if (accountid == AccountNULL) {
410
            _debug ("! Manager Cancel Call: Call doesn't exists\n");
411 412
            return false;
        }
413 414 415 416

        returnValue = getAccountLink (accountid)->cancel (id);

        removeCallAccount (id);
417
    }
418

419
    // it could be a waiting call?
420 421 422
    removeWaitingCall (id);

    switchCall ("");
423 424

    return returnValue;
jpbl's avatar
jpbl committed
425 426
}

yanmorin's avatar
yanmorin committed
427
//THREAD=Main
428 429
bool
ManagerImpl::onHoldCall (const CallID& id)
jpbl's avatar
jpbl committed
430
{
431 432
    AccountID accountid;
    bool returnValue;
433
    CallID call_id;
yanmorin's avatar
yanmorin committed
434

435
    stopTone (true);
436

437 438
    call_id = id;

439
    /* Direct IP to IP call */
440

441
    if (getConfigFromCall (id) == Call::IPtoIP) {
442
        returnValue = SIPVoIPLink::instance (AccountNULL)-> onhold (id);
443
    }
444

445
    /* Classic call, attached to an account */
446
    else {
447 448
        accountid = getAccountFromCall (id);

449
        if (accountid == AccountNULL) {
450
            _debug ("Manager On Hold Call: Account ID %s or callid %s doesn't exists\n", accountid.c_str(), id.c_str());
451 452
            return false;
        }
453 454

        returnValue = getAccountLink (accountid)->onhold (id);
455
    }
456

457 458 459
    removeWaitingCall (id);

    switchCall ("");
460

461
    if (_dbus) _dbus->getCallManager()->callStateChanged (call_id, "HOLD");
462

463
    return returnValue;
yanmorin's avatar
yanmorin committed
464 465 466
}

//THREAD=Main
467 468
bool
ManagerImpl::offHoldCall (const CallID& id)
yanmorin's avatar
yanmorin committed
469
{
470

471 472 473
    AccountID accountid;
    bool returnValue, rec;
    std::string codecName;
474
    CallID call_id;
475

476
    stopTone (false);
477

478
    call_id = id;
479
    //Place current call on hold if it isn't
480 481

    if (hasCurrentCall()) {
482
        _debug ("Put the current call (ID=%s) on hold\n", getCurrentCallId().c_str());
483
        onHoldCall (getCurrentCallId());
484
    }
485

486 487 488
    /* Direct IP to IP call */
    if (getConfigFromCall (id) == Call::IPtoIP) {
        rec = SIPVoIPLink::instance (AccountNULL)-> isRecording (id);
489
        returnValue = SIPVoIPLink::instance (AccountNULL)-> offhold (id);
490
    }
491

492
    /* Classic call, attached to an account */
493
    else {
494 495
        accountid = getAccountFromCall (id);

496
        if (accountid == AccountNULL) {
497
            _debug ("Manager OffHold Call: Call doesn't exists\n");
498 499
            return false;
        }
500 501 502 503 504

        _debug ("Setting OFFHOLD, Account %s, callid %s\n", accountid.c_str(), id.c_str());

        rec = getAccountLink (accountid)->isRecording (id);
        returnValue = getAccountLink (accountid)->offhold (id);
505
    }
506

507

508
    if (_dbus) {
509
        if (rec)
510
            _dbus->getCallManager()->callStateChanged (call_id, "UNHOLD_RECORD");
511
        else
512
            _dbus->getCallManager()->callStateChanged (call_id, "UNHOLD_CURRENT");
513

514
    }
515

516
    switchCall (id);
517

518
    codecName = getCurrentCodecName (id);
519
    // _debug("ManagerImpl::hangupCall(): broadcast codec name %s \n",codecName.c_str());
520 521

    if (_dbus) _dbus->getCallManager()->currentSelectedCodec (id,codecName.c_str());
522

523
    return returnValue;
jpbl's avatar
jpbl committed
524 525
}

yanmorin's avatar
yanmorin committed
526
//THREAD=Main
527 528
bool
ManagerImpl::transferCall (const CallID& id, const std::string& to)
jpbl's avatar
jpbl committed
529
{
530 531
    AccountID accountid;
    bool returnValue;
532

533
    stopTone (true);
534

535
    /* Direct IP to IP call */
536

537
    if (getConfigFromCall (id) == Call::IPtoIP) {
538
        returnValue = SIPVoIPLink::instance (AccountNULL)-> transfer (id, to);
539 540 541
    }

    /* Classic call, attached to an account */
542
    else {
543 544
        accountid = getAccountFromCall (id);

545
        if (accountid == AccountNULL) {
546
            _debug ("! Manager Transfer Call: Call doesn't exists\n");
547 548
            return false;
        }
549 550 551 552

        returnValue = getAccountLink (accountid)->transfer (id, to);

        removeCallAccount (id);
553
    }
554

555 556 557 558 559
    removeWaitingCall (id);

    switchCall ("");

    if (_dbus) _dbus->getCallManager()->callStateChanged (id, "HUNGUP");
560

561
    return returnValue;
jpbl's avatar
jpbl committed
562 563
}

564 565
void ManagerImpl::transferFailed()
{
566
    if (_dbus) _dbus->getCallManager()->transferFailed();
567 568 569 570
}

void ManagerImpl::transferSucceded()
{
571
    if (_dbus) _dbus->getCallManager()->transferSucceded();
572 573 574 575

}


yanmorin's avatar
yanmorin committed
576
//THREAD=Main : Call:Incoming
577
bool
yanmorin's avatar
yanmorin committed
578
ManagerImpl::refuseCall (const CallID& id)
jpbl's avatar
jpbl committed
579
{
580 581
    AccountID accountid;
    bool returnValue;
582

583 584 585
    stopTone (true);

    /* Direct IP to IP call */
586 587

    if (getConfigFromCall (id) == Call::IPtoIP) {
588
        returnValue = SIPVoIPLink::instance (AccountNULL)-> refuse (id);
589 590 591
    }

    /* Classic call, attached to an account */
592
    else {
593 594
        accountid = getAccountFromCall (id);

595
        if (accountid == AccountNULL) {
596
            _debug ("! Manager OffHold Call: Call doesn't exists\n");
597 598
            return false;
        }
599 600 601 602

        returnValue = getAccountLink (accountid)->refuse (id);

        removeCallAccount (id);
603 604
    }

605 606 607
    // if the call was outgoing or established, we didn't refuse it
    // so the method did nothing
    if (returnValue) {
608 609 610 611 612
        removeWaitingCall (id);

        if (_dbus) _dbus->getCallManager()->callStateChanged (id, "HUNGUP");

        switchCall ("");
613
    }
614

615
    return returnValue;
jpbl's avatar
jpbl committed
616 617
}

yanmorin's avatar
yanmorin committed
618
//THREAD=Main
619
bool
jpbl's avatar
jpbl committed
620 621
ManagerImpl::saveConfig (void)
{
622 623 624
    _debug ("Saving Configuration...\n");
    setConfig (AUDIO, VOLUME_SPKR, getSpkrVolume());
    setConfig (AUDIO, VOLUME_MICRO, getMicVolume());
jpbl's avatar
jpbl committed
625

626 627
    _setupLoaded = _config.saveConfigTree (_path.data());
    return _setupLoaded;
jpbl's avatar
jpbl committed
628 629
}

yanmorin's avatar
yanmorin committed
630
//THREAD=Main
631
int
632
ManagerImpl::initRegisterAccounts()
jpbl's avatar
jpbl committed
633
{
634
    int status;
635
    bool flag = true;
636 637
    AccountMap::iterator iter;

638
    _debugInit ("Initiate VoIP Links Registration");
639 640
    iter = _accountMap.begin();

641
    /* Loop on the account map previously loaded */
642 643 644

    while (iter != _accountMap.end()) {
        if (iter->second) {
645 646
            iter->second->loadConfig();
            /* If the account is set as enabled, try to register */
647 648 649 650 651 652

            if (iter->second->isEnabled()) {
                status = iter->second->registerVoIPLink();

                if (status != SUCCESS) {
                    flag = false;
653 654
                }
            }
655
        }
656

657
        iter++;
Emmanuel Milou's avatar
Emmanuel Milou committed
658
    }
659

660
    // calls the client notification here in case of errors at startup...
661 662 663 664
    if (_audiodriver -> getErrorMessage() != -1)
        notifyErrClient (_audiodriver -> getErrorMessage());

    ASSERT (flag, true);
665

666
    return SUCCESS;
jpbl's avatar
jpbl committed
667 668
}

yanmorin's avatar
yanmorin committed
669
//THREAD=Main
670 671
bool
ManagerImpl::sendDtmf (const CallID& id, char code)
jpbl's avatar
jpbl committed
672
{
673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702
    AccountID accountid = getAccountFromCall (id);

    if (accountid == AccountNULL) {
        //_debug("Send DTMF: call doesn't exists\n");
        playDtmf (code, false);
        return false;
    }

    int sendType = getConfigInt (SIGNALISATION, SEND_DTMF_AS);

    bool returnValue = false;

    switch (sendType) {

        case 0: // SIP INFO
            playDtmf (code , true);
            returnValue = getAccountLink (accountid)->carryingDTMFdigits (id, code);
            break;

        case 1: // Audio way
            break;

        case 2: // rfc 2833
            break;

        default: // unknown - error config?
            break;
    }

    return returnValue;
jpbl's avatar
jpbl committed
703 704
}

yanmorin's avatar
yanmorin committed
705
//THREAD=Main | VoIPLink
706 707
bool
ManagerImpl::playDtmf (char code, bool isTalking)
jpbl's avatar
jpbl committed
708
{
709 710 711 712
    int hasToPlayTone, pulselen, layer, size;
    bool ret = false;
    AudioLayer *audiolayer;
    SFLDataFormat *buf;
713

714 715 716
    stopTone (false);

    hasToPlayTone = getConfigInt (SIGNALISATION, PLAY_DTMF);
717 718

    if (!hasToPlayTone)
719
        return false;
jpbl's avatar
jpbl committed
720

721
    // length in milliseconds
722 723
    pulselen = getConfigInt (SIGNALISATION, PULSE_LENGTH);

724 725
    if (!pulselen)
        return false;
jpbl's avatar
jpbl committed
726

727 728 729
    // numbers of int = length in milliseconds / 1000 (number of seconds)
    //                = number of seconds * SAMPLING_RATE by SECONDS
    audiolayer = getAudioDriver();
730

731
    layer = audiolayer->getLayerType();
jpbl's avatar
jpbl committed
732

733 734 735
    // fast return, no sound, so no dtmf
    if (audiolayer==0 || _dtmfKey == 0)
        return false;
736

737
    // number of data sampling in one pulselen depends on samplerate
738
    // size (n sampling) = time_ms * sampling/s
739 740
    //                     ---------------------
    //                            ms/s
741
    size = (int) (pulselen * ( (float) audiolayer->getSampleRate() /1000));
742 743 744 745 746 747

    // this buffer is for mono
    // TODO <-- this should be global and hide if same size
    buf = new SFLDataFormat[size];

    // Handle dtmf
748
    _dtmfKey->startTone (code);
749 750

    // copy the sound
751
    if (_dtmfKey->generateDTMF (buf, size)) {
752
        // Put buffer to urgentRingBuffer
753 754
        // put the size in bytes...
        // so size * 1 channel (mono) * sizeof (bytes for the data)
755
        audiolayer->startStream();
756
        audiolayer->putUrgent (buf, size * sizeof (SFLDataFormat));
757
    }
758

759
    ret = true;
760

761
    // TODO Cache the DTMF
Emmanuel Milou's avatar
Emmanuel Milou committed
762

763 764
    delete[] buf;
    buf = 0;
765

766
    return ret;
jpbl's avatar
jpbl committed
767 768
}

769
// Multi-thread
jpbl's avatar
jpbl committed
770
bool
771 772 773
ManagerImpl::incomingCallWaiting()
{
    return (_nbIncomingWaitingCall > 0) ? true : false;
jpbl's avatar
jpbl committed
774 775 776
}

void
777 778 779 780 781
ManagerImpl::addWaitingCall (const CallID& id)
{
    ost::MutexLock m (_waitingCallMutex);
    _waitingCall.insert (id);
    _nbIncomingWaitingCall++;
jpbl's avatar
jpbl committed
782 783 784
}

void
785 786 787 788 789 790 791 792
ManagerImpl::removeWaitingCall (const CallID& id)
{
    ost::MutexLock m (_waitingCallMutex);
    // should return more than 1 if it erase a call

    if (_waitingCall.erase (id)) {
        _nbIncomingWaitingCall--;
    }
jpbl's avatar
jpbl committed
793 794 795
}

bool
796 797 798 799 800 801 802 803 804
ManagerImpl::isWaitingCall (const CallID& id)
{
    CallIDSet::iterator iter = _waitingCall.find (id);

    if (iter != _waitingCall.end()) {
        return false;
    }

    return true;
jpbl's avatar
jpbl committed
805 806
}

yanmorin's avatar
yanmorin committed
807
///////////////////////////////////////////////////////////////////////////////
808
// Management of event peer IP-phone
yanmorin's avatar
yanmorin committed
809
////////////////////////////////////////////////////////////////////////////////
810 811
// SipEvent Thread
bool
812
ManagerImpl::incomingCall (Call* call, const AccountID& accountId)
jpbl's avatar
jpbl committed
813
{
814 815
    PulseLayer *pulselayer;
    std::string from, number;
816

817
    stopTone (true);
818

819
    _debug ("Incoming call %s for account %s\n", call->getCallId().data(), accountId.c_str());
820

821
    associateCallToAccount (call->getCallId(), accountId);
jpbl's avatar
jpbl committed
822

823 824 825
    if (accountId==AccountNULL)
        associateConfigToCall (call->getCallId(), Call::IPtoIP);

826
    _debug ("ManagerImpl::incomingCall :: hasCurrentCall() %i \n",hasCurrentCall());
827

828 829
    if (!hasCurrentCall()) {
        call->setConnectionState (Call::Ringing);
830
        ringtone();
831
        switchCall (call->getCallId());
832

833
    }
834

835
    /*
836
    else {
837 838
        addWaitingCall(call->getCallId());
    }
839 840
    */

841
    addWaitingCall (call->getCallId());
842 843

    from = call->getPeerName();
844

845 846 847
    number = call->getPeerNumber();

    if (from != "" && number != "") {
848 849 850 851 852 853 854
        from.append (" <");
        from.append (number);
        from.append (">");
    } else if (from.empty()) {
        from.append ("<");
        from.append (number);
        from.append (">");
855
    }
856 857 858 859 860 861 862 863 864

    /*
    CallIDSet::iterator iter = _waitingCall.begin();
    while (iter != _waitingCall.end()) {
        CallID ident = *iter;
        _debug("ManagerImpl::incomingCall :: CALL iteration: %s \n",ident.c_str());
        ++iter;
    }
    */
865

866
    /* Broadcast a signal over DBus */
867
    if (_dbus) _dbus->getCallManager()->incomingCall (accountId, call->getCallId(), from);
868

869
    //if (_dbus) _dbus->getCallManager()->callStateChanged(call->getCallId(), "INCOMING");
870

871
    // Reduce volume of the other pulseaudio-connected audio applications
872
    if (_audiodriver->getLayerType() == PULSEAUDIO && getConfigInt (PREFERENCES , CONFIG_PA_VOLUME_CTRL)) {
873
        pulselayer = dynamic_cast<PulseLayer *> (getAudioDriver());
874 875

        if (pulselayer)  pulselayer->reducePulseAppsVolume();
876
    }
877

878
    return true;
jpbl's avatar
jpbl committed
879 880
}

yanmorin's avatar
yanmorin committed
881 882
//THREAD=VoIP
void
883 884 885 886 887
ManagerImpl::incomingMessage (const AccountID& accountId, const std::string& message)
{
    if (_dbus) {
        _dbus->getCallManager()->incomingMessage (accountId, message);
    }
jpbl's avatar
jpbl committed
888 889
}

yanmorin's avatar
yanmorin committed
890
//THREAD=VoIP CALL=Outgoing
891 892
void
ManagerImpl::peerAnsweredCall (const CallID& id)
jpbl's avatar
jpbl committed
893
{
894 895
    if (isCurrentCall (id)) {
        stopTone (false);
896
    }
897

898
    if (_dbus) _dbus->getCallManager()->callStateChanged (id, "CURRENT");
899

900 901 902 903
    std::string codecName = getCurrentCodecName (id);

    // _debug("ManagerImpl::hangupCall(): broadcast codec name %s \n",codecName.c_str());
    if (_dbus) _dbus->getCallManager()->currentSelectedCodec (id,codecName.c_str());
jpbl's avatar
jpbl committed
904 905
}

yanmorin's avatar
yanmorin committed
906
//THREAD=VoIP Call=Outgoing
907 908
void
ManagerImpl::peerRingingCall (const CallID& id)
jpbl's avatar
jpbl committed
909
{
910 911 912 913 914
    if (isCurrentCall (id)) {
        ringback();
    }

    if (_dbus) _dbus->getCallManager()->callStateChanged (id, "RINGING");
jpbl's avatar
jpbl committed
915 916
}

yanmorin's avatar
yanmorin committed
917
//THREAD=VoIP Call=Outgoing/Ingoing
918 919
void
ManagerImpl::peerHungupCall (const CallID& id)
jpbl's avatar
jpbl committed
920
{
921 922
    PulseLayer *pulselayer;
    AccountID accountid;
923
    bool returnValue;
924

925
    /* Direct IP to IP call */
926

927 928 929 930
    if (getConfigFromCall (id) == Call::IPtoIP) {
        SIPVoIPLink::instance (AccountNULL)->hangup (id);
    }

931 932 933
    else {
        accountid = getAccountFromCall (id);

934
        if (accountid == AccountNULL) {
935
            _debug ("peerHungupCall: Call doesn't exists\n");
936 937
            return;
        }
938 939

        returnValue = getAccountLink (accountid)->peerHungup (id);
940
    }
941

942
    /* Broadcast a signal over DBus */
943
    if (_dbus) _dbus->getCallManager()->callStateChanged (id, "HUNGUP");
944

945 946 947
    if (isCurrentCall (id)) {
        stopTone (true);
        switchCall ("");
948 949
    }

950
    removeWaitingCall (id);
951

952 953 954
    removeCallAccount (id);

    if (_audiodriver->getLayerType() == PULSEAUDIO && getConfigInt (PREFERENCES , CONFIG_PA_VOLUME_CTRL)) {
955
        pulselayer = dynamic_cast<PulseLayer *> (getAudioDriver());
956 957

        if (pulselayer)  pulselayer->restorePulseAppsVolume();
958
    }
jpbl's avatar
jpbl committed
959 960
}

yanmorin's avatar
yanmorin committed
961
//THREAD=VoIP
jpbl's avatar
jpbl committed
962
void
963 964 965 966 967 968 969 970 971 972
ManagerImpl::callBusy (const CallID& id)
{
    _debug ("Call busy\n");

    if (_dbus) _dbus->getCallManager()->callStateChanged (id, "BUSY");

    if (isCurrentCall (id)) {
        playATone (Tone::TONE_BUSY);
        switchCall ("");
    }
973

974 975 976
    removeCallAccount (id);

    removeWaitingCall (id);
jpbl's avatar
jpbl committed
977 978
}

yanmorin's avatar
yanmorin committed
979
//THREAD=VoIP
980 981
void
ManagerImpl::callFailure (const CallID& id)
yanmorin's avatar
yanmorin committed
982
{
983 984 985 986 987 988 989 990 991 992 993 994
    if (_dbus) _dbus->getCallManager()->callStateChanged (id, "FAILURE");

    _debug ("CALL ID = %s\n" , id.c_str());

    if (isCurrentCall (id)) {
        playATone (Tone::TONE_BUSY);
        switchCall ("");
    }

    removeCallAccount (id);

    removeWaitingCall (id);
995

jpbl's avatar
jpbl committed
996 997
}

yanmorin's avatar
yanmorin committed
998
//THREAD=VoIP
999 1000
void
ManagerImpl::startVoiceMessageNotification (const AccountID& accountId, int nb_msg)
jpbl's avatar
jpbl committed
1001
{
1002
    if (_dbus) _dbus->getCallManager()->voiceMailNotify (accountId, nb_msg) ;
jpbl's avatar
jpbl committed
1003 1004
}

1005
void ManagerImpl::connectionStatusNotification()
1006
{
1007 1008
    if (_dbus)
        _dbus->getConfigurationManager()->accountsChanged();
Emmanuel Milou's avatar
Emmanuel Milou committed
1009 1010
}

jpbl's avatar
jpbl committed
1011 1012 1013
/**
 * Multi Thread
 */
1014
bool ManagerImpl::playATone (Tone::TONEID toneId)
1015 1016 1017 1018 1019
{
    int hasToPlayTone;
    AudioLoop *audioloop;
    AudioLayer *audiolayer;
    unsigned int nbSamples;
1020

1021 1022
    hasToPlayTone = getConfigInt (SIGNALISATION, PLAY_TONES);

1023
    if (!hasToPlayTone)
1024
        return false;
1025

1026
    audiolayer = getAudioDriver();
1027

1028 1029
    if (_telephoneTone != 0) {
        _toneMutex.enterMutex();
1030
        _telephoneTone->setCurrentTone (toneId);
1031 1032 1033 1034 1035
        _toneMutex.leaveMutex();

        audioloop = getTelephoneTone();
        nbSamples = audioloop->getSize();
        SFLDataFormat buf[nbSamples];
1036