managerimpl.cpp 86.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
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
#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>

38
39
#include "conference.h"

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

yanmorin's avatar
   
yanmorin committed
48
#include "accountcreator.h" // create new account
49
50
#include "sipvoiplink.h"

jpbl's avatar
jpbl committed
51
52
53
54
55
56
57
#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)))

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

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

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

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

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

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

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

123
    initVolume();
124

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

129
    initAudioDriver();
130

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

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

136
    AudioLayer *audiolayer = getAudioDriver();
137

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

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

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

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


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

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

162
    unloadAccountMap();
163

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

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

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

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

jpbl's avatar
jpbl committed
178
179
}

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    stopTone (true);
288

289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
    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");
        }
308
    }
309

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

313
314
    if (lastCall != NULL ) {
        if (lastCall->getState() == Call::Active && _conferencemap.empty()) {
315
316
317
            _debug ("* Manager Info: there is currently a call, try to hold it\n");
            onHoldCall (getCurrentCallId());
        }
318
319
	else
	{
320
	    _debug("There is a conference! Do not hold the current call\n");
321
	}
322
323
    }

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

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

338
339
340
    switchCall (id);

    return true;
jpbl's avatar
jpbl committed
341
342
}

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

353
    stopTone (false);
yanmorin's avatar
   
yanmorin committed
354

355
    /* Broadcast a signal over DBus */
356

357
    _debug("ManagerImpl::hangupCall: Send DBUS call state change (HUNGUP) for id %s\n", id.c_str());
358
359
    if (_dbus) _dbus->getCallManager()->callStateChanged (id, "HUNGUP");

360
361
    int nbCalls = getCallList().size();

362
    audiolayer = getAudioDriver();
363
    // stop streamx
364
365
366
    if (! (nbCalls >= 1))
    {
	_debug("ManagerImpl::stop audio stream, ther is only %i call(s) remaining\n", nbCalls);
367
        audiolayer->stopStream();
368
    }
369

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

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

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

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

        removeCallAccount (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
388
    }
389

390
391
392
    if(participToConference(id))
	removeParticipant(id);

393
394
    _debug("What next (before switch call)?\n");

395
    switchCall ("");
396

397
398
    _debug("What next (after switch call, before restore pulse app volume)?\n");

399
    if (_audiodriver->getLayerType() == PULSEAUDIO && getConfigInt (PREFERENCES , CONFIG_PA_VOLUME_CTRL)) {
400
        pulselayer = dynamic_cast<PulseLayer *> (getAudioDriver());
401
402

        if (pulselayer)  pulselayer->restorePulseAppsVolume();
403
    }
404

405
    _debug("What next (after restore pulse app volume)?\n");
406

407
    return returnValue;
jpbl's avatar
jpbl committed
408
409
}

yanmorin's avatar
   
yanmorin committed
410
//THREAD=Main
411
bool
yanmorin's avatar
   
yanmorin committed
412
ManagerImpl::cancelCall (const CallID& id)
jpbl's avatar
jpbl committed
413
{
Emmanuel Milou's avatar
Emmanuel Milou committed
414
415
    AccountID accountid;
    bool returnValue;
yanmorin's avatar
   
yanmorin committed
416

417
    stopTone (true);
418

Emmanuel Milou's avatar
Emmanuel Milou committed
419
    /* Direct IP to IP call */
420

Emmanuel Milou's avatar
Emmanuel Milou committed
421
    if (getConfigFromCall (id) == Call::IPtoIP) {
422
        returnValue = SIPVoIPLink::instance (AccountNULL)->cancel (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
423
424
425
    }

    /* Classic call, attached to an account */
426
    else {
427
428
        accountid = getAccountFromCall (id);

Emmanuel Milou's avatar
Emmanuel Milou committed
429
        if (accountid == AccountNULL) {
430
            _debug ("! Manager Cancel Call: Call doesn't exists\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
431
432
            return false;
        }
433
434
435
436

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

        removeCallAccount (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
437
    }
438

Emmanuel Milou's avatar
Emmanuel Milou committed
439
    // it could be a waiting call?
440
441
442
    removeWaitingCall (id);

    switchCall ("");
Emmanuel Milou's avatar
Emmanuel Milou committed
443
444

    return returnValue;
jpbl's avatar
jpbl committed
445
446
}

yanmorin's avatar
   
yanmorin committed
447
//THREAD=Main
448
449
bool
ManagerImpl::onHoldCall (const CallID& id)
jpbl's avatar
jpbl committed
450
{
Emmanuel Milou's avatar
Emmanuel Milou committed
451
452
    AccountID accountid;
    bool returnValue;
453
    CallID call_id;
yanmorin's avatar
   
yanmorin committed
454

455
    stopTone (true);
456

457
458
    call_id = id;

459
460
461
    if(participToConference(id))
	removeParticipant(id);

Emmanuel Milou's avatar
Emmanuel Milou committed
462
    /* Direct IP to IP call */
463

Emmanuel Milou's avatar
Emmanuel Milou committed
464
    if (getConfigFromCall (id) == Call::IPtoIP) {
465
        returnValue = SIPVoIPLink::instance (AccountNULL)-> onhold (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
466
    }
467

Emmanuel Milou's avatar
Emmanuel Milou committed
468
    /* Classic call, attached to an account */
469
    else {
470
471
        accountid = getAccountFromCall (id);

Emmanuel Milou's avatar
Emmanuel Milou committed
472
        if (accountid == AccountNULL) {
473
            _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
474
475
            return false;
        }
476
477

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

480
481
482
    removeWaitingCall (id);

    switchCall ("");
483

484
    if (_dbus) _dbus->getCallManager()->callStateChanged (call_id, "HOLD");
485

Emmanuel Milou's avatar
Emmanuel Milou committed
486
    return returnValue;
yanmorin's avatar
   
yanmorin committed
487
488
489
}

//THREAD=Main
490
491
bool
ManagerImpl::offHoldCall (const CallID& id)
yanmorin's avatar
   
yanmorin committed
492
{
493

Emmanuel Milou's avatar
Emmanuel Milou committed
494
495
496
    AccountID accountid;
    bool returnValue, rec;
    std::string codecName;
497
    CallID call_id;
498

499
    stopTone (false);
500

501
    call_id = id;
Emmanuel Milou's avatar
Emmanuel Milou committed
502
    //Place current call on hold if it isn't
503
504

    if (hasCurrentCall()) {
505
        _debug ("Put the current call (ID=%s) on hold\n", getCurrentCallId().c_str());
506
        onHoldCall (getCurrentCallId());
Emmanuel Milou's avatar
Emmanuel Milou committed
507
    }
508

Emmanuel Milou's avatar
Emmanuel Milou committed
509
510
511
    /* Direct IP to IP call */
    if (getConfigFromCall (id) == Call::IPtoIP) {
        rec = SIPVoIPLink::instance (AccountNULL)-> isRecording (id);
512
        returnValue = SIPVoIPLink::instance (AccountNULL)-> offhold (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
513
    }
alexandresavard's avatar
alexandresavard committed
514

Emmanuel Milou's avatar
Emmanuel Milou committed
515
    /* Classic call, attached to an account */
516
    else {
517
518
        accountid = getAccountFromCall (id);

Emmanuel Milou's avatar
Emmanuel Milou committed
519
        if (accountid == AccountNULL) {
520
            _debug ("Manager OffHold Call: Call doesn't exists\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
521
522
            return false;
        }
523
524
525
526
527

        _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
528
    }
alexandresavard's avatar
alexandresavard committed
529

530

531
    if (_dbus) {
Emmanuel Milou's avatar
Emmanuel Milou committed
532
        if (rec)
533
            _dbus->getCallManager()->callStateChanged (call_id, "UNHOLD_RECORD");
534
        else
535
            _dbus->getCallManager()->callStateChanged (call_id, "UNHOLD_CURRENT");
536

Emmanuel Milou's avatar
Emmanuel Milou committed
537
    }
538

539
    switchCall (id);
540

541
    codecName = getCurrentCodecName (id);
542
    // _debug("ManagerImpl::hangupCall(): broadcast codec name %s \n",codecName.c_str());
543
544

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

Emmanuel Milou's avatar
Emmanuel Milou committed
546
    return returnValue;
jpbl's avatar
jpbl committed
547
548
}

yanmorin's avatar
   
yanmorin committed
549
//THREAD=Main
550
551
bool
ManagerImpl::transferCall (const CallID& id, const std::string& to)
jpbl's avatar
jpbl committed
552
{
Emmanuel Milou's avatar
Emmanuel Milou committed
553
554
    AccountID accountid;
    bool returnValue;
555

556
    stopTone (true);
557

Emmanuel Milou's avatar
Emmanuel Milou committed
558
    /* Direct IP to IP call */
559

Emmanuel Milou's avatar
Emmanuel Milou committed
560
    if (getConfigFromCall (id) == Call::IPtoIP) {
561
        returnValue = SIPVoIPLink::instance (AccountNULL)-> transfer (id, to);
Emmanuel Milou's avatar
Emmanuel Milou committed
562
563
564
    }

    /* Classic call, attached to an account */
565
    else {
566
567
        accountid = getAccountFromCall (id);

Emmanuel Milou's avatar
Emmanuel Milou committed
568
        if (accountid == AccountNULL) {
569
            _debug ("! Manager Transfer Call: Call doesn't exists\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
570
571
            return false;
        }
572
573
574
575

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

        removeCallAccount (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
576
    }
577

578
579
580
581
582
    removeWaitingCall (id);

    switchCall ("");

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

Emmanuel Milou's avatar
Emmanuel Milou committed
584
    return returnValue;
jpbl's avatar
jpbl committed
585
586
}

587
588
void ManagerImpl::transferFailed()
{
589
    if (_dbus) _dbus->getCallManager()->transferFailed();
590
591
592
593
}

void ManagerImpl::transferSucceded()
{
594
    if (_dbus) _dbus->getCallManager()->transferSucceded();
595
596
597
598

}


yanmorin's avatar
   
yanmorin committed
599
//THREAD=Main : Call:Incoming
600
bool
yanmorin's avatar
   
yanmorin committed
601
ManagerImpl::refuseCall (const CallID& id)
jpbl's avatar
jpbl committed
602
{
Emmanuel Milou's avatar
Emmanuel Milou committed
603
604
    AccountID accountid;
    bool returnValue;
605

606
607
608
    stopTone (true);

    /* Direct IP to IP call */
Emmanuel Milou's avatar
Emmanuel Milou committed
609
610

    if (getConfigFromCall (id) == Call::IPtoIP) {
611
        returnValue = SIPVoIPLink::instance (AccountNULL)-> refuse (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
612
613
614
    }

    /* Classic call, attached to an account */
615
    else {
616
617
        accountid = getAccountFromCall (id);

Emmanuel Milou's avatar
Emmanuel Milou committed
618
        if (accountid == AccountNULL) {
619
            _debug ("! Manager OffHold Call: Call doesn't exists\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
620
621
            return false;
        }
622
623
624
625

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

        removeCallAccount (id);
626
627
    }

Emmanuel Milou's avatar
Emmanuel Milou committed
628
629
630
    // if the call was outgoing or established, we didn't refuse it
    // so the method did nothing
    if (returnValue) {
631
632
633
634
635
        removeWaitingCall (id);

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

        switchCall ("");
Emmanuel Milou's avatar
Emmanuel Milou committed
636
    }
637

Emmanuel Milou's avatar
Emmanuel Milou committed
638
    return returnValue;
jpbl's avatar
jpbl committed
639
640
}

641
642

void
643
ManagerImpl::createConference(const CallID& id)
644
645
{
    _debug("ManagerImpl::createConference()\n");
646
647
    
    Conference* conf = new Conference();
648
649

    _conferencecall.insert(pair<CallID, Conference*>(id, conf));
650
    _conferencemap.insert(pair<CallID, Conference*>(default_conf, conf));
651
652
653
654
655
656
657

    conf->add(getCurrentCallId());
    conf->add(id);

}

void
658
ManagerImpl::removeConference(const CallID& conference_id)
659
{
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676

    _debug("ManagerImpl::removeConference(%s)\n", conference_id.c_str());

    Conference* conf; 
    ConferenceMap::iterator iter = _conferencemap.find(conference_id);
    conf = iter->second;


    ConferenceCallMap::iterator iter_p;
    for(iter_p = _conferencecall.begin(); iter_p != _conferencecall.end(); iter_p++)
    {
	if(iter_p->second == conf)
	{
	    _conferencecall.erase(iter_p);
	}
    }

677
    _conferencemap.erase(default_conf);
678

679
680
    _debug("ManagerImpl::conference removed succesfully\n");

681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
}

bool
ManagerImpl::participToConference(const CallID& call_id)
{
    ConferenceCallMap::iterator iter = _conferencecall.find(call_id);
    if(iter == _conferencecall.end())
    {
	return false;
    }
    else
    {
	return true;
    }
}

void
ManagerImpl::addParticipant(const CallID& call_id)
{
    _debug("ManagerImpl::addParticipant(%s)\n", call_id.c_str());
701
702
    _debug("    Current call ID %s\n", getCurrentCallId().c_str());

703
    // TODO: add conference_id as a second parameter
704
    ConferenceMap::iterator iter = _conferencemap.find(default_conf);
705
706

    if(iter == _conferencemap.end())
707
708
    {
	_debug("NO CONFERENCE YET, CREATE ONE\n");
709
	createConference(call_id);
710
711
712

	answerCall(call_id);

713
714
715
716
    }
    else
    {
	_debug("ALREADY A CONFERENCE CREATED, ADD PARTICIPANT TO IT\n");
717
	Conference* conf = iter->second;
718

719
720
721
	conf->add(call_id);
	
	_conferencecall.insert(pair<CallID, Conference*>(call_id, conf));
722

723
	answerCall(call_id);
724
725
    }
    
726
727
}

728
729
730
731
732
733
734
void
ManagerImpl::removeParticipant(const CallID& call_id)
{
    _debug("ManagerImpl::removeParticipant(%s)\n", call_id.c_str());

    // TODO: add conference_id as a second parameter
    Conference* conf;
735
    ConferenceMap::iterator iter = _conferencemap.find(default_conf);
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750

    if(iter == _conferencemap.end())
    {
	_debug("NO CONFERENCE CREATED, CANNOT REMOVE PARTICIPANT\n");
    }
    else
    {
	conf = iter->second;

	_debug("REMOVE PARTICIPANT %s\n", call_id.c_str());
	conf->remove(call_id);

	_conferencecall.erase(iter);

	if (conf->getNbParticipants() <= 1)
751
	    removeConference(default_conf);
752
753
754
    }
}

755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
void
ManagerImpl::addStream(const CallID& call_id)
{
    _debug("ManagerImpl::addStream %s\n", call_id.c_str());

    if(participToConference(call_id))
    {
	ConferenceMap::iterator iter = _conferencemap.find(default_conf);
	
	Conference* conf = iter->second;

	conf->bindParticipant(call_id);
    }
    else
    {
	getAudioDriver()->getMainBuffer()->bindCallID(call_id);
    }
}

yanmorin's avatar
   
yanmorin committed
774
//THREAD=Main
775
bool
jpbl's avatar
jpbl committed
776
777
ManagerImpl::saveConfig (void)
{
778
779
780
    _debug ("Saving Configuration...\n");
    setConfig (AUDIO, VOLUME_SPKR, getSpkrVolume());
    setConfig (AUDIO, VOLUME_MICRO, getMicVolume());
jpbl's avatar
jpbl committed
781

782
783
    _setupLoaded = _config.saveConfigTree (_path.data());
    return _setupLoaded;
jpbl's avatar
jpbl committed
784
785
}

yanmorin's avatar
   
yanmorin committed
786
//THREAD=Main
787
int
788
ManagerImpl::initRegisterAccounts()
jpbl's avatar
jpbl committed
789
{
790
    int status;
791
    bool flag = true;
792
793
    AccountMap::iterator iter;

794
    _debugInit ("Initiate VoIP Links Registration");
795
796
    iter = _accountMap.begin();

797
    /* Loop on the account map previously loaded */
798
799
800

    while (iter != _accountMap.end()) {
        if (iter->second) {
801
802
            iter->second->loadConfig();
            /* If the account is set as enabled, try to register */
803
804
805
806
807
808

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

                if (status != SUCCESS) {
                    flag = false;
809
810
                }
            }
811
        }
812

813
        iter++;
Emmanuel Milou's avatar
Emmanuel Milou committed
814
    }
815

816
    // calls the client notification here in case of errors at startup...
817
818
819
820
    if (_audiodriver -> getErrorMessage() != -1)
        notifyErrClient (_audiodriver -> getErrorMessage());

    ASSERT (flag, true);
821

822
    return SUCCESS;
jpbl's avatar
jpbl committed
823
824
}

yanmorin's avatar
   
yanmorin committed
825
//THREAD=Main
826
827
bool
ManagerImpl::sendDtmf (const CallID& id, char code)
jpbl's avatar
jpbl committed
828
{
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
    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
859
860
}

yanmorin's avatar
   
yanmorin committed
861
//THREAD=Main | VoIPLink
862
863
bool
ManagerImpl::playDtmf (char code, bool isTalking)
jpbl's avatar
jpbl committed
864
{
865
866
867
868
    int hasToPlayTone, pulselen, layer, size;
    bool ret = false;
    AudioLayer *audiolayer;
    SFLDataFormat *buf;
869

870
871
872
    stopTone (false);

    hasToPlayTone = getConfigInt (SIGNALISATION, PLAY_DTMF);
873
874

    if (!hasToPlayTone)