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

#include <errno.h>
#include <time.h>
#include <cstdlib>
#include <iostream>
#include <fstream>
29
#include <sstream>  
jpbl's avatar
jpbl committed
30
31
32
33
34
35
36
37
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)))

Yun Liu's avatar
Yun Liu committed
56
57
58
59
ManagerImpl::ManagerImpl (void) 
	: _hasTriedToRegister(false)
        , _config()
	, _currentCallId2()
60
        , _currentCallMutex()
Yun Liu's avatar
Yun Liu committed
61
62
63
64
        , _codecBuilder(NULL)
        , _audiodriver(NULL)
        , _dtmfKey(NULL)
        , _codecDescriptorMap()
65
        , _toneMutex()
Yun Liu's avatar
Yun Liu committed
66
67
68
69
        , _telephoneTone(NULL)
        , _audiofile()
        , _spkr_volume(0)
        , _mic_volume(0)
70
        , _mutex()
Yun Liu's avatar
Yun Liu committed
71
72
	, _dbus(NULL)
        , _waitingCall()
73
        , _waitingCallMutex()
Yun Liu's avatar
Yun Liu committed
74
75
76
77
78
79
80
81
        , _nbIncomingWaitingCall(0)
        , _path("")
        , _exist(0)
        , _setupLoaded(false)
        , _firewallPort()
        , _firewallAddr("")
        , _hasZeroconf(false)
        , _callAccountMap()
82
        , _callAccountMapMutex()
Emmanuel Milou's avatar
Emmanuel Milou committed
83
        , _callConfigMap()
Yun Liu's avatar
Yun Liu committed
84
        , _accountMap()
jpbl's avatar
jpbl committed
85
{
86
87
88
  
    // initialize random generator for call id
    srand (time(NULL));
yanmorin's avatar
   
yanmorin committed
89
90
91
92
93
94
95
96
97

#ifdef TEST
  testAccountMap();
  loadAccountMap();
  testCallAccountMap();
  unloadAccountMap();
#endif

  // should be call before initConfigFile
98
  // loadAccountMap();, called in init() now.
jpbl's avatar
jpbl committed
99
100
101
102
103
}

// never call if we use only the singleton...
ManagerImpl::~ManagerImpl (void) 
{
104
    // terminate();
105
    _debug("%s stop correctly.\n", PROGNAME);
jpbl's avatar
jpbl committed
106
107
}

108
  void 
jpbl's avatar
jpbl committed
109
110
ManagerImpl::init() 
{
111
112
    // Load accounts, init map
    loadAccountMap();
113
 
114
    initVolume();
115

116
117
118
    if (_exist == 0) {
        _debug("Cannot create config file in your home directory\n");
    }
119

120
121
    initAudioDriver();
    selectAudioDriver();
jpbl's avatar
jpbl committed
122

123
124
    // Initialize the list of supported audio codecs
    initAudioCodec();
125

126
    AudioLayer *audiolayer = getAudioDriver();
127
    
128
    if (audiolayer != 0) {
129
        unsigned int sampleRate = audiolayer->getSampleRate();
jpbl's avatar
jpbl committed
130

131
132
133
        _debugInit("Load Telephone Tone");
        std::string country = getConfigString(PREFERENCES, ZONE_TONE);
        _telephoneTone = new TelephoneTone(country, sampleRate);
jpbl's avatar
jpbl committed
134

135
136
137
        _debugInit("Loading DTMF key");
        _dtmfKey = new DTMF(sampleRate);
    }
138
139
140

    if (audiolayer == 0)
      audiolayer->stopStream();
jpbl's avatar
jpbl committed
141
142
143
144
}

void ManagerImpl::terminate()
{
145
    _debug("ManagerImpl::terminate \n");
146
    saveConfig();
jpbl's avatar
jpbl committed
147

148
    unloadAccountMap();
149
  
150
    _debug("Unload DTMF Key \n");
151
    delete _dtmfKey;
jpbl's avatar
jpbl committed
152

153
    _debug("Unload Audio Driver \n");
154
    delete _audiodriver; _audiodriver = NULL;
jpbl's avatar
jpbl committed
155

156
    _debug("Unload Telephone Tone \n");
157
    delete _telephoneTone; _telephoneTone = NULL;
158

159
    _debug("Unload Audio Codecs \n");
160
    _codecDescriptorMap.deleteHandlePointer();
161
    
jpbl's avatar
jpbl committed
162
163
}

yanmorin's avatar
   
yanmorin committed
164
165
166
bool
ManagerImpl::isCurrentCall(const CallID& callId) {
  return (_currentCallId2 == callId ? true : false);
jpbl's avatar
jpbl committed
167
168
}

yanmorin's avatar
   
yanmorin committed
169
170
bool
ManagerImpl::hasCurrentCall() {
Emmanuel Milou's avatar
Bug fix    
Emmanuel Milou committed
171
  _debug("Current call ID = %s\n", _currentCallId2.c_str());
yanmorin's avatar
   
yanmorin committed
172
173
  if ( _currentCallId2 != "") {
    return true;
jpbl's avatar
jpbl committed
174
  }
yanmorin's avatar
   
yanmorin committed
175
  return false;
jpbl's avatar
jpbl committed
176
177
}

yanmorin's avatar
   
yanmorin committed
178
179
180
const CallID& 
ManagerImpl::getCurrentCallId() {
  return _currentCallId2;
jpbl's avatar
jpbl committed
181
182
183
}

void
yanmorin's avatar
   
yanmorin committed
184
ManagerImpl::switchCall(const CallID& id ) {
185
  ost::MutexLock m(_currentCallMutex);
yanmorin's avatar
   
yanmorin committed
186
  _currentCallId2 = id;
jpbl's avatar
jpbl committed
187
188
189
190
191
192
}


///////////////////////////////////////////////////////////////////////////////
// Management of events' IP-phone user
///////////////////////////////////////////////////////////////////////////////
yanmorin's avatar
   
yanmorin committed
193
/* Main Thread */ 
Emmanuel Milou's avatar
Emmanuel Milou committed
194

195
  bool
yanmorin's avatar
   
yanmorin committed
196
197
ManagerImpl::outgoingCall(const std::string& accountid, const CallID& id, const std::string& to)
{
Emmanuel Milou's avatar
Emmanuel Milou committed
198
199
200
201
    std::string pattern;
    Call::CallConfiguration callConfig;
    SIPVoIPLink *siplink;
    
202
203
    _debug("ManagerImpl::outgoingCall() method \n");

Emmanuel Milou's avatar
Emmanuel Milou committed
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
    // stopTone(false);
    // playTone();

    /* Check what kind of call we are dealing with */
    check_call_configuration (id, to, &callConfig);
    
    if (callConfig == Call::IPtoIP) {
        _debug ("Start IP to IP call\n");
        /* We need to retrieve the sip voiplink instance */
        siplink = SIPVoIPLink::instance("");     
        if (siplink->new_ip_to_ip_call (id, to)) {
            switchCall (id);
            return true;
        }
        else {
            callFailure (id);
        }
        return false;
    } 
223

Emmanuel Milou's avatar
Emmanuel Milou committed
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
    if (!accountExists(accountid)) {
        _debug("! Manager Error: Outgoing Call: account doesn't exist\n");
        return false;
    }
  
    if (getAccountFromCall(id) != AccountNULL) {
        _debug("! Manager Error: Outgoing Call: call id already exists\n");
        return false;
    }
  
    if (hasCurrentCall()) {
        _debug("* Manager Info: there is currently a call, try to hold it\n");
        onHoldCall(getCurrentCallId());
    }
  
    _debug("- Manager Action: Adding Outgoing Call %s on account %s\n", id.data(), accountid.data());
yanmorin's avatar
   
yanmorin committed
240
    associateCallToAccount( id, accountid );
Emmanuel Milou's avatar
Emmanuel Milou committed
241
242
243
244
245
246
247
248
    if ( getAccountLink(accountid)->newOutgoingCall(id, to) ) {
        switchCall(id);
        return true;
    } else {
        callFailure(id);
        _debug("! Manager Error: An error occur, the call was not created\n");
    }
    return false;
jpbl's avatar
jpbl committed
249
250
}

yanmorin's avatar
   
yanmorin committed
251
//THREAD=Main : for outgoing Call
252
  bool
yanmorin's avatar
   
yanmorin committed
253
ManagerImpl::answerCall(const CallID& id)
jpbl's avatar
jpbl committed
254
{
255
256
  bool isActive = false;

257
258
  stopTone(true);

259
260
261
262
263
264
  AccountID currentaccountid = getAccountFromCall( id );
  Call* currentcall = getAccountLink(currentaccountid)->getCall(getCurrentCallId());
  _debug("ManagerImpl::answerCall :: current call->getState %i \n",currentcall->getState());

  if (currentcall->getState() == 1)
      isActive = true;
265

Emmanuel Milou's avatar
Emmanuel Milou committed
266
  // stopTone(false); 
267
  _debug("Try to answer call: %s\n", id.data());
yanmorin's avatar
   
yanmorin committed
268
269
270
271
  AccountID accountid = getAccountFromCall( id );
  if (accountid == AccountNULL) {
    _debug("Answering Call: Call doesn't exists\n");
    return false;
jpbl's avatar
jpbl committed
272
  }
273
274
275
  
  //  if (id != getCurrentCallId()) {
  if (isActive) { 
Yun Liu's avatar
Yun Liu committed
276
    _debug("* Manager Info: there is currently a call, try to hold it\n");
277

Yun Liu's avatar
Yun Liu committed
278
279
    onHoldCall(getCurrentCallId());
  }
280
  
Yun Liu's avatar
Yun Liu committed
281

yanmorin's avatar
   
yanmorin committed
282
283
284
285
  if (!getAccountLink(accountid)->answer(id)) {
    // error when receiving...
    removeCallAccount(id);
    return false;
jpbl's avatar
jpbl committed
286
  }
Alexandre Savard's avatar
Alexandre Savard committed
287

yanmorin's avatar
   
yanmorin committed
288
  // if it was waiting, it's waiting no more
289
  if (_dbus) _dbus->getCallManager()->callStateChanged(id, "CURRENT");
yanmorin's avatar
   
yanmorin committed
290
291
  removeWaitingCall(id);
  switchCall(id);
292
 
293
  // std::string codecName = getCurrentCodecName(id);
Emmanuel Milou's avatar
Emmanuel Milou committed
294
  // _debug("ManagerImpl::hangupCall(): broadcast codec name %s \n",codecName.c_str());
295
  // if (_dbus) _dbus->getCallManager()->currentSelectedCodec(id,codecName.c_str());
296

yanmorin's avatar
   
yanmorin committed
297
  return true;
jpbl's avatar
jpbl committed
298
299
}

yanmorin's avatar
   
yanmorin committed
300
//THREAD=Main
301
  bool
yanmorin's avatar
   
yanmorin committed
302
ManagerImpl::hangupCall(const CallID& id)
jpbl's avatar
jpbl committed
303
{
Alexandre Savard's avatar
Alexandre Savard committed
304
    _debug("ManagerImpl::hangupCall(): This function is called when user hangup \n");
305
306
307
    PulseLayer *pulselayer;
    AccountID accountid;
    bool returnValue;
Emmanuel Milou's avatar
Emmanuel Milou committed
308

309
    stopTone(false);
yanmorin's avatar
   
yanmorin committed
310

311
312
    /* Broadcast a signal over DBus */
    if (_dbus) _dbus->getCallManager()->callStateChanged(id, "HUNGUP");
Emmanuel Milou's avatar
Emmanuel Milou committed
313
314
315
316
    
    /* Direct IP to IP call */
    if (getConfigFromCall (id) == Call::IPtoIP) {
        returnValue = SIPVoIPLink::instance (AccountNULL)->hangup (id);        
317
    }
Emmanuel Milou's avatar
Emmanuel Milou committed
318

Emmanuel Milou's avatar
Emmanuel Milou committed
319
320
321
322
323
324
325
326
327
328
    /* Classic call, attached to an account */
    else { 
        accountid = getAccountFromCall( id );
        if (accountid == AccountNULL) {
            _debug("! Manager Hangup Call: Call doesn't exists\n");
            return false;
        }
        returnValue = getAccountLink(accountid)->hangup(id);
        removeCallAccount(id);
    }
329

330
    switchCall("");
331

332
333
334
335
336
337
    if( _audiodriver->getLayerType() == PULSEAUDIO && getConfigInt( PREFERENCES , CONFIG_PA_VOLUME_CTRL ) ) {
        pulselayer = dynamic_cast<PulseLayer *> (getAudioDriver());
        if(pulselayer)  pulselayer->restorePulseAppsVolume();
    }
  
    return returnValue;
jpbl's avatar
jpbl committed
338
339
}

yanmorin's avatar
   
yanmorin committed
340
//THREAD=Main
341
  bool
yanmorin's avatar
   
yanmorin committed
342
ManagerImpl::cancelCall (const CallID& id)
jpbl's avatar
jpbl committed
343
{
Emmanuel Milou's avatar
Emmanuel Milou committed
344
345
    AccountID accountid;
    bool returnValue;
yanmorin's avatar
   
yanmorin committed
346

Emmanuel Milou's avatar
Emmanuel Milou committed
347
    stopTone(true);
348

Emmanuel Milou's avatar
Emmanuel Milou committed
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
    /* Direct IP to IP call */
    if (getConfigFromCall (id) == Call::IPtoIP) {
        returnValue = SIPVoIPLink::instance (AccountNULL)->cancel (id);        
    }

    /* Classic call, attached to an account */
    else { 
        accountid = getAccountFromCall( id );
        if (accountid == AccountNULL) {
            _debug("! Manager Cancel Call: Call doesn't exists\n");
            return false;
        }
        returnValue = getAccountLink(accountid)->cancel(id);
        removeCallAccount(id);
    }
        
    // it could be a waiting call?
    removeWaitingCall(id);
    switchCall("");

    return returnValue;
jpbl's avatar
jpbl committed
370
371
}

yanmorin's avatar
   
yanmorin committed
372
//THREAD=Main
373
  bool
yanmorin's avatar
   
yanmorin committed
374
ManagerImpl::onHoldCall(const CallID& id)
jpbl's avatar
jpbl committed
375
{
Emmanuel Milou's avatar
Emmanuel Milou committed
376
377
    AccountID accountid;
    bool returnValue;
yanmorin's avatar
   
yanmorin committed
378

Emmanuel Milou's avatar
Emmanuel Milou committed
379
    stopTone(true);
380

Emmanuel Milou's avatar
Emmanuel Milou committed
381
382
383
384
    /* Direct IP to IP call */
    if (getConfigFromCall (id) == Call::IPtoIP) {
        returnValue = SIPVoIPLink::instance (AccountNULL)-> onhold (id);        
    }
385

Emmanuel Milou's avatar
Emmanuel Milou committed
386
387
388
389
390
391
392
393
394
    /* Classic call, attached to an account */
    else { 
        accountid = getAccountFromCall( id );
        if (accountid == AccountNULL) {
            _debug("Manager On Hold Call: Account ID %s or callid %s doesn't exists\n", accountid.c_str(), id.c_str());
            return false;
        }
        returnValue = getAccountLink(accountid)->onhold(id);
    }
395

Emmanuel Milou's avatar
Emmanuel Milou committed
396
397
398
399
    removeWaitingCall(id);
    switchCall("");
  
    if (_dbus) _dbus->getCallManager()->callStateChanged(id, "HOLD");
400

Emmanuel Milou's avatar
Emmanuel Milou committed
401
    return returnValue;
yanmorin's avatar
   
yanmorin committed
402
403
404
}

//THREAD=Main
405
  bool
yanmorin's avatar
   
yanmorin committed
406
407
ManagerImpl::offHoldCall(const CallID& id)
{
408
  
Emmanuel Milou's avatar
Emmanuel Milou committed
409
410
411
    AccountID accountid;
    bool returnValue, rec;
    std::string codecName;
412

Emmanuel Milou's avatar
Emmanuel Milou committed
413
    stopTone(false);
414

Emmanuel Milou's avatar
Emmanuel Milou committed
415
416
417
418
419
    //Place current call on hold if it isn't
    if (hasCurrentCall()) 
    { 
        onHoldCall(getCurrentCallId());
    }
420

Emmanuel Milou's avatar
Emmanuel Milou committed
421
422
423
424
425
    /* Direct IP to IP call */
    if (getConfigFromCall (id) == Call::IPtoIP) {
        rec = SIPVoIPLink::instance (AccountNULL)-> isRecording (id);
        returnValue = SIPVoIPLink::instance (AccountNULL)-> offhold (id);        
    }
alexandresavard's avatar
alexandresavard committed
426

Emmanuel Milou's avatar
Emmanuel Milou committed
427
428
429
430
431
432
433
434
435
436
437
    /* Classic call, attached to an account */
    else { 
        accountid = getAccountFromCall( id );
        if (accountid == AccountNULL) {
            _debug("Manager OffHold Call: Call doesn't exists\n");
            return false;
        }
        _debug("Setting OFFHOLD, Account %s, callid %s\n", accountid.c_str(), id.c_str());
        rec = getAccountLink(accountid)->isRecording(id);
        returnValue = getAccountLink(accountid)->offhold(id);
    }
alexandresavard's avatar
alexandresavard committed
438

Emmanuel Milou's avatar
Emmanuel Milou committed
439
    if (_dbus){ 
440
        /*if (rec)
Emmanuel Milou's avatar
Emmanuel Milou committed
441
442
443
            _dbus->getCallManager()->callStateChanged(id, "UNHOLD_RECORD");
        else 
            _dbus->getCallManager()->callStateChanged(id, "UNHOLD_CURRENT");
444
445
        */
        _dbus->getCallManager()->callStateChanged(id, "CURRENT");
Emmanuel Milou's avatar
Emmanuel Milou committed
446
447
448
    }
  
    switchCall(id);
449

450
    codecName = getCurrentCodecName(id);
451
    // _debug("ManagerImpl::hangupCall(): broadcast codec name %s \n",codecName.c_str());
452
    if (_dbus) _dbus->getCallManager()->currentSelectedCodec(id,codecName.c_str());
453

Emmanuel Milou's avatar
Emmanuel Milou committed
454
    return returnValue;
jpbl's avatar
jpbl committed
455
456
}

yanmorin's avatar
   
yanmorin committed
457
//THREAD=Main
458
  bool
yanmorin's avatar
   
yanmorin committed
459
ManagerImpl::transferCall(const CallID& id, const std::string& to)
jpbl's avatar
jpbl committed
460
{
Emmanuel Milou's avatar
Emmanuel Milou committed
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
    AccountID accountid;
    bool returnValue;
  
    stopTone(true);
  
    /* Direct IP to IP call */
    if (getConfigFromCall (id) == Call::IPtoIP) {
        returnValue = SIPVoIPLink::instance (AccountNULL)-> transfer (id, to);        
    }

    /* Classic call, attached to an account */
    else { 
        accountid = getAccountFromCall( id );
        if (accountid == AccountNULL) {
            _debug("! Manager Transfer Call: Call doesn't exists\n");
            return false;
        }
        returnValue = getAccountLink(accountid)->transfer(id, to);
        removeCallAccount(id);
    }
        
    removeWaitingCall(id);
    switchCall("");
  
    if (_dbus) _dbus->getCallManager()->callStateChanged(id, "HUNGUP");
    return returnValue;
jpbl's avatar
jpbl committed
487
488
}

yanmorin's avatar
   
yanmorin committed
489
//THREAD=Main : Call:Incoming
490
  bool
yanmorin's avatar
   
yanmorin committed
491
ManagerImpl::refuseCall (const CallID& id)
jpbl's avatar
jpbl committed
492
{
Emmanuel Milou's avatar
Emmanuel Milou committed
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
    AccountID accountid;
    bool returnValue;
  
    stopTone(true);

     /* Direct IP to IP call */
    if (getConfigFromCall (id) == Call::IPtoIP) {
        returnValue = SIPVoIPLink::instance (AccountNULL)-> refuse (id);        
    }

    /* Classic call, attached to an account */
    else { 
        accountid = getAccountFromCall( id );
        if (accountid == AccountNULL) {
            _debug("! Manager OffHold Call: Call doesn't exists\n");
            return false;
        }
        returnValue = getAccountLink(accountid)->refuse(id);
        removeCallAccount(id);
    } 
    
    // if the call was outgoing or established, we didn't refuse it
    // so the method did nothing
    if (returnValue) {
        removeWaitingCall(id);
        if (_dbus) _dbus->getCallManager()->callStateChanged(id, "HUNGUP");
        switchCall("");
    }
    return returnValue;
jpbl's avatar
jpbl committed
522
523
}

yanmorin's avatar
   
yanmorin committed
524
//THREAD=Main
525
  bool
jpbl's avatar
jpbl committed
526
527
528
529
530
531
532
533
534
535
ManagerImpl::saveConfig (void)
{
  _debug("Saving Configuration...\n");
  setConfig(AUDIO, VOLUME_SPKR, getSpkrVolume());
  setConfig(AUDIO, VOLUME_MICRO, getMicVolume());

  _setupLoaded = _config.saveConfigTree(_path.data());
  return _setupLoaded;
}

yanmorin's avatar
   
yanmorin committed
536
//THREAD=Main
537
 int 
538
ManagerImpl::initRegisterAccounts() 
jpbl's avatar
jpbl committed
539
{
540
    int status; 
541
    bool flag = true;
542
543
544
545
546
    AccountMap::iterator iter;

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

547
    /* Loop on the account map previously loaded */
548
    while( iter != _accountMap.end() ) {
549
550
551
552
553
554
555
556
557
        if ( iter->second ) {
            iter->second->loadConfig();
            /* If the account is set as enabled, try to register */
            if ( iter->second->isEnabled() ) {
	            status = iter->second->registerVoIPLink();
	            if (status != SUCCESS){
		            flag = false;
                }
            }
558
        }
559
        iter++;
Emmanuel Milou's avatar
Emmanuel Milou committed
560
    }
561

562
563
564
565
    // calls the client notification here in case of errors at startup...
    if( _audiodriver -> getErrorMessage() != -1 )
      notifyErrClient( _audiodriver -> getErrorMessage() );
    
566
    ASSERT( flag, true );
567
    return SUCCESS;
jpbl's avatar
jpbl committed
568
569
}

yanmorin's avatar
   
yanmorin committed
570
//THREAD=Main
571
  bool 
yanmorin's avatar
   
yanmorin committed
572
ManagerImpl::sendDtmf(const CallID& id, char code)
jpbl's avatar
jpbl committed
573
{
yanmorin's avatar
   
yanmorin committed
574
575
  AccountID accountid = getAccountFromCall( id );
  if (accountid == AccountNULL) {
Emmanuel Milou's avatar
Emmanuel Milou committed
576
577
    //_debug("Send DTMF: call doesn't exists\n");
    playDtmf(code, false);
yanmorin's avatar
   
yanmorin committed
578
579
580
    return false;
  }

jpbl's avatar
jpbl committed
581
  int sendType = getConfigInt(SIGNALISATION, SEND_DTMF_AS);
yanmorin's avatar
   
yanmorin committed
582
  bool returnValue = false;
jpbl's avatar
jpbl committed
583
  switch (sendType) {
584
    case 0: // SIP INFO
Emmanuel Milou's avatar
Emmanuel Milou committed
585
      playDtmf(code , true);
586
587
588
589
590
591
592
593
594
      returnValue = getAccountLink(accountid)->carryingDTMFdigits(id, code);
      break;

    case 1: // Audio way
      break;
    case 2: // rfc 2833
      break;
    default: // unknown - error config?
      break;
jpbl's avatar
jpbl committed
595
596
597
598
  }
  return returnValue;
}

yanmorin's avatar
   
yanmorin committed
599
//THREAD=Main | VoIPLink
600
  bool
Emmanuel Milou's avatar
Emmanuel Milou committed
601
ManagerImpl::playDtmf(char code, bool isTalking)
jpbl's avatar
jpbl committed
602
{
603
604
605
606
607
608
609
610
611
612
    int hasToPlayTone, pulselen, layer, size;
    bool ret = false;
    AudioLayer *audiolayer;
    SFLDataFormat *buf;
  
    stopTone(false);
    
    hasToPlayTone = getConfigInt(SIGNALISATION, PLAY_DTMF);
    if (!hasToPlayTone) 
        return false;
jpbl's avatar
jpbl committed
613

614
615
616
617
    // length in milliseconds
    pulselen = getConfigInt(SIGNALISATION, PULSE_LENGTH);
    if (!pulselen)
        return false;
jpbl's avatar
jpbl committed
618

619
620
621
622
    // numbers of int = length in milliseconds / 1000 (number of seconds)
    //                = number of seconds * SAMPLING_RATE by SECONDS
    audiolayer = getAudioDriver();
    layer = audiolayer->getLayerType();
jpbl's avatar
jpbl committed
623

624
625
626
    // fast return, no sound, so no dtmf
    if (audiolayer==0 || _dtmfKey == 0)
        return false;
627

628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
    // number of data sampling in one pulselen depends on samplerate
    // size (n sampling) = time_ms * sampling/s 
    //                     ---------------------
    //                            ms/s
    size = (int)(pulselen * ((float)audiolayer->getSampleRate()/1000));

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

    // Handle dtmf
    _dtmfKey->startTone(code);

    // copy the sound
    if ( _dtmfKey->generateDTMF(buf, size) ) {
        // Put buffer to urgentRingBuffer 
        // put the size in bytes...
        // so size * 1 channel (mono) * sizeof (bytes for the data)
646
        audiolayer->startStream();
647
648
649
        audiolayer->putUrgent (buf, size * sizeof(SFLDataFormat));
    }
    ret = true;
650

651
    // TODO Cache the DTMF
Emmanuel Milou's avatar
Emmanuel Milou committed
652

653
654
655
    delete[] buf; buf = 0;
    
    return ret;
jpbl's avatar
jpbl committed
656
657
}

yanmorin's avatar
   
yanmorin committed
658
// Multi-thread 
jpbl's avatar
jpbl committed
659
660
661
662
663
664
bool
ManagerImpl::incomingCallWaiting() {
  return (_nbIncomingWaitingCall > 0) ? true : false;
}

void
yanmorin's avatar
   
yanmorin committed
665
ManagerImpl::addWaitingCall(const CallID& id) {
666
  ost::MutexLock m(_waitingCallMutex);
yanmorin's avatar
   
yanmorin committed
667
  _waitingCall.insert(id);
jpbl's avatar
jpbl committed
668
669
670
671
  _nbIncomingWaitingCall++;
}

void
yanmorin's avatar
   
yanmorin committed
672
ManagerImpl::removeWaitingCall(const CallID& id) {
673
  ost::MutexLock m(_waitingCallMutex);
yanmorin's avatar
   
yanmorin committed
674
675
676
  // should return more than 1 if it erase a call
  if (_waitingCall.erase(id)) {
    _nbIncomingWaitingCall--;
jpbl's avatar
jpbl committed
677
678
679
680
  }
}

bool
yanmorin's avatar
   
yanmorin committed
681
682
683
684
ManagerImpl::isWaitingCall(const CallID& id) {
  CallIDSet::iterator iter = _waitingCall.find(id);
  if (iter != _waitingCall.end()) {
    return false;
jpbl's avatar
jpbl committed
685
  }
yanmorin's avatar
   
yanmorin committed
686
  return true;
jpbl's avatar
jpbl committed
687
688
}

yanmorin's avatar
   
yanmorin committed
689
690
691
692
///////////////////////////////////////////////////////////////////////////////
// Management of event peer IP-phone 
////////////////////////////////////////////////////////////////////////////////
// SipEvent Thread 
Alexandre Savard's avatar
Alexandre Savard committed
693
bool 
yanmorin's avatar
   
yanmorin committed
694
ManagerImpl::incomingCall(Call* call, const AccountID& accountId) 
jpbl's avatar
jpbl committed
695
{
696
697
    PulseLayer *pulselayer;
    std::string from, number;
698

699
700
    stopTone(true);

701
    _debug("Incoming call %s\n", call->getCallId().data());
702

703
    associateCallToAccount(call->getCallId(), accountId);
jpbl's avatar
jpbl committed
704

705
706
    _debug("ManagerImpl::incomingCall :: hasCurrentCall() %i \n",hasCurrentCall());

707
708
709
710
    if ( !hasCurrentCall() ) {
        call->setConnectionState(Call::Ringing);
        ringtone();
        switchCall(call->getCallId());
711
712
713
714
    
    }
    /* 
    else {
715
716
        addWaitingCall(call->getCallId());
    }
717
718
719
    */

    addWaitingCall(call->getCallId());
720
721
722
723
724
725
726
727
728
729
730
731
732

    from = call->getPeerName();
    number = call->getPeerNumber();

    if (from != "" && number != "") {
        from.append(" <");
        from.append(number);
        from.append(">");
    } else if ( from.empty() ) {
        from.append("<");
        from.append(number);
        from.append(">");
    }
733
734
735
736
737
738
739
740
741

    /*
    CallIDSet::iterator iter = _waitingCall.begin();
    while (iter != _waitingCall.end()) {
        CallID ident = *iter;
        _debug("ManagerImpl::incomingCall :: CALL iteration: %s \n",ident.c_str());
        ++iter;
    }
    */
742
  
743
    /* Broadcast a signal over DBus */
744
745
    if (_dbus) _dbus->getCallManager()->incomingCall(accountId, call->getCallId(), from);

746
    //if (_dbus) _dbus->getCallManager()->callStateChanged(call->getCallId(), "INCOMING");
747
  
748
749
750
751
752
    // Reduce volume of the other pulseaudio-connected audio applications
    if( _audiodriver->getLayerType() == PULSEAUDIO && getConfigInt( PREFERENCES , CONFIG_PA_VOLUME_CTRL ) ) {
        pulselayer = dynamic_cast<PulseLayer *> (getAudioDriver());
        if(pulselayer)  pulselayer->reducePulseAppsVolume();
    }
753
  
754
    return true;
jpbl's avatar
jpbl committed
755
756
}

yanmorin's avatar
   
yanmorin committed
757
758
759
//THREAD=VoIP
void
ManagerImpl::incomingMessage(const AccountID& accountId, const std::string& message) {
760
761
  if (_dbus) {
    _dbus->getCallManager()->incomingMessage(accountId, message);
jpbl's avatar
jpbl committed
762
763
764
  }
}

yanmorin's avatar
   
yanmorin committed
765
//THREAD=VoIP CALL=Outgoing
766
  void
yanmorin's avatar
   
yanmorin committed
767
ManagerImpl::peerAnsweredCall(const CallID& id)
jpbl's avatar
jpbl committed
768
{
Emmanuel Milou's avatar
Emmanuel Milou committed
769
770
771
772
773
    if (isCurrentCall(id)) {
        stopTone(false);
    }
  
    if (_dbus) _dbus->getCallManager()->callStateChanged(id, "CURRENT");
Alexandre Savard's avatar
Alexandre Savard committed
774
775
  
  std::string codecName = getCurrentCodecName(id);
Emmanuel Milou's avatar
Emmanuel Milou committed
776
  // _debug("ManagerImpl::hangupCall(): broadcast codec name %s \n",codecName.c_str());
Alexandre Savard's avatar
Alexandre Savard committed
777
  if (_dbus) _dbus->getCallManager()->currentSelectedCodec(id,codecName.c_str());
jpbl's avatar
jpbl committed
778
779
}

yanmorin's avatar
   
yanmorin committed
780
//THREAD=VoIP Call=Outgoing
781
  void
yanmorin's avatar
   
yanmorin committed
782
ManagerImpl::peerRingingCall(const CallID& id)
jpbl's avatar
jpbl committed
783
{
yanmorin's avatar
   
yanmorin committed
784
  if (isCurrentCall(id)) {
jpbl's avatar
jpbl committed
785
786
    ringback();
  }
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
787
  if (_dbus) _dbus->getCallManager()->callStateChanged(id, "RINGING");
jpbl's avatar
jpbl committed
788
789
}

yanmorin's avatar
   
yanmorin committed
790
//THREAD=VoIP Call=Outgoing/Ingoing
791
  void
yanmorin's avatar
   
yanmorin committed
792
ManagerImpl::peerHungupCall(const CallID& id)
jpbl's avatar
jpbl committed
793
{
794
795
    PulseLayer *pulselayer;
    AccountID accountid;
796
    bool returnValue;
797
798
799
800
801
802

    accountid = getAccountFromCall( id );
    if (accountid == AccountNULL) {
        _debug("peerHungupCall: Call doesn't exists\n");
        return;
    }
Emmanuel Milou's avatar
Emmanuel Milou committed
803
  
804
805
806
807
808
809
810
811
    /* Broadcast a signal over DBus */
    if (_dbus) _dbus->getCallManager()->callStateChanged(id, "HUNGUP");
    
    if (isCurrentCall(id)) {
        stopTone(true);
        switchCall("");
    }

812
    returnValue = getAccountLink(accountid)->peerHungup(id);
813

814
815
    removeWaitingCall(id);
    removeCallAccount(id);
Emmanuel Milou's avatar
Emmanuel Milou committed
816
  
817
818
819
820
    if( _audiodriver->getLayerType() == PULSEAUDIO && getConfigInt( PREFERENCES , CONFIG_PA_VOLUME_CTRL ) ) {
        pulselayer = dynamic_cast<PulseLayer *> (getAudioDriver());
        if(pulselayer)  pulselayer->restorePulseAppsVolume();
    }
jpbl's avatar
jpbl committed
821
822
}

yanmorin's avatar
   
yanmorin committed
823
//THREAD=VoIP
jpbl's avatar
jpbl committed
824
void
yanmorin's avatar
   
yanmorin committed
825
826
ManagerImpl::callBusy(const CallID& id) {
  _debug("Call busy\n");
827

828
  if (_dbus) _dbus->getCallManager()->callStateChanged(id, "BUSY");
yanmorin's avatar
   
yanmorin committed
829
830
831
  if (isCurrentCall(id) ) {
    playATone(Tone::TONE_BUSY);
    switchCall("");
jpbl's avatar
jpbl committed
832
  }
yanmorin's avatar
   
yanmorin committed
833
834
  removeCallAccount(id);
  removeWaitingCall(id);
jpbl's avatar
jpbl committed
835
836
}

yanmorin's avatar
   
yanmorin committed
837
//THREAD=VoIP
838
  void
yanmorin's avatar
   
yanmorin committed
839
840
ManagerImpl::callFailure(const CallID& id) 
{
841
  if (_dbus) _dbus->getCallManager()->callStateChanged(id, "FAILURE");
Emmanuel Milou's avatar
Emmanuel Milou committed
842
  _debug("CALL ID = %s\n" , id.c_str());
yanmorin's avatar
   
yanmorin committed
843
844
845
846
847
848
  if (isCurrentCall(id) ) {
    playATone(Tone::TONE_BUSY);
    switchCall("");
  }
  removeCallAccount(id);
  removeWaitingCall(id);
849

jpbl's avatar
jpbl committed
850
851
}

yanmorin's avatar
   
yanmorin committed
852
//THREAD=VoIP
853
  void
Emmanuel Milou's avatar
Emmanuel Milou committed
854
ManagerImpl::startVoiceMessageNotification(const AccountID& accountId, int nb_msg)
jpbl's avatar
jpbl committed
855
{
Emmanuel Milou's avatar
Emmanuel Milou committed
856
  if (_dbus) _dbus->getCallManager()->voiceMailNotify(accountId, nb_msg) ;
jpbl's avatar
jpbl committed
857
858
}

859
void ManagerImpl::connectionStatusNotification(  )
860
{
861
862
863
864
    if (_dbus)
        _dbus->getConfigurationManager()->accountsChanged();
    else
        _debug("Error: DBus connection not found\n");
Emmanuel Milou's avatar
nothing    
Emmanuel Milou committed
865
866
}

jpbl's avatar
jpbl committed
867
868
869
/**
 * Multi Thread
 */
870
871
872
873
874
875
bool ManagerImpl::playATone(Tone::TONEID toneId) 
{
    int hasToPlayTone;
    AudioLoop *audioloop;
    AudioLayer *audiolayer;
    unsigned int nbSamples;
yanmorin's avatar
   
yanmorin committed
876

877
878
879
880
881
    hasToPlayTone = getConfigInt(SIGNALISATION, PLAY_TONES);
    if (!hasToPlayTone) 
        return false;
    
    audiolayer = getAudioDriver();
882
   
883
884
885
886
887
888
889
890
891
892
893
894
895
    if (_telephoneTone != 0) {
        _toneMutex.enterMutex();
        _telephoneTone->setCurrentTone(toneId);
        _toneMutex.leaveMutex();

        audioloop = getTelephoneTone();
        nbSamples = audioloop->getSize();
        SFLDataFormat buf[nbSamples];
    
        if ( audiolayer ){ 
            audiolayer->putUrgent( buf, nbSamples );
        } else 
            return false;
jpbl's avatar
jpbl committed
896
  }
897
  return true;
jpbl's avatar
jpbl committed
898
899
900
901
902
}

/**
 * Multi Thread
 */
903
904
905
906
void ManagerImpl::stopTone (bool stopAudio=true)
{
    int hasToPlayTone;
    AudioLayer *audiolayer;
yanmorin's avatar
   
yanmorin committed
907

908
909
910
    hasToPlayTone = getConfigInt(SIGNALISATION, PLAY_TONES);
    if (!hasToPlayTone) 
        return;
911

912
913
914
915
    if (stopAudio) {
        audiolayer = getAudioDriver();
        if (audiolayer) audiolayer->stopStream();
    }
jpbl's avatar
jpbl committed
916

917
918
919
920
921
    _toneMutex.enterMutex();
    if (_telephoneTone != 0) {
        _telephoneTone->setCurrentTone(Tone::TONE_NULL);
    }
    _toneMutex.leaveMutex();
jpbl's avatar
jpbl committed
922

923
924
925
926
    // for ringing tone..
    _toneMutex.enterMutex();
    _audiofile.stop();
    _toneMutex.leaveMutex();
jpbl's avatar
jpbl committed
927
928
929
930
931
}

/**
 * Multi Thread
 */
932
  bool
jpbl's avatar
jpbl committed
933
934
ManagerImpl::playTone()
{
935
  playATone(Tone::TONE_DIALTONE);
Yun Liu's avatar
Yun Liu committed
936
  return true;
jpbl's avatar
jpbl committed
937
938
}

939
940
941
942
943
944
945
/**
 * Multi Thread
 */
  bool
ManagerImpl::playToneWithMessage()
{
  playATone(Tone::TONE_CONGESTION);
Yun Liu's avatar
Yun Liu committed
946
  return true;
947
948
}

jpbl's avatar
jpbl committed
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
/**
 * Multi Thread
 */
void
ManagerImpl::congestion () {
  playATone(Tone::TONE_CONGESTION);
}

/**
 * Multi Thread
 */
void
ManagerImpl::ringback () {
  playATone(Tone::TONE_RINGTONE);
}

/**
 * Multi Thread
 */
968
  void
jpbl's avatar
jpbl committed
969
970
ManagerImpl::ringtone() 
{
971
972
973
974
975
976
    std::string ringchoice;
    AudioLayer *audiolayer;
    AudioCodec *codecForTone;
    int layer, samplerate;
    bool loadFile;

977
978
    // stopTone(true);

979
980
981
982
983
    if( isRingtoneEnabled() )
    {
        //TODO Comment this because it makes the daemon crashes since the main thread
        //synchronizes the ringtone thread.
        
984
        ringchoice = getConfigString(AUDIO, RING_CHOICE);
985
986
987
988
989
990
        //if there is no / inside the path
        if ( ringchoice.find(DIR_SEPARATOR_CH) == std::string::npos ) {
            // check inside global share directory
            ringchoice = std::string(PROGSHAREDIR) + DIR_SEPARATOR_STR + RINGDIR + DIR_SEPARATOR_STR + ringchoice; 
        }

991
992
993
994
995
        audiolayer = getAudioDriver();
        layer = audiolayer->getLayerType();
        if (audiolayer == 0)
            return;

996

997
998
        samplerate  = audiolayer->getSampleRate();
        codecForTone = _codecDescriptorMap.getFirstCodecAvailable();
Emmanuel Milou's avatar
Emmanuel Milou committed
999

1000
        _toneMutex.enterMutex();