managerimpl.cpp 84.3 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
29
30
31
32
33
34
35
36
37
38
39
#include "managerimpl.h"

#include "account.h"
#include "dbus/callmanager.h"
#include "user_cfg.h"
#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
40
41
42
43
44
#include <errno.h>
#include <time.h>
#include <cstdlib>
#include <iostream>
#include <fstream>
45
#include <sstream>
jpbl's avatar
jpbl committed
46
47
48
#include <sys/types.h> // mkdir(2)
#include <sys/stat.h>	// mkdir(2)

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


52

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

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

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

92
    // initialize random generator for call id
93
    srand (time (NULL));
yanmorin's avatar
   
yanmorin committed
94

95
    _cleaner = new NumberCleaner ();
96
    _history = new HistoryManager ();
97

yanmorin's avatar
   
yanmorin committed
98
#ifdef TEST
99
100
101
102
    testAccountMap();
    loadAccountMap();
    testCallAccountMap();
    unloadAccountMap();
yanmorin's avatar
   
yanmorin committed
103
104
#endif

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

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

118
void
119
ManagerImpl::init()
jpbl's avatar
jpbl committed
120
{
121
122
    // Load accounts, init map
    loadAccountMap();
123

124
    initVolume();
125

126
    if (_exist == 0) {
127
        _debug ("Cannot create config file in your home directory\n");
128
    }
129

130
    initAudioDriver();
131

132
    selectAudioDriver();
jpbl's avatar
jpbl committed
133

134
135
    // Initialize the list of supported audio codecs
    initAudioCodec();
136

137
    AudioLayer *audiolayer = getAudioDriver();
138

139
    if (audiolayer != 0) {
140
        unsigned int sampleRate = audiolayer->getSampleRate();
jpbl's avatar
jpbl committed
141

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

146
147
        _debugInit ("Loading DTMF key");
        _dtmfKey = new DTMF (sampleRate);
148
    }
149
150

    if (audiolayer == 0)
151
        audiolayer->stopStream();
152
153
154


    // Load the history
155
    _history->load_history (getConfigInt (PREFERENCES, CONFIG_HISTORY_LIMIT));
jpbl's avatar
jpbl committed
156
157
158
159
}

void ManagerImpl::terminate()
{
160
    _debug ("ManagerImpl::terminate \n");
161
    saveConfig();
jpbl's avatar
jpbl committed
162

163
    unloadAccountMap();
164

165
    _debug ("Unload DTMF Key \n");
166
    delete _dtmfKey;
jpbl's avatar
jpbl committed
167

168
169
170
    _debug ("Unload Audio Driver \n");
    delete _audiodriver;
    _audiodriver = NULL;
jpbl's avatar
jpbl committed
171

172
173
174
    _debug ("Unload Telephone Tone \n");
    delete _telephoneTone;
    _telephoneTone = NULL;
175

176
    _debug ("Unload Audio Codecs \n");
177
    _codecDescriptorMap.deleteHandlePointer();
178

jpbl's avatar
jpbl committed
179
180
}

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

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

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

    return false;
jpbl's avatar
jpbl committed
197
198
}

199
const CallID&
200
201
202
ManagerImpl::getCurrentCallId()
{
    return _currentCallId2;
jpbl's avatar
jpbl committed
203
204
205
}

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


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

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

225
    _debug ("ManagerImpl::outgoingCall() method \n");
226

227
228
    if (getConfigString (HOOKS, PHONE_NUMBER_HOOK_ENABLED) ==  "1")
        _cleaner->set_phone_number_prefix (getConfigString (HOOKS, PHONE_NUMBER_HOOK_ADD_PREFIX));
229
230
    else
        _cleaner->set_phone_number_prefix ("");
231

232
    to_cleaned = _cleaner->clean (to);
Emmanuel Milou's avatar
Emmanuel Milou committed
233
234

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

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

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

Emmanuel Milou's avatar
Emmanuel Milou committed
249
        return false;
250
    }
251

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

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

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

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

Emmanuel Milou's avatar
Emmanuel Milou committed
279
    return false;
jpbl's avatar
jpbl committed
280
281
}

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

288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
    AccountID currentAccountId;
    currentAccountId = getAccountFromCall (id);
    if(currentAccountId == AccountNULL) {
        _debug("ManagerImpl::answerCall : AccountId is null\n");
        return false;
    }
    
    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");
        }
307
    }
308

309
310
    _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
311

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

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

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

333
334
335
    switchCall (id);

    return true;
jpbl's avatar
jpbl committed
336
337
}

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

348
    stopTone (false);
yanmorin's avatar
   
yanmorin committed
349

350
    /* Broadcast a signal over DBus */
351

352
353
354
355
    if (_dbus) _dbus->getCallManager()->callStateChanged (id, "HUNGUP");

    _debug ("Stop audio stream\n");

356
    audiolayer = getAudioDriver();
357
358
359

    int nbCalls = getCallList().size();

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

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

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

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

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

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

        removeCallAccount (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
383
    }
384

385
    switchCall ("");
386

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

        if (pulselayer)  pulselayer->restorePulseAppsVolume();
391
    }
392

393

394

395
    return returnValue;
jpbl's avatar
jpbl committed
396
397
}

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

405
    stopTone (true);
406

Emmanuel Milou's avatar
Emmanuel Milou committed
407
    /* Direct IP to IP call */
408

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

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

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

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

        removeCallAccount (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
425
    }
426

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

    switchCall ("");
Emmanuel Milou's avatar
Emmanuel Milou committed
431
432

    return returnValue;
jpbl's avatar
jpbl committed
433
434
}

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

443
    stopTone (true);
444

445
446
    call_id = id;

Emmanuel Milou's avatar
Emmanuel Milou committed
447
    /* Direct IP to IP call */
448

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

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

Emmanuel Milou's avatar
Emmanuel Milou committed
457
        if (accountid == AccountNULL) {
458
            _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
459
460
            return false;
        }
461
462

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

465
466
467
    removeWaitingCall (id);

    switchCall ("");
468

469
    if (_dbus) _dbus->getCallManager()->callStateChanged (call_id, "HOLD");
470

Emmanuel Milou's avatar
Emmanuel Milou committed
471
    return returnValue;
yanmorin's avatar
   
yanmorin committed
472
473
474
}

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

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

484
    stopTone (false);
485

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

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

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

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

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

        _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
513
    }
alexandresavard's avatar
alexandresavard committed
514

515

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

Emmanuel Milou's avatar
Emmanuel Milou committed
522
    }
523

524
    switchCall (id);
525

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

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

Emmanuel Milou's avatar
Emmanuel Milou committed
531
    return returnValue;
jpbl's avatar
jpbl committed
532
533
}

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

541
    stopTone (true);
542

Emmanuel Milou's avatar
Emmanuel Milou committed
543
    /* Direct IP to IP call */
544

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

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

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

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

        removeCallAccount (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
561
    }
562

563
564
565
566
567
    removeWaitingCall (id);

    switchCall ("");

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

Emmanuel Milou's avatar
Emmanuel Milou committed
569
    return returnValue;
jpbl's avatar
jpbl committed
570
571
}

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

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

}


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

591
592
593
    stopTone (true);

    /* Direct IP to IP call */
Emmanuel Milou's avatar
Emmanuel Milou committed
594
595

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

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

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

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

        removeCallAccount (id);
611
612
    }

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

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

        switchCall ("");
Emmanuel Milou's avatar
Emmanuel Milou committed
621
    }
622

Emmanuel Milou's avatar
Emmanuel Milou committed
623
    return returnValue;
jpbl's avatar
jpbl committed
624
625
}

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

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

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

646
    _debugInit ("Initiate VoIP Links Registration");
647
648
    iter = _accountMap.begin();

649
    /* Loop on the account map previously loaded */
650
651
652

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

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

                if (status != SUCCESS) {
                    flag = false;
661
662
                }
            }
663
        }
664

665
        iter++;
Emmanuel Milou's avatar
Emmanuel Milou committed
666
    }
667

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

    ASSERT (flag, true);
673

674
    return SUCCESS;
jpbl's avatar
jpbl committed
675
676
}

yanmorin's avatar
   
yanmorin committed
677
//THREAD=Main
678
679
bool
ManagerImpl::sendDtmf (const CallID& id, char code)
jpbl's avatar
jpbl committed
680
{
681
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
    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
711
712
}

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

722
723
724
    stopTone (false);

    hasToPlayTone = getConfigInt (SIGNALISATION, PLAY_DTMF);
725
726

    if (!hasToPlayTone)
727
        return false;
jpbl's avatar
jpbl committed
728

729
    // length in milliseconds
730
731
    pulselen = getConfigInt (SIGNALISATION, PULSE_LENGTH);

732
733
    if (!pulselen)
        return false;
jpbl's avatar
jpbl committed
734

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

739
    layer = audiolayer->getLayerType();
jpbl's avatar
jpbl committed
740

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

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

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

    // Handle dtmf
756
    _dtmfKey->startTone (code);
757
758

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

767
    ret = true;
768

769
    // TODO Cache the DTMF
Emmanuel Milou's avatar
Emmanuel Milou committed
770

771
772
    delete[] buf;
    buf = 0;
773

774
    return ret;
jpbl's avatar
jpbl committed
775
776
}

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

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

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

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

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

    return true;
jpbl's avatar
jpbl committed
813
814
}

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

825
    stopTone (true);
826

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

829
    associateCallToAccount (call->getCallId(), accountId);
jpbl's avatar
jpbl committed
830

831
832
833
    if (accountId==AccountNULL)
        associateConfigToCall (call->getCallId(), Call::IPtoIP);

834
    _debug ("ManagerImpl::incomingCall :: hasCurrentCall() %i \n",hasCurrentCall());
Alexandre Savard's avatar