managerimpl.cpp 83 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
}

625
626
627
628
629
630
631

void
ManagerImpl::createConference()
{
    _debug("ManagerImpl::createConference()\n");
}

yanmorin's avatar
   
yanmorin committed
632
//THREAD=Main
633
bool
jpbl's avatar
jpbl committed
634
635
ManagerImpl::saveConfig (void)
{
636
637
638
    _debug ("Saving Configuration...\n");
    setConfig (AUDIO, VOLUME_SPKR, getSpkrVolume());
    setConfig (AUDIO, VOLUME_MICRO, getMicVolume());
jpbl's avatar
jpbl committed
639

640
641
    _setupLoaded = _config.saveConfigTree (_path.data());
    return _setupLoaded;
jpbl's avatar
jpbl committed
642
643
}

yanmorin's avatar
   
yanmorin committed
644
//THREAD=Main
645
int
646
ManagerImpl::initRegisterAccounts()
jpbl's avatar
jpbl committed
647
{
648
    int status;
649
    bool flag = true;
650
651
    AccountMap::iterator iter;

652
    _debugInit ("Initiate VoIP Links Registration");
653
654
    iter = _accountMap.begin();

655
    /* Loop on the account map previously loaded */
656
657
658

    while (iter != _accountMap.end()) {
        if (iter->second) {
659
660
            iter->second->loadConfig();
            /* If the account is set as enabled, try to register */
661
662
663
664
665
666

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

                if (status != SUCCESS) {
                    flag = false;
667
668
                }
            }
669
        }
670

671
        iter++;
Emmanuel Milou's avatar
Emmanuel Milou committed
672
    }
673

674
    // calls the client notification here in case of errors at startup...
675
676
677
678
    if (_audiodriver -> getErrorMessage() != -1)
        notifyErrClient (_audiodriver -> getErrorMessage());

    ASSERT (flag, true);
679

680
    return SUCCESS;
jpbl's avatar
jpbl committed
681
682
}

yanmorin's avatar
   
yanmorin committed
683
//THREAD=Main
684
685
bool
ManagerImpl::sendDtmf (const CallID& id, char code)
jpbl's avatar
jpbl committed
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
711
712
713
714
715
716
    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
717
718
}

yanmorin's avatar
   
yanmorin committed
719
//THREAD=Main | VoIPLink
720
721
bool
ManagerImpl::playDtmf (char code, bool isTalking)
jpbl's avatar
jpbl committed
722
{
723
724
725
726
    int hasToPlayTone, pulselen, layer, size;
    bool ret = false;
    AudioLayer *audiolayer;
    SFLDataFormat *buf;
727

728
729
730
    stopTone (false);

    hasToPlayTone = getConfigInt (SIGNALISATION, PLAY_DTMF);
731
732

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

735
    // length in milliseconds
736
737
    pulselen = getConfigInt (SIGNALISATION, PULSE_LENGTH);

738
739
    if (!pulselen)
        return false;
jpbl's avatar
jpbl committed
740

741
742
743
    // numbers of int = length in milliseconds / 1000 (number of seconds)
    //                = number of seconds * SAMPLING_RATE by SECONDS
    audiolayer = getAudioDriver();
744

745
    layer = audiolayer->getLayerType();
jpbl's avatar
jpbl committed
746

747
748
749
    // fast return, no sound, so no dtmf
    if (audiolayer==0 || _dtmfKey == 0)
        return false;
750

751
    // number of data sampling in one pulselen depends on samplerate
752
    // size (n sampling) = time_ms * sampling/s
753
754
    //                     ---------------------
    //                            ms/s
755
    size = (int) (pulselen * ( (float) audiolayer->getSampleRate() /1000));
756
757
758
759
760
761

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

    // Handle dtmf
762
    _dtmfKey->startTone (code);
763
764

    // copy the sound
765
    if (_dtmfKey->generateDTMF (buf, size)) {
766
        // Put buffer to urgentRingBuffer
767
768
        // put the size in bytes...
        // so size * 1 channel (mono) * sizeof (bytes for the data)
769
        audiolayer->startStream();
770
        audiolayer->putUrgent (buf, size * sizeof (SFLDataFormat));
771
    }
772

773
    ret = true;
774

775
    // TODO Cache the DTMF
Emmanuel Milou's avatar
Emmanuel Milou committed
776

777
778
    delete[] buf;
    buf = 0;
779

780
    return ret;
jpbl's avatar
jpbl committed
781
782
}

783
// Multi-thread
jpbl's avatar
jpbl committed
784
bool
785
786
787
ManagerImpl::incomingCallWaiting()
{
    return (_nbIncomingWaitingCall > 0) ? true : false;
jpbl's avatar
jpbl committed
788
789
790
}

void
791
792
793
794
795
ManagerImpl::addWaitingCall (const CallID& id)
{
    ost::MutexLock m (_waitingCallMutex);
    _waitingCall.insert (id);
    _nbIncomingWaitingCall++;
jpbl's avatar
jpbl committed
796
797
798
}

void
799
800
801
802
803
804
805
806
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
807
808
809
}

bool
810
811
812
813
814
815
816
817
818
ManagerImpl::isWaitingCall (const CallID& id)
{
    CallIDSet::iterator iter = _waitingCall.find (id);

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

    return true;
jpbl's avatar
jpbl committed
819
820
}

yanmorin's avatar
   
yanmorin committed
821
///////////////////////////////////////////////////////////////////////////////
822
// Management of event peer IP-phone
yanmorin's avatar
   
yanmorin committed
823
////////////////////////////////////////////////////////////////////////////////
824
825
// SipEvent Thread
bool
826
ManagerImpl::incomingCall (Call* call, const AccountID& accountId)
jpbl's avatar
jpbl committed
827
{
828
829
    PulseLayer *pulselayer;
    std::string from, number;
830

831
    stopTone (true);
832

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

835
    associateCallToAccount (call->getCallId(), accountId);
jpbl's avatar
jpbl committed
836

Emmanuel Milou's avatar