managerimpl.cpp 101 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
 *  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.
 */

24
25
26
27
28
#include "managerimpl.h"

#include "account.h"
#include "dbus/callmanager.h"
#include "user_cfg.h"
29
#include "global.h"
30
31
32
33
34
35
36
37
38
39
40
#include "sip/sipaccount.h"
#include "audio/audiolayer.h"
#include "audio/alsa/alsalayer.h"
#include "audio/pulseaudio/pulselayer.h"
#include "audio/sound/tonelist.h"
#include "history/historymanager.h"
#include "accountcreator.h" // create new account
#include "sip/sipvoiplink.h"
#include "manager.h"
#include "dbus/configurationmanager.h"

jpbl's avatar
jpbl committed
41
42
43
44
45
#include <errno.h>
#include <time.h>
#include <cstdlib>
#include <iostream>
#include <fstream>
46
#include <sstream>
jpbl's avatar
jpbl committed
47
48
49
#include <sys/types.h> // mkdir(2)
#include <sys/stat.h>	// mkdir(2)

50
//#include <cc++/file.h>
jpbl's avatar
jpbl committed
51
52


53

jpbl's avatar
jpbl committed
54
55
56
57
58
59

#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)))

60
61
#define MD5_APPEND(pms,buf,len) pj_md5_update(pms, (const pj_uint8_t*)buf, len)

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

95
    // initialize random generator for call id
96
    srand (time (NULL));
yanmorin's avatar
   
yanmorin committed
97

98
    _cleaner = new NumberCleaner ();
99
    _history = new HistoryManager ();
100

yanmorin's avatar
   
yanmorin committed
101
#ifdef TEST
102
103
104
105
    testAccountMap();
    loadAccountMap();
    testCallAccountMap();
    unloadAccountMap();
yanmorin's avatar
   
yanmorin committed
106
107
#endif

108
109
    // should be call before initConfigFile
    // loadAccountMap();, called in init() now.
jpbl's avatar
jpbl committed
110
111
112
}

// never call if we use only the singleton...
113
ManagerImpl::~ManagerImpl (void)
jpbl's avatar
jpbl committed
114
{
115
    // terminate();
116
117
118
    delete _cleaner;
    _cleaner=0;
    _debug ("%s stop correctly.\n", PROGNAME);
jpbl's avatar
jpbl committed
119
120
}

121
void
122
ManagerImpl::init()
jpbl's avatar
jpbl committed
123
{
124
125
    // Load accounts, init map
    loadAccountMap();
126

127
    initVolume();
128

129
    if (_exist == 0) {
130
        _debug ("Cannot create config file in your home directory\n");
131
    }
132

133
    initAudioDriver();
134

135
    selectAudioDriver();
jpbl's avatar
jpbl committed
136

137
138
    // Initialize the list of supported audio codecs
    initAudioCodec();
139

140
    AudioLayer *audiolayer = getAudioDriver();
141

142
    if (audiolayer != 0) {
143
        unsigned int sampleRate = audiolayer->getSampleRate();
jpbl's avatar
jpbl committed
144

145
146
147
        _debugInit ("Load Telephone Tone");
        std::string country = getConfigString (PREFERENCES, ZONE_TONE);
        _telephoneTone = new TelephoneTone (country, sampleRate);
jpbl's avatar
jpbl committed
148

149
150
        _debugInit ("Loading DTMF key");
        _dtmfKey = new DTMF (sampleRate);
151
    }
152
153

    if (audiolayer == 0)
154
        audiolayer->stopStream();
155
156
157


    // Load the history
158
    _history->load_history (getConfigInt (PREFERENCES, CONFIG_HISTORY_LIMIT));
jpbl's avatar
jpbl committed
159
160
161
162
}

void ManagerImpl::terminate()
{
163
    _debug ("ManagerImpl::terminate \n");
164
    saveConfig();
jpbl's avatar
jpbl committed
165

166
    unloadAccountMap();
167

168
    _debug ("Unload DTMF Key \n");
169
    delete _dtmfKey;
jpbl's avatar
jpbl committed
170

171
172
173
    _debug ("Unload Audio Driver \n");
    delete _audiodriver;
    _audiodriver = NULL;
jpbl's avatar
jpbl committed
174

175
176
177
    _debug ("Unload Telephone Tone \n");
    delete _telephoneTone;
    _telephoneTone = NULL;
178

179
    _debug ("Unload Audio Codecs \n");
180
    _codecDescriptorMap.deleteHandlePointer();
181

jpbl's avatar
jpbl committed
182
183
}

yanmorin's avatar
   
yanmorin committed
184
bool
185
186
187
ManagerImpl::isCurrentCall (const CallID& callId)
{
    return (_currentCallId2 == callId ? true : false);
jpbl's avatar
jpbl committed
188
189
}

yanmorin's avatar
   
yanmorin committed
190
bool
191
192
193
194
195
196
197
198
199
ManagerImpl::hasCurrentCall()
{
    _debug ("Current call ID = %s\n", _currentCallId2.c_str());

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

    return false;
jpbl's avatar
jpbl committed
200
201
}

202
const CallID&
203
204
205
ManagerImpl::getCurrentCallId()
{
    return _currentCallId2;
jpbl's avatar
jpbl committed
206
207
208
}

void
209
210
211
212
ManagerImpl::switchCall (const CallID& id)
{
    ost::MutexLock m (_currentCallMutex);
    _currentCallId2 = id;
jpbl's avatar
jpbl committed
213
214
215
216
217
218
}


///////////////////////////////////////////////////////////////////////////////
// Management of events' IP-phone user
///////////////////////////////////////////////////////////////////////////////
219
/* Main Thread */
Emmanuel Milou's avatar
Emmanuel Milou committed
220

221
222
bool
ManagerImpl::outgoingCall (const std::string& accountid, const CallID& id, const std::string& to)
yanmorin's avatar
   
yanmorin committed
223
{
224
    std::string pattern, to_cleaned;
Emmanuel Milou's avatar
Emmanuel Milou committed
225
226
    Call::CallConfiguration callConfig;
    SIPVoIPLink *siplink;
227

228
    _debug ("ManagerImpl::outgoingCall() method \n");
229

230
231
    if (getConfigString (HOOKS, PHONE_NUMBER_HOOK_ENABLED) ==  "1")
        _cleaner->set_phone_number_prefix (getConfigString (HOOKS, PHONE_NUMBER_HOOK_ADD_PREFIX));
232
233
    else
        _cleaner->set_phone_number_prefix ("");
234

235
    to_cleaned = _cleaner->clean (to);
Emmanuel Milou's avatar
Emmanuel Milou committed
236
237

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

Emmanuel Milou's avatar
Emmanuel Milou committed
240
241
242
    if (callConfig == Call::IPtoIP) {
        _debug ("Start IP to IP call\n");
        /* We need to retrieve the sip voiplink instance */
243
244
        siplink = SIPVoIPLink::instance ("");

245
        if (siplink->new_ip_to_ip_call (id, to_cleaned)) {
Emmanuel Milou's avatar
Emmanuel Milou committed
246
247
            switchCall (id);
            return true;
248
        } else {
Emmanuel Milou's avatar
Emmanuel Milou committed
249
250
            callFailure (id);
        }
251

Emmanuel Milou's avatar
Emmanuel Milou committed
252
        return false;
253
    }
254

255
256
    if (!accountExists (accountid)) {
        _debug ("! Manager Error: Outgoing Call: account doesn't exist\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
257
258
        return false;
    }
259

260
261
    if (getAccountFromCall (id) != AccountNULL) {
        _debug ("! Manager Error: Outgoing Call: call id already exists\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
262
263
        return false;
    }
264

Emmanuel Milou's avatar
Emmanuel Milou committed
265
    if (hasCurrentCall()) {
266
267
        _debug ("* Manager Info: there is currently a call, try to hold it\n");
        onHoldCall (getCurrentCallId());
Emmanuel Milou's avatar
Emmanuel Milou committed
268
    }
269

270
271
272
273
274
275
    _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);
Emmanuel Milou's avatar
Emmanuel Milou committed
276
277
        return true;
    } else {
278
279
        callFailure (id);
        _debug ("! Manager Error: An error occur, the call was not created\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
280
    }
281

Emmanuel Milou's avatar
Emmanuel Milou committed
282
    return false;
jpbl's avatar
jpbl committed
283
284
}

yanmorin's avatar
   
yanmorin committed
285
//THREAD=Main : for outgoing Call
286
287
bool
ManagerImpl::answerCall (const CallID& id)
jpbl's avatar
jpbl committed
288
{
289
    stopTone (true);
290

291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
    AccountID currentAccountId;
    currentAccountId = getAccountFromCall (id);
    if(currentAccountId == AccountNULL) {
        _debug("ManagerImpl::answerCall : AccountId is null\n");
    }
    
    Call* currentCall = NULL;
    currentCall = getAccountLink (currentAccountId)->getCall (id);
    if (currentCall == NULL) {
        _debug("ManagerImpl::answerCall : currentCall is null\n");
    }
    
    Call* lastCall = NULL;
    if (!getCurrentCallId().empty()) {
        lastCall = getAccountLink (currentAccountId)->getCall (getCurrentCallId());
        if (lastCall == NULL) {
            _debug("ManagerImpl::answerCall : lastCall is null\n");
        }
309
    }
310

311
312
    _debug ("ManagerImpl::answerCall :: current call->getState %i \n", currentCall->getState());
    _debug ("Try to answer call: %s\n", id.data());
Yun Liu's avatar
Yun Liu committed
313

314
315
316
317
318
    if (lastCall != NULL) {
        if (lastCall->getState() == Call::Active) {
            _debug ("* Manager Info: there is currently a call, try to hold it\n");
            onHoldCall (getCurrentCallId());
        }
319
320
    }

321
    if (!getAccountLink (currentAccountId)->answer (id)) {
322
323
324
325
        // error when receiving...
        removeCallAccount (id);
        return false;
    }
Alexandre Savard's avatar
Alexandre Savard committed
326

327
328
    // if it was waiting, it's waiting no more
    if (_dbus) _dbus->getCallManager()->callStateChanged (id, "CURRENT");
329
330
331
332
        
    std::string codecName = Manager::instance().getCurrentCodecName (id);
    if (_dbus) _dbus->getCallManager()->currentSelectedCodec (id,codecName.c_str());
        
333
    removeWaitingCall (id);
334

335
336
337
    switchCall (id);

    return true;
jpbl's avatar
jpbl committed
338
339
}

yanmorin's avatar
   
yanmorin committed
340
//THREAD=Main
341
342
bool
ManagerImpl::hangupCall (const CallID& id)
jpbl's avatar
jpbl committed
343
{
344
    _debug ("ManagerImpl::hangupCall()\n");
345
346
347
    PulseLayer *pulselayer;
    AccountID accountid;
    bool returnValue;
348
    AudioLayer *audiolayer;
Emmanuel Milou's avatar
Emmanuel Milou committed
349

350
    stopTone (false);
yanmorin's avatar
   
yanmorin committed
351

352
    /* Broadcast a signal over DBus */
353

354
355
356
357
    if (_dbus) _dbus->getCallManager()->callStateChanged (id, "HUNGUP");

    _debug ("Stop audio stream\n");

358
    audiolayer = getAudioDriver();
359
360
361

    int nbCalls = getCallList().size();

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

364
365
    // stop stream
    if (! (nbCalls > 1))
366
        audiolayer->stopStream();
367

Emmanuel Milou's avatar
Emmanuel Milou committed
368
369
    /* Direct IP to IP call */
    if (getConfigFromCall (id) == Call::IPtoIP) {
370
        returnValue = SIPVoIPLink::instance (AccountNULL)->hangup (id);
371
    }
372

Emmanuel Milou's avatar
Emmanuel Milou committed
373
    /* Classic call, attached to an account */
374
    else {
375
376
        accountid = getAccountFromCall (id);

Emmanuel Milou's avatar
Emmanuel Milou committed
377
        if (accountid == AccountNULL) {
378
            _debug ("! Manager Hangup Call: Call doesn't exists\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
379
380
            return false;
        }
381
382
383
384

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

        removeCallAccount (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
385
    }
386

387
    switchCall ("");
388

389
    if (_audiodriver->getLayerType() == PULSEAUDIO && getConfigInt (PREFERENCES , CONFIG_PA_VOLUME_CTRL)) {
390
        pulselayer = dynamic_cast<PulseLayer *> (getAudioDriver());
391
392

        if (pulselayer)  pulselayer->restorePulseAppsVolume();
393
    }
394

395

396

397
    return returnValue;
jpbl's avatar
jpbl committed
398
399
}

yanmorin's avatar
   
yanmorin committed
400
//THREAD=Main
401
bool
yanmorin's avatar
   
yanmorin committed
402
ManagerImpl::cancelCall (const CallID& id)
jpbl's avatar
jpbl committed
403
{
Emmanuel Milou's avatar
Emmanuel Milou committed
404
405
    AccountID accountid;
    bool returnValue;
yanmorin's avatar
   
yanmorin committed
406

407
    stopTone (true);
408

Emmanuel Milou's avatar
Emmanuel Milou committed
409
    /* Direct IP to IP call */
410

Emmanuel Milou's avatar
Emmanuel Milou committed
411
    if (getConfigFromCall (id) == Call::IPtoIP) {
412
        returnValue = SIPVoIPLink::instance (AccountNULL)->cancel (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
413
414
415
    }

    /* Classic call, attached to an account */
416
    else {
417
418
        accountid = getAccountFromCall (id);

Emmanuel Milou's avatar
Emmanuel Milou committed
419
        if (accountid == AccountNULL) {
420
            _debug ("! Manager Cancel Call: Call doesn't exists\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
421
422
            return false;
        }
423
424
425
426

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

        removeCallAccount (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
427
    }
428

Emmanuel Milou's avatar
Emmanuel Milou committed
429
    // it could be a waiting call?
430
431
432
    removeWaitingCall (id);

    switchCall ("");
Emmanuel Milou's avatar
Emmanuel Milou committed
433
434

    return returnValue;
jpbl's avatar
jpbl committed
435
436
}

yanmorin's avatar
   
yanmorin committed
437
//THREAD=Main
438
439
bool
ManagerImpl::onHoldCall (const CallID& id)
jpbl's avatar
jpbl committed
440
{
Emmanuel Milou's avatar
Emmanuel Milou committed
441
442
    AccountID accountid;
    bool returnValue;
443
    CallID call_id;
yanmorin's avatar
   
yanmorin committed
444

445
    stopTone (true);
446

447
448
    call_id = id;

Emmanuel Milou's avatar
Emmanuel Milou committed
449
    /* Direct IP to IP call */
450

Emmanuel Milou's avatar
Emmanuel Milou committed
451
    if (getConfigFromCall (id) == Call::IPtoIP) {
452
        returnValue = SIPVoIPLink::instance (AccountNULL)-> onhold (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
453
    }
454

Emmanuel Milou's avatar
Emmanuel Milou committed
455
    /* Classic call, attached to an account */
456
    else {
457
458
        accountid = getAccountFromCall (id);

Emmanuel Milou's avatar
Emmanuel Milou committed
459
        if (accountid == AccountNULL) {
460
            _debug ("Manager On Hold Call: Account ID %s or callid %s doesn't exists\n", accountid.c_str(), id.c_str());
Emmanuel Milou's avatar
Emmanuel Milou committed
461
462
            return false;
        }
463
464

        returnValue = getAccountLink (accountid)->onhold (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
465
    }
466

467
468
469
    removeWaitingCall (id);

    switchCall ("");
470

471
    if (_dbus) _dbus->getCallManager()->callStateChanged (call_id, "HOLD");
472

Emmanuel Milou's avatar
Emmanuel Milou committed
473
    return returnValue;
yanmorin's avatar
   
yanmorin committed
474
475
476
}

//THREAD=Main
477
478
bool
ManagerImpl::offHoldCall (const CallID& id)
yanmorin's avatar
   
yanmorin committed
479
{
480

Emmanuel Milou's avatar
Emmanuel Milou committed
481
482
483
    AccountID accountid;
    bool returnValue, rec;
    std::string codecName;
484
    CallID call_id;
485

486
    stopTone (false);
487

488
    call_id = id;
Emmanuel Milou's avatar
Emmanuel Milou committed
489
    //Place current call on hold if it isn't
490
491

    if (hasCurrentCall()) {
492
        _debug ("Put the current call (ID=%s) on hold\n", getCurrentCallId().c_str());
493
        onHoldCall (getCurrentCallId());
Emmanuel Milou's avatar
Emmanuel Milou committed
494
    }
495

Emmanuel Milou's avatar
Emmanuel Milou committed
496
497
498
    /* Direct IP to IP call */
    if (getConfigFromCall (id) == Call::IPtoIP) {
        rec = SIPVoIPLink::instance (AccountNULL)-> isRecording (id);
499
        returnValue = SIPVoIPLink::instance (AccountNULL)-> offhold (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
500
    }
alexandresavard's avatar
alexandresavard committed
501

Emmanuel Milou's avatar
Emmanuel Milou committed
502
    /* Classic call, attached to an account */
503
    else {
504
505
        accountid = getAccountFromCall (id);

Emmanuel Milou's avatar
Emmanuel Milou committed
506
        if (accountid == AccountNULL) {
507
            _debug ("Manager OffHold Call: Call doesn't exists\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
508
509
            return false;
        }
510
511
512
513
514

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

        rec = getAccountLink (accountid)->isRecording (id);
        returnValue = getAccountLink (accountid)->offhold (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
515
    }
alexandresavard's avatar
alexandresavard committed
516

517

518
    if (_dbus) {
Emmanuel Milou's avatar
Emmanuel Milou committed
519
        if (rec)
520
            _dbus->getCallManager()->callStateChanged (call_id, "UNHOLD_RECORD");
521
        else
522
            _dbus->getCallManager()->callStateChanged (call_id, "UNHOLD_CURRENT");
523

Emmanuel Milou's avatar
Emmanuel Milou committed
524
    }
525

526
    switchCall (id);
527

528
    codecName = getCurrentCodecName (id);
529
    // _debug("ManagerImpl::hangupCall(): broadcast codec name %s \n",codecName.c_str());
530
531

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

Emmanuel Milou's avatar
Emmanuel Milou committed
533
    return returnValue;
jpbl's avatar
jpbl committed
534
535
}

yanmorin's avatar
   
yanmorin committed
536
//THREAD=Main
537
538
bool
ManagerImpl::transferCall (const CallID& id, const std::string& to)
jpbl's avatar
jpbl committed
539
{
Emmanuel Milou's avatar
Emmanuel Milou committed
540
541
    AccountID accountid;
    bool returnValue;
542

543
    stopTone (true);
544

Emmanuel Milou's avatar
Emmanuel Milou committed
545
    /* Direct IP to IP call */
546

Emmanuel Milou's avatar
Emmanuel Milou committed
547
    if (getConfigFromCall (id) == Call::IPtoIP) {
548
        returnValue = SIPVoIPLink::instance (AccountNULL)-> transfer (id, to);
Emmanuel Milou's avatar
Emmanuel Milou committed
549
550
551
    }

    /* Classic call, attached to an account */
552
    else {
553
554
        accountid = getAccountFromCall (id);

Emmanuel Milou's avatar
Emmanuel Milou committed
555
        if (accountid == AccountNULL) {
556
            _debug ("! Manager Transfer Call: Call doesn't exists\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
557
558
            return false;
        }
559
560
561
562

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

        removeCallAccount (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
563
    }
564

565
566
567
568
569
    removeWaitingCall (id);

    switchCall ("");

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

Emmanuel Milou's avatar
Emmanuel Milou committed
571
    return returnValue;
jpbl's avatar
jpbl committed
572
573
}

574
575
void ManagerImpl::transferFailed()
{
576
    if (_dbus) _dbus->getCallManager()->transferFailed();
577
578
579
580
}

void ManagerImpl::transferSucceded()
{
581
    if (_dbus) _dbus->getCallManager()->transferSucceded();
582
583
584
585

}


yanmorin's avatar
   
yanmorin committed
586
//THREAD=Main : Call:Incoming
587
bool
yanmorin's avatar
   
yanmorin committed
588
ManagerImpl::refuseCall (const CallID& id)
jpbl's avatar
jpbl committed
589
{
Emmanuel Milou's avatar
Emmanuel Milou committed
590
591
    AccountID accountid;
    bool returnValue;
592

593
594
595
    stopTone (true);

    /* Direct IP to IP call */
Emmanuel Milou's avatar
Emmanuel Milou committed
596
597

    if (getConfigFromCall (id) == Call::IPtoIP) {
598
        returnValue = SIPVoIPLink::instance (AccountNULL)-> refuse (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
599
600
601
    }

    /* Classic call, attached to an account */
602
    else {
603
604
        accountid = getAccountFromCall (id);

Emmanuel Milou's avatar
Emmanuel Milou committed
605
        if (accountid == AccountNULL) {
606
            _debug ("! Manager OffHold Call: Call doesn't exists\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
607
608
            return false;
        }
609
610
611
612

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

        removeCallAccount (id);
613
614
    }

Emmanuel Milou's avatar
Emmanuel Milou committed
615
616
617
    // if the call was outgoing or established, we didn't refuse it
    // so the method did nothing
    if (returnValue) {
618
619
620
621
622
        removeWaitingCall (id);

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

        switchCall ("");
Emmanuel Milou's avatar
Emmanuel Milou committed
623
    }
624

Emmanuel Milou's avatar
Emmanuel Milou committed
625
    return returnValue;
jpbl's avatar
jpbl committed
626
627
}

yanmorin's avatar
   
yanmorin committed
628
//THREAD=Main
629
bool
jpbl's avatar
jpbl committed
630
631
ManagerImpl::saveConfig (void)
{
632
    _debug ("Saving Configuration to XDG directory %s ... \n", _path.c_str());
633
634
    setConfig (AUDIO, VOLUME_SPKR, getSpkrVolume());
    setConfig (AUDIO, VOLUME_MICRO, getMicVolume());
jpbl's avatar
jpbl committed
635

636
637
    _setupLoaded = _config.saveConfigTree (_path.data());
    return _setupLoaded;
jpbl's avatar
jpbl committed
638
639
}

yanmorin's avatar
   
yanmorin committed
640
//THREAD=Main
641
int
642
ManagerImpl::initRegisterAccounts()
jpbl's avatar
jpbl committed
643
{
644
    int status;
645
    bool flag = true;
646
647
    AccountMap::iterator iter;

648
    _debugInit ("Initiate VoIP Links Registration");
649
650
    iter = _accountMap.begin();

651
    /* Loop on the account map previously loaded */
652
653
654

    while (iter != _accountMap.end()) {
        if (iter->second) {
655
656
            iter->second->loadConfig();
            /* If the account is set as enabled, try to register */
657
658
659
660
661
662

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

                if (status != SUCCESS) {
                    flag = false;
663
664
                }
            }
665
        }
666

667
        iter++;
Emmanuel Milou's avatar
Emmanuel Milou committed
668
    }
669

670
    // calls the client notification here in case of errors at startup...
671
672
673
674
    if (_audiodriver -> getErrorMessage() != -1)
        notifyErrClient (_audiodriver -> getErrorMessage());

    ASSERT (flag, true);
675

676
    return SUCCESS;
jpbl's avatar
jpbl committed
677
678
}

yanmorin's avatar
   
yanmorin committed
679
//THREAD=Main
680
681
bool
ManagerImpl::sendDtmf (const CallID& id, char code)
jpbl's avatar
jpbl committed
682
{
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
    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
713
714
}

yanmorin's avatar
   
yanmorin committed
715
//THREAD=Main | VoIPLink
716
717
bool
ManagerImpl::playDtmf (char code, bool isTalking)
jpbl's avatar
jpbl committed
718
{
pierre-luc's avatar
pierre-luc committed
719
    int pulselen, layer, size;
720
721
722
    bool ret = false;
    AudioLayer *audiolayer;
    SFLDataFormat *buf;
723

724
725
    stopTone (false);

pierre-luc's avatar
pierre-luc committed
726
    bool hasToPlayTone = getConfigBool (SIGNALISATION, PLAY_DTMF);
727
728

    if (!hasToPlayTone)
729
        return false;
jpbl's avatar
jpbl committed
730

731
    // length in milliseconds
732
733
    pulselen = getConfigInt (SIGNALISATION, PULSE_LENGTH);

734
735
    if (!pulselen)
        return false;
jpbl's avatar
jpbl committed
736

737
738
739
    // numbers of int = length in milliseconds / 1000 (number of seconds)
    //                = number of seconds * SAMPLING_RATE by SECONDS
    audiolayer = getAudioDriver();
740

741
    layer = audiolayer->getLayerType();
jpbl's avatar
jpbl committed
742

743
744
745
    // fast return, no sound, so no dtmf
    if (audiolayer==0 || _dtmfKey == 0)
        return false;
746

747
    // number of data sampling in one pulselen depends on samplerate
748
    // size (n sampling) = time_ms * sampling/s
749
750
    //                     ---------------------
    //                            ms/s
751
    size = (int) (pulselen * ( (float) audiolayer->getSampleRate() /1000));
752
753
754
755
756
757

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

    // Handle dtmf
758
    _dtmfKey->startTone (code);
759
760

    // copy the sound
761
    if (_dtmfKey->generateDTMF (buf, size)) {
762
        // Put buffer to urgentRingBuffer
763
764
        // put the size in bytes...
        // so size * 1 channel (mono) * sizeof (bytes for the data)
765
        audiolayer->startStream();
766
        audiolayer->putUrgent (buf, size * sizeof (SFLDataFormat));
767
    }
768

769
    ret = true;
770

771
    // TODO Cache the DTMF
Emmanuel Milou's avatar
Emmanuel Milou committed
772

773
774
    delete[] buf;
    buf = 0;
775

776
    return ret;
jpbl's avatar
jpbl committed
777
778
}

779
// Multi-thread
jpbl's avatar
jpbl committed
780
bool
781
782
783
ManagerImpl::incomingCallWaiting()
{
    return (_nbIncomingWaitingCall > 0) ? true : false;
jpbl's avatar
jpbl committed
784
785
786
}

void
787
788
789
790
791
ManagerImpl::addWaitingCall (const CallID& id)
{
    ost::MutexLock m (_waitingCallMutex);
    _waitingCall.insert (id);
    _nbIncomingWaitingCall++;
jpbl's avatar
jpbl committed
792
793
794
}

void
795
796
797
798
799
800
801
802
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
803
804
805
}

bool
806
807
808
809
810
811
812
813
814
ManagerImpl::isWaitingCall (const CallID& id)
{
    CallIDSet::iterator iter = _waitingCall.find (id);

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

    return true;
jpbl's avatar
jpbl committed
815
816
}

yanmorin's avatar
   
yanmorin committed
817
///////////////////////////////////////////////////////////////////////////////
818
// Management of event peer IP-phone
yanmorin's avatar
   
yanmorin committed
819
////////////////////////////////////////////////////////////////////////////////
820
821
// SipEvent Thread
bool
822
ManagerImpl::incomingCall (Call* call, const AccountID& accountId)
jpbl's avatar
jpbl committed
823
{
824
825
    PulseLayer *pulselayer;
    std::string from, number;
826

827
    stopTone (true);
828

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