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

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

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

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

yanmorin's avatar
   
yanmorin committed
46
#include "accountcreator.h" // create new account
47
#include "sip/sipvoiplink.h"
48

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

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

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

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

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

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

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

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

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

121
    initVolume();
122

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

127
    initAudioDriver();
128

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

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

134
    AudioLayer *audiolayer = getAudioDriver();
135

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

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

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

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


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

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

160
    unloadAccountMap();
161

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

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

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

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

jpbl's avatar
jpbl committed
176
177
}

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

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

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

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

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

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


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

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

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

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

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

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

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

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

Emmanuel Milou's avatar
Emmanuel Milou committed
246
        return false;
247
    }
248

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

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

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

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

    associateCallToAccount (id, accountid);

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

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

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

285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
    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");
        }
304
    }
305

306
307
    _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
308

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

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

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

330
331
332
    switchCall (id);

    return true;
jpbl's avatar
jpbl committed
333
334
}

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

345
    stopTone (false);
yanmorin's avatar
   
yanmorin committed
346

347
    /* Broadcast a signal over DBus */
348

349
350
351
352
    if (_dbus) _dbus->getCallManager()->callStateChanged (id, "HUNGUP");

    _debug ("Stop audio stream\n");

353
    audiolayer = getAudioDriver();
354
355
356

    int nbCalls = getCallList().size();

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

359
360
    // stop stream
    if (! (nbCalls > 1))
361
        audiolayer->stopStream();
362

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

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

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

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

        removeCallAccount (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
380
    }
381

382
    switchCall ("");
383

384
    if (_audiodriver->getLayerType() == PULSEAUDIO && getConfigInt (PREFERENCES , CONFIG_PA_VOLUME_CTRL)) {
385
        pulselayer = dynamic_cast<PulseLayer *> (getAudioDriver());
386
387

        if (pulselayer)  pulselayer->restorePulseAppsVolume();
388
    }
389

390

391

392
    return returnValue;
jpbl's avatar
jpbl committed
393
394
}

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

402
    stopTone (true);
403

Emmanuel Milou's avatar
Emmanuel Milou committed
404
    /* Direct IP to IP call */
405

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

    /* Classic call, attached to an account */
411
    else {
412
413
        accountid = getAccountFromCall (id);

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

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

        removeCallAccount (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
422
    }
423

Emmanuel Milou's avatar
Emmanuel Milou committed
424
    // it could be a waiting call?
425
426
427
    removeWaitingCall (id);

    switchCall ("");
Emmanuel Milou's avatar
Emmanuel Milou committed
428
429

    return returnValue;
jpbl's avatar
jpbl committed
430
431
}

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

440
    stopTone (true);
441

442
443
    call_id = id;

Emmanuel Milou's avatar
Emmanuel Milou committed
444
    /* Direct IP to IP call */
445

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

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

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

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

462
463
464
    removeWaitingCall (id);

    switchCall ("");
465

466
    if (_dbus) _dbus->getCallManager()->callStateChanged (call_id, "HOLD");
467

Emmanuel Milou's avatar
Emmanuel Milou committed
468
    return returnValue;
yanmorin's avatar
   
yanmorin committed
469
470
471
}

//THREAD=Main
472
473
bool
ManagerImpl::offHoldCall (const CallID& id)
yanmorin's avatar
   
yanmorin committed
474
{
475

Emmanuel Milou's avatar
Emmanuel Milou committed
476
477
478
    AccountID accountid;
    bool returnValue, rec;
    std::string codecName;
479
    CallID call_id;
480

481
    stopTone (false);
482

483
    call_id = id;
Emmanuel Milou's avatar
Emmanuel Milou committed
484
    //Place current call on hold if it isn't
485
486

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

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

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

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

        _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
510
    }
alexandresavard's avatar
alexandresavard committed
511

512

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

Emmanuel Milou's avatar
Emmanuel Milou committed
519
    }
520

521
    switchCall (id);
522

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

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

Emmanuel Milou's avatar
Emmanuel Milou committed
528
    return returnValue;
jpbl's avatar
jpbl committed
529
530
}

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

538
    stopTone (true);
539

Emmanuel Milou's avatar
Emmanuel Milou committed
540
    /* Direct IP to IP call */
541

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

    /* Classic call, attached to an account */
547
    else {
548
549
        accountid = getAccountFromCall (id);

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

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

        removeCallAccount (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
558
    }
559

560
561
562
563
564
    removeWaitingCall (id);

    switchCall ("");

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

Emmanuel Milou's avatar
Emmanuel Milou committed
566
    return returnValue;
jpbl's avatar
jpbl committed
567
568
}

569
570
void ManagerImpl::transferFailed()
{
571
    if (_dbus) _dbus->getCallManager()->transferFailed();
572
573
574
575
}

void ManagerImpl::transferSucceded()
{
576
    if (_dbus) _dbus->getCallManager()->transferSucceded();
577
578
579
580

}


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

588
589
590
    stopTone (true);

    /* Direct IP to IP call */
Emmanuel Milou's avatar
Emmanuel Milou committed
591
592

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

    /* Classic call, attached to an account */
597
    else {
598
599
        accountid = getAccountFromCall (id);

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

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

        removeCallAccount (id);
608
609
    }

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

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

        switchCall ("");
Emmanuel Milou's avatar
Emmanuel Milou committed
618
    }
619

Emmanuel Milou's avatar
Emmanuel Milou committed
620
    return returnValue;
jpbl's avatar
jpbl committed
621
622
}

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

631
632
    _setupLoaded = _config.saveConfigTree (_path.data());
    return _setupLoaded;
jpbl's avatar
jpbl committed
633
634
}

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

643
    _debugInit ("Initiate VoIP Links Registration");
644
645
    iter = _accountMap.begin();

646
    /* Loop on the account map previously loaded */
647
648
649

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

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

                if (status != SUCCESS) {
                    flag = false;
658
659
                }
            }
660
        }
661

662
        iter++;
Emmanuel Milou's avatar
Emmanuel Milou committed
663
    }
664

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

    ASSERT (flag, true);
670

671
    return SUCCESS;
jpbl's avatar
jpbl committed
672
673
}

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

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

719
720
721
    stopTone (false);

    hasToPlayTone = getConfigInt (SIGNALISATION, PLAY_DTMF);
722
723

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

726
    // length in milliseconds
727
728
    pulselen = getConfigInt (SIGNALISATION, PULSE_LENGTH);

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

732
733
734
    // numbers of int = length in milliseconds / 1000 (number of seconds)
    //                = number of seconds * SAMPLING_RATE by SECONDS
    audiolayer = getAudioDriver();
735

736
    layer = audiolayer->getLayerType();
jpbl's avatar
jpbl committed
737

738
739
740
    // fast return, no sound, so no dtmf
    if (audiolayer==0 || _dtmfKey == 0)
        return false;
741

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

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

    // Handle dtmf
753
    _dtmfKey->startTone (code);
754
755

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

764
    ret = true;
765

766
    // TODO Cache the DTMF
Emmanuel Milou's avatar
Emmanuel Milou committed
767

768
769
    delete[] buf;
    buf = 0;
770

771
    return ret;
jpbl's avatar
jpbl committed
772
773
}

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

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

void
790
791
792
793
794
795
796
797
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
798
799
800
}

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

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

    return true;
jpbl's avatar
jpbl committed
810
811
}

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

822
    stopTone (true);
823

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

826
    associateCallToAccount (call->getCallId(), accountId);
jpbl's avatar
jpbl committed
827