managerimpl.cpp 83.8 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
320
321
	else
	{
	    _debug("There is a conference!!!!!!!!!!!!!!!!!!!!!!\n");
	}
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
358
359
360
    if (_dbus) _dbus->getCallManager()->callStateChanged (id, "HUNGUP");

    _debug ("Stop audio stream\n");

361
    audiolayer = getAudioDriver();
362
363
364

    int nbCalls = getCallList().size();

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

367
368
    // stop stream
    if (! (nbCalls > 1))
369
        audiolayer->stopStream();
370

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

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

Emmanuel Milou's avatar
Emmanuel Milou committed
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
    switchCall ("");
391

392
    if (_audiodriver->getLayerType() == PULSEAUDIO && getConfigInt (PREFERENCES , CONFIG_PA_VOLUME_CTRL)) {
393
        pulselayer = dynamic_cast<PulseLayer *> (getAudioDriver());
394
395

        if (pulselayer)  pulselayer->restorePulseAppsVolume();
396
    }
397

398

399

400
    return returnValue;
jpbl's avatar
jpbl committed
401
402
}

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

410
    stopTone (true);
411

Emmanuel Milou's avatar
Emmanuel Milou committed
412
    /* Direct IP to IP call */
413

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

    /* Classic call, attached to an account */
419
    else {
420
421
        accountid = getAccountFromCall (id);

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

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

        removeCallAccount (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
430
    }
431

Emmanuel Milou's avatar
Emmanuel Milou committed
432
    // it could be a waiting call?
433
434
435
    removeWaitingCall (id);

    switchCall ("");
Emmanuel Milou's avatar
Emmanuel Milou committed
436
437

    return returnValue;
jpbl's avatar
jpbl committed
438
439
}

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

448
    stopTone (true);
449

450
451
    call_id = id;

Emmanuel Milou's avatar
Emmanuel Milou committed
452
    /* Direct IP to IP call */
453

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

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

Emmanuel Milou's avatar
Emmanuel Milou committed
462
        if (accountid == AccountNULL) {
463
            _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
464
465
            return false;
        }
466
467

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

470
471
472
    removeWaitingCall (id);

    switchCall ("");
473

474
    if (_dbus) _dbus->getCallManager()->callStateChanged (call_id, "HOLD");
475

Emmanuel Milou's avatar
Emmanuel Milou committed
476
    return returnValue;
yanmorin's avatar
   
yanmorin committed
477
478
479
}

//THREAD=Main
480
481
bool
ManagerImpl::offHoldCall (const CallID& id)
yanmorin's avatar
   
yanmorin committed
482
{
483

Emmanuel Milou's avatar
Emmanuel Milou committed
484
485
486
    AccountID accountid;
    bool returnValue, rec;
    std::string codecName;
487
    CallID call_id;
488

489
    stopTone (false);
490

491
    call_id = id;
Emmanuel Milou's avatar
Emmanuel Milou committed
492
    //Place current call on hold if it isn't
493
494

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

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

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

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

        _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
518
    }
alexandresavard's avatar
alexandresavard committed
519

520

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

Emmanuel Milou's avatar
Emmanuel Milou committed
527
    }
528

529
    switchCall (id);
530

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

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

Emmanuel Milou's avatar
Emmanuel Milou committed
536
    return returnValue;
jpbl's avatar
jpbl committed
537
538
}

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

546
    stopTone (true);
547

Emmanuel Milou's avatar
Emmanuel Milou committed
548
    /* Direct IP to IP call */
549

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

    /* Classic call, attached to an account */
555
    else {
556
557
        accountid = getAccountFromCall (id);

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

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

        removeCallAccount (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
566
    }
567

568
569
570
571
572
    removeWaitingCall (id);

    switchCall ("");

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

Emmanuel Milou's avatar
Emmanuel Milou committed
574
    return returnValue;
jpbl's avatar
jpbl committed
575
576
}

577
578
void ManagerImpl::transferFailed()
{
579
    if (_dbus) _dbus->getCallManager()->transferFailed();
580
581
582
583
}

void ManagerImpl::transferSucceded()
{
584
    if (_dbus) _dbus->getCallManager()->transferSucceded();
585
586
587
588

}


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

596
597
598
    stopTone (true);

    /* Direct IP to IP call */
Emmanuel Milou's avatar
Emmanuel Milou committed
599
600

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

    /* Classic call, attached to an account */
605
    else {
606
607
        accountid = getAccountFromCall (id);

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

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

        removeCallAccount (id);
616
617
    }

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

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

        switchCall ("");
Emmanuel Milou's avatar
Emmanuel Milou committed
626
    }
627

Emmanuel Milou's avatar
Emmanuel Milou committed
628
    return returnValue;
jpbl's avatar
jpbl committed
629
630
}

631
632

void
633
ManagerImpl::createConference(const CallID& id)
634
635
{
    _debug("ManagerImpl::createConference()\n");
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
    
    Conference* conf = new Conference();
    _conferencemap["conf"] = conf;

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

    answerCall(id);
    
}

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

    if(_conferencemap.empty())
    {
	_debug("NO CONFERENCE YET, CREATE ONE\n");
	createConference(id);
    }
    else
    {
	_debug("ALREADY A CONFERENCE CREATED, ADD PARTICIPANT TO IT\n");
	Conference* conf;
	ConferenceMap::iterator iter = _conferencemap.find("conf");
	conf = iter->second;

	conf->add(id);

	answerCall(id);
    }
    
670
671
}

yanmorin's avatar
   
yanmorin committed
672
//THREAD=Main
673
bool
jpbl's avatar
jpbl committed
674
675
ManagerImpl::saveConfig (void)
{
676
677
678
    _debug ("Saving Configuration...\n");
    setConfig (AUDIO, VOLUME_SPKR, getSpkrVolume());
    setConfig (AUDIO, VOLUME_MICRO, getMicVolume());
jpbl's avatar
jpbl committed
679

680
681
    _setupLoaded = _config.saveConfigTree (_path.data());
    return _setupLoaded;
jpbl's avatar
jpbl committed
682
683
}

yanmorin's avatar
   
yanmorin committed
684
//THREAD=Main
685
int
686
ManagerImpl::initRegisterAccounts()
jpbl's avatar
jpbl committed
687
{
688
    int status;
689
    bool flag = true;
690
691
    AccountMap::iterator iter;

692
    _debugInit ("Initiate VoIP Links Registration");
693
694
    iter = _accountMap.begin();

695
    /* Loop on the account map previously loaded */
696
697
698

    while (iter != _accountMap.end()) {
        if (iter->second) {
699
700
            iter->second->loadConfig();
            /* If the account is set as enabled, try to register */
701
702
703
704
705
706

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

                if (status != SUCCESS) {
                    flag = false;
707
708
                }
            }
709
        }
710

711
        iter++;
Emmanuel Milou's avatar
Emmanuel Milou committed
712
    }
713

714
    // calls the client notification here in case of errors at startup...
715
716
717
718
    if (_audiodriver -> getErrorMessage() != -1)
        notifyErrClient (_audiodriver -> getErrorMessage());

    ASSERT (flag, true);
719

720
    return SUCCESS;
jpbl's avatar
jpbl committed
721
722
}

yanmorin's avatar
   
yanmorin committed
723
//THREAD=Main
724
725
bool
ManagerImpl::sendDtmf (const CallID& id, char code)
jpbl's avatar
jpbl committed
726
{
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
    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
757
758
}

yanmorin's avatar
   
yanmorin committed
759
//THREAD=Main | VoIPLink
760
761
bool
ManagerImpl::playDtmf (char code, bool isTalking)
jpbl's avatar
jpbl committed
762
{
763
764
765
766
    int hasToPlayTone, pulselen, layer, size;
    bool ret = false;
    AudioLayer *audiolayer;
    SFLDataFormat *buf;
767

768
769
770
    stopTone (false);

    hasToPlayTone = getConfigInt (SIGNALISATION, PLAY_DTMF);
771
772

    if (!hasToPlayTone)
773
        return false;
jpbl's avatar
jpbl committed
774

775
    // length in milliseconds
776
777
    pulselen = getConfigInt (SIGNALISATION, PULSE_LENGTH);

778
779
    if (!pulselen)
        return false;
jpbl's avatar
jpbl committed
780

781
782
783
    // numbers of int = length in milliseconds / 1000 (number of seconds)
    //                = number of seconds * SAMPLING_RATE by SECONDS
    audiolayer = getAudioDriver();
784

785
    layer = audiolayer->getLayerType();
jpbl's avatar
jpbl committed
786

787
788
789
    // fast return, no sound, so no dtmf
    if (audiolayer==0 || _dtmfKey == 0)
        return false;
790

791
    // number of data sampling in one pulselen depends on samplerate
792
    // size (n sampling) = time_ms * sampling/s
793
794
    //                     ---------------------
    //                            ms/s
795
    size = (int) (pulselen * ( (float) audiolayer->getSampleRate() /1000));
796
797
798
799
800
801

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

    // Handle dtmf
802
    _dtmfKey->startTone (code);
803
804

    // copy the sound
805
    if (_dtmfKey->generateDTMF (buf, size)) {
806
        // Put buffer to urgentRingBuffer
807
808
        // put the size in bytes...
        // so size * 1 channel (mono) * sizeof (bytes for the data)
809
        audiolayer->startStream();
810
        audiolayer->putUrgent (buf, size * sizeof (SFLDataFormat));
811
    }
812

813
    ret = true;
814

815
    // TODO Cache the DTMF
Emmanuel Milou's avatar
Emmanuel Milou committed
816

817
818
    delete[] buf;
    buf = 0;
819

820
    return ret;
jpbl's avatar
jpbl committed
821
822
}

823
// Multi-thread
jpbl's avatar
jpbl committed
824
bool
825
826
827
ManagerImpl::incomingCallWaiting()
{
    return (_nbIncomingWaitingCall > 0) ? true : false;
jpbl's avatar
jpbl committed
828
829
830
}

void
831
832
833
834
835
ManagerImpl::addWaitingCall (const CallID& id)
{
    ost::MutexLock m (_waitingCallMutex);
    _waitingCall.insert (id);
    _nbIncomingWaitingCall++;
jpbl's avatar
jpbl committed
836
837
838
}

void
839
840
841
842
843
844
845
846
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
847
848
849
}

bool
850
851
852
853
854
855
856
857
858
ManagerImpl::isWaitingCall (const CallID& id)
{
    CallIDSet::iterator iter = _waitingCall.find (id);

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

    return true;
jpbl's avatar
jpbl committed
859
860
}

yanmorin's avatar
   
yanmorin committed
861