managerimpl.cpp 84.1 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 "sipaccount.h"
jpbl's avatar
jpbl committed
41
#include "audio/audiolayer.h"
42
43
#include "audio/alsalayer.h"
#include "audio/pulselayer.h"
jpbl's avatar
jpbl committed
44
45
#include "audio/tonelist.h"

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

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
284
285
    bool isActive = false;

    stopTone (true);
286

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

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

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

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

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

332
333
334
    switchCall (id);

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

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

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

349
    /* Broadcast a signal over DBus */
350

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

    _debug ("Stop audio stream\n");

355
    audiolayer = getAudioDriver();
356
357
358

    int nbCalls = getCallList().size();

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

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

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

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

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

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

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

384
    switchCall ("");
385

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

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

392

393

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

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

404
    stopTone (true);
405

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

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

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

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

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

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

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

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

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

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

442
    stopTone (true);
443

444
445
    call_id = id;

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

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

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

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

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

464
465
466
    removeWaitingCall (id);

    switchCall ("");
467

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

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

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

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

483
    stopTone (false);
484

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

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

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

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

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

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

514

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

Emmanuel Milou's avatar
Emmanuel Milou committed
521
    }
522

523
    switchCall (id);
524

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

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

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

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

540
    stopTone (true);
541

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

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

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

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

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

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

562
563
564
565
566
    removeWaitingCall (id);

    switchCall ("");

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

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

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

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

}


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

590
591
592
    stopTone (true);

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

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

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

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

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

        removeCallAccount (id);
610
611
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    ASSERT (flag, true);
672

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

yanmorin's avatar
   
yanmorin committed
676
//THREAD=Main
677
678
bool
ManagerImpl::sendDtmf (const CallID& id, char code)
jpbl's avatar
jpbl committed
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
708
709
    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
710
711
}

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

721
722
723
    stopTone (false);

    hasToPlayTone = getConfigInt (SIGNALISATION, PLAY_DTMF);
724
725

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

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

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

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

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

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

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

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

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

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

766
    ret = true;
767

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

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

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

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

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

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

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

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

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

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

824
    stopTone (true);
825

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

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

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