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

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

#include "account.h"
#include "dbus/callmanager.h"
#include "user_cfg.h"
29
#include "global.h"
30
#include "sip/sipaccount.h"
31

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

jpbl's avatar
jpbl committed
42
43
44
45
46
#include <errno.h>
#include <time.h>
#include <cstdlib>
#include <iostream>
#include <fstream>
47
#include <sstream>
jpbl's avatar
jpbl committed
48
49
#include <sys/types.h> // mkdir(2)
#include <sys/stat.h>	// mkdir(2)
50
#include <pwd.h> // getpwuid
jpbl's avatar
jpbl committed
51
52
53
54
55
56

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

57
58
#define MD5_APPEND(pms,buf,len) pj_md5_update(pms, (const pj_uint8_t*)buf, len)

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

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

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

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

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

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

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

125
    initVolume();
126

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

131
    initAudioDriver();
132

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

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

138
    AudioLayer *audiolayer = getAudioDriver();
139

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

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

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

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


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

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

164
    unloadAccountMap();
165

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

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

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

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

jpbl's avatar
jpbl committed
180
181
}

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

333
334
335
    switchCall (id);

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

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

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

350
    /* Broadcast a signal over DBus */
351

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

    _debug ("Stop audio stream\n");

356
    audiolayer = getAudioDriver();
357
358
359

    int nbCalls = getCallList().size();

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

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

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

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

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

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

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

385
    switchCall ("");
386

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

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

393

394

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

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

405
    stopTone (true);
406

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

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

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

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

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

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

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

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

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

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

443
    stopTone (true);
444

445
446
    call_id = id;

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

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

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

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

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

465
466
467
    removeWaitingCall (id);

    switchCall ("");
468

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

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

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

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

484
    stopTone (false);
485

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

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

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

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

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

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

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

515

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

Emmanuel Milou's avatar
Emmanuel Milou committed
522
    }
523

524
    switchCall (id);
525

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

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

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

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

541
    stopTone (true);
542

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

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

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

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

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

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

563
564
565
566
567
    removeWaitingCall (id);

    switchCall ("");

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

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

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

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

}


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

591
592
593
    stopTone (true);

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

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

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

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

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

        removeCallAccount (id);
611
612
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    ASSERT (flag, true);
673

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

yanmorin's avatar
   
yanmorin committed
677
//THREAD=Main
678
679
bool
ManagerImpl::sendDtmf (const CallID& id, char code)
jpbl's avatar
jpbl committed
680
{
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
    AccountID accountid = getAccountFromCall (id);

    if (accountid == AccountNULL) {
        //_debug("Send DTMF: call doesn't exists\n");
        playDtmf (code, false);
        return false;
    }

    int sendType = getConfigInt (SIGNALISATION, SEND_DTMF_AS);

    bool returnValue = false;

    switch (sendType) {

        case 0: // SIP INFO
            playDtmf (code , true);
            returnValue = getAccountLink (accountid)->carryingDTMFdigits (id, code);
            break;

        case 1: // Audio way
            break;

        case 2: // rfc 2833
            break;

        default: // unknown - error config?
            break;
    }

    return returnValue;
jpbl's avatar
jpbl committed
711
712
}

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

722
723
    stopTone (false);

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

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

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

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

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

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

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

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

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

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

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

767
    ret = true;
768

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

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

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

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

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

void
793
794
795
796
797
798
799
800
ManagerImpl::removeWaitingCall (const CallID& id)
{
    ost::MutexLock m (_waitingCallMutex);
    // should return more than 1 if it erase a call

    if (_waitingCall.erase (id)) {
        _nbIncomingWaitingCall--;
    }
jpbl's avatar
jpbl committed
801
802
803
}

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

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

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

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

825
    stopTone (true);
826

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