managerimpl.cpp 69.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)))

56
ManagerImpl::ManagerImpl (void)
Yun Liu's avatar
Yun Liu committed
57
58
59
	: _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
}

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

108
109
  void
ManagerImpl::init()
jpbl's avatar
jpbl committed
110
{
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
}

178
const CallID&
yanmorin's avatar
   
yanmorin committed
179
180
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
///////////////////////////////////////////////////////////////////////////////
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
    std::string pattern;
    Call::CallConfiguration callConfig;
    SIPVoIPLink *siplink;
201

202
203
    _debug("ManagerImpl::outgoingCall() method \n");

Emmanuel Milou's avatar
Emmanuel Milou committed
204
205
206
207
208
    // stopTone(false);
    // playTone();

    /* Check what kind of call we are dealing with */
    check_call_configuration (id, to, &callConfig);
209

Emmanuel Milou's avatar
Emmanuel Milou committed
210
211
212
    if (callConfig == Call::IPtoIP) {
        _debug ("Start IP to IP call\n");
        /* We need to retrieve the sip voiplink instance */
213
        siplink = SIPVoIPLink::instance("");
Emmanuel Milou's avatar
Emmanuel Milou committed
214
215
216
217
218
219
220
221
        if (siplink->new_ip_to_ip_call (id, to)) {
            switchCall (id);
            return true;
        }
        else {
            callFailure (id);
        }
        return false;
222
    }
223

Emmanuel Milou's avatar
Emmanuel Milou committed
224
225
226
227
    if (!accountExists(accountid)) {
        _debug("! Manager Error: Outgoing Call: account doesn't exist\n");
        return false;
    }
228

Emmanuel Milou's avatar
Emmanuel Milou committed
229
230
231
232
    if (getAccountFromCall(id) != AccountNULL) {
        _debug("! Manager Error: Outgoing Call: call id already exists\n");
        return false;
    }
233

Emmanuel Milou's avatar
Emmanuel Milou committed
234
235
236
237
    if (hasCurrentCall()) {
        _debug("* Manager Info: there is currently a call, try to hold it\n");
        onHoldCall(getCurrentCallId());
    }
238

Emmanuel Milou's avatar
Emmanuel Milou committed
239
    _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

266
  // stopTone(false);
267
  _debug("Try to answer call: %s\n", id.data());
yanmorin's avatar
   
yanmorin committed
268
269
270
  AccountID accountid = getAccountFromCall( id );
  if (accountid == AccountNULL) {
    _debug("Answering Call: Call doesn't exists\n");
271
    //return false;
jpbl's avatar
jpbl committed
272
  }
273

274
  //  if (id != getCurrentCallId()) {
275
  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

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

yanmorin's avatar
   
yanmorin committed
287
  // if it was waiting, it's waiting no more
288
  if (_dbus) _dbus->getCallManager()->callStateChanged(id, "CURRENT");
yanmorin's avatar
   
yanmorin committed
289
290
  removeWaitingCall(id);
  switchCall(id);
291

292
  // std::string codecName = getCurrentCodecName(id);
Emmanuel Milou's avatar
Emmanuel Milou committed
293
  // _debug("ManagerImpl::hangupCall(): broadcast codec name %s \n",codecName.c_str());
294
  // if (_dbus) _dbus->getCallManager()->currentSelectedCodec(id,codecName.c_str());
295

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

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

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

310
311
    /* Broadcast a signal over DBus */
    if (_dbus) _dbus->getCallManager()->callStateChanged(id, "HUNGUP");
312

Emmanuel Milou's avatar
Emmanuel Milou committed
313
314
    /* Direct IP to IP call */
    if (getConfigFromCall (id) == Call::IPtoIP) {
315
        returnValue = SIPVoIPLink::instance (AccountNULL)->hangup (id);
316
    }
Emmanuel Milou's avatar
Emmanuel Milou committed
317

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

329
    switchCall("");
330

331
332
333
334
    if( _audiodriver->getLayerType() == PULSEAUDIO && getConfigInt( PREFERENCES , CONFIG_PA_VOLUME_CTRL ) ) {
        pulselayer = dynamic_cast<PulseLayer *> (getAudioDriver());
        if(pulselayer)  pulselayer->restorePulseAppsVolume();
    }
335

336
    return returnValue;
jpbl's avatar
jpbl committed
337
338
}

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

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

Emmanuel Milou's avatar
Emmanuel Milou committed
348
349
    /* Direct IP to IP call */
    if (getConfigFromCall (id) == Call::IPtoIP) {
350
        returnValue = SIPVoIPLink::instance (AccountNULL)->cancel (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
351
352
353
    }

    /* Classic call, attached to an account */
354
    else {
Emmanuel Milou's avatar
Emmanuel Milou committed
355
356
357
358
359
360
361
362
        accountid = getAccountFromCall( id );
        if (accountid == AccountNULL) {
            _debug("! Manager Cancel Call: Call doesn't exists\n");
            return false;
        }
        returnValue = getAccountLink(accountid)->cancel(id);
        removeCallAccount(id);
    }
363

Emmanuel Milou's avatar
Emmanuel Milou committed
364
365
366
367
368
    // it could be a waiting call?
    removeWaitingCall(id);
    switchCall("");

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

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

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

381
382
    call_id = id;

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

Emmanuel Milou's avatar
Emmanuel Milou committed
388
    /* Classic call, attached to an account */
389
    else {
Emmanuel Milou's avatar
Emmanuel Milou committed
390
391
392
393
394
395
396
        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);
    }
397

Emmanuel Milou's avatar
Emmanuel Milou committed
398
399
    removeWaitingCall(id);
    switchCall("");
400

401
    if (_dbus) _dbus->getCallManager()->callStateChanged(call_id, "HOLD");
402

Emmanuel Milou's avatar
Emmanuel Milou committed
403
    return returnValue;
yanmorin's avatar
   
yanmorin committed
404
405
406
}

//THREAD=Main
407
  bool
yanmorin's avatar
   
yanmorin committed
408
409
ManagerImpl::offHoldCall(const CallID& id)
{
410

Emmanuel Milou's avatar
Emmanuel Milou committed
411
412
413
    AccountID accountid;
    bool returnValue, rec;
    std::string codecName;
414
    CallID call_id;
415

Emmanuel Milou's avatar
Emmanuel Milou committed
416
    stopTone(false);
417

418
    call_id = id;
Emmanuel Milou's avatar
Emmanuel Milou committed
419
    //Place current call on hold if it isn't
420
421
    if (hasCurrentCall())
    {
422
        _debug ("Put the current call (ID=%s) on hold\n", getCurrentCallId().c_str());
Emmanuel Milou's avatar
Emmanuel Milou committed
423
424
        onHoldCall(getCurrentCallId());
    }
425

Emmanuel Milou's avatar
Emmanuel Milou committed
426
427
428
    /* Direct IP to IP call */
    if (getConfigFromCall (id) == Call::IPtoIP) {
        rec = SIPVoIPLink::instance (AccountNULL)-> isRecording (id);
429
        returnValue = SIPVoIPLink::instance (AccountNULL)-> offhold (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
430
    }
alexandresavard's avatar
alexandresavard committed
431

Emmanuel Milou's avatar
Emmanuel Milou committed
432
    /* Classic call, attached to an account */
433
    else {
Emmanuel Milou's avatar
Emmanuel Milou committed
434
435
436
437
438
439
440
441
442
        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
443

444
    if (_dbus){
Emmanuel Milou's avatar
Emmanuel Milou committed
445
        if (rec)
446
            _dbus->getCallManager()->callStateChanged(call_id, "UNHOLD_RECORD");
447
        else
448
            _dbus->getCallManager()->callStateChanged(call_id, "UNHOLD_CURRENT");
Emmanuel Milou's avatar
Emmanuel Milou committed
449
    }
450

Emmanuel Milou's avatar
Emmanuel Milou committed
451
    switchCall(id);
452

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

Emmanuel Milou's avatar
Emmanuel Milou committed
457
    return returnValue;
jpbl's avatar
jpbl committed
458
459
}

yanmorin's avatar
   
yanmorin committed
460
//THREAD=Main
461
  bool
yanmorin's avatar
   
yanmorin committed
462
ManagerImpl::transferCall(const CallID& id, const std::string& to)
jpbl's avatar
jpbl committed
463
{
Emmanuel Milou's avatar
Emmanuel Milou committed
464
465
    AccountID accountid;
    bool returnValue;
466

Emmanuel Milou's avatar
Emmanuel Milou committed
467
    stopTone(true);
468

Emmanuel Milou's avatar
Emmanuel Milou committed
469
470
    /* Direct IP to IP call */
    if (getConfigFromCall (id) == Call::IPtoIP) {
471
        returnValue = SIPVoIPLink::instance (AccountNULL)-> transfer (id, to);
Emmanuel Milou's avatar
Emmanuel Milou committed
472
473
474
    }

    /* Classic call, attached to an account */
475
    else {
Emmanuel Milou's avatar
Emmanuel Milou committed
476
477
478
479
480
481
482
483
        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);
    }
484

Emmanuel Milou's avatar
Emmanuel Milou committed
485
486
    removeWaitingCall(id);
    switchCall("");
487

Emmanuel Milou's avatar
Emmanuel Milou committed
488
489
    if (_dbus) _dbus->getCallManager()->callStateChanged(id, "HUNGUP");
    return returnValue;
jpbl's avatar
jpbl committed
490
491
}

yanmorin's avatar
   
yanmorin committed
492
//THREAD=Main : Call:Incoming
493
  bool
yanmorin's avatar
   
yanmorin committed
494
ManagerImpl::refuseCall (const CallID& id)
jpbl's avatar
jpbl committed
495
{
Emmanuel Milou's avatar
Emmanuel Milou committed
496
497
    AccountID accountid;
    bool returnValue;
498

Emmanuel Milou's avatar
Emmanuel Milou committed
499
500
501
502
    stopTone(true);

     /* Direct IP to IP call */
    if (getConfigFromCall (id) == Call::IPtoIP) {
503
        returnValue = SIPVoIPLink::instance (AccountNULL)-> refuse (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
504
505
506
    }

    /* Classic call, attached to an account */
507
    else {
Emmanuel Milou's avatar
Emmanuel Milou committed
508
509
510
511
512
513
514
        accountid = getAccountFromCall( id );
        if (accountid == AccountNULL) {
            _debug("! Manager OffHold Call: Call doesn't exists\n");
            return false;
        }
        returnValue = getAccountLink(accountid)->refuse(id);
        removeCallAccount(id);
515
516
    }

Emmanuel Milou's avatar
Emmanuel Milou committed
517
518
519
520
521
522
523
524
    // 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
525
526
}

yanmorin's avatar
   
yanmorin committed
527
//THREAD=Main
528
  bool
jpbl's avatar
jpbl committed
529
530
531
532
533
534
535
536
537
538
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
539
//THREAD=Main
540
541
 int
ManagerImpl::initRegisterAccounts()
jpbl's avatar
jpbl committed
542
{
543
    int status;
544
    bool flag = true;
545
546
547
548
549
    AccountMap::iterator iter;

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

550
    /* Loop on the account map previously loaded */
551
    while( iter != _accountMap.end() ) {
552
553
554
555
556
557
558
559
560
        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;
                }
            }
561
        }
562
        iter++;
Emmanuel Milou's avatar
Emmanuel Milou committed
563
    }
564

565
566
567
    // calls the client notification here in case of errors at startup...
    if( _audiodriver -> getErrorMessage() != -1 )
      notifyErrClient( _audiodriver -> getErrorMessage() );
568

569
    ASSERT( flag, true );
570
    return SUCCESS;
jpbl's avatar
jpbl committed
571
572
}

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

jpbl's avatar
jpbl committed
584
  int sendType = getConfigInt(SIGNALISATION, SEND_DTMF_AS);
yanmorin's avatar
   
yanmorin committed
585
  bool returnValue = false;
jpbl's avatar
jpbl committed
586
  switch (sendType) {
587
    case 0: // SIP INFO
Emmanuel Milou's avatar
Emmanuel Milou committed
588
      playDtmf(code , true);
589
590
591
592
593
594
595
596
597
      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
598
599
600
601
  }
  return returnValue;
}

yanmorin's avatar
   
yanmorin committed
602
//THREAD=Main | VoIPLink
603
  bool
Emmanuel Milou's avatar
Emmanuel Milou committed
604
ManagerImpl::playDtmf(char code, bool isTalking)
jpbl's avatar
jpbl committed
605
{
606
607
608
609
    int hasToPlayTone, pulselen, layer, size;
    bool ret = false;
    AudioLayer *audiolayer;
    SFLDataFormat *buf;
610

611
    stopTone(false);
612

613
    hasToPlayTone = getConfigInt(SIGNALISATION, PLAY_DTMF);
614
    if (!hasToPlayTone)
615
        return false;
jpbl's avatar
jpbl committed
616

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

622
623
624
625
    // 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
626

627
628
629
    // fast return, no sound, so no dtmf
    if (audiolayer==0 || _dtmfKey == 0)
        return false;
630

631
    // number of data sampling in one pulselen depends on samplerate
632
    // size (n sampling) = time_ms * sampling/s
633
634
635
636
637
638
639
640
641
642
643
644
645
    //                     ---------------------
    //                            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) ) {
646
        // Put buffer to urgentRingBuffer
647
648
        // put the size in bytes...
        // so size * 1 channel (mono) * sizeof (bytes for the data)
649
        audiolayer->startStream();
650
651
652
        audiolayer->putUrgent (buf, size * sizeof(SFLDataFormat));
    }
    ret = true;
653

654
    // TODO Cache the DTMF
Emmanuel Milou's avatar
Emmanuel Milou committed
655

656
    delete[] buf; buf = 0;
657

658
    return ret;
jpbl's avatar
jpbl committed
659
660
}

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

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

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

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

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

702
703
    stopTone(true);

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

706
    associateCallToAccount(call->getCallId(), accountId);
jpbl's avatar
jpbl committed
707

708
709
710
    if (accountId==AccountNULL)
        associateConfigToCall (call->getCallId(), Call::IPtoIP);

711
712
    _debug("ManagerImpl::incomingCall :: hasCurrentCall() %i \n",hasCurrentCall());

713
714
715
716
    if ( !hasCurrentCall() ) {
        call->setConnectionState(Call::Ringing);
        ringtone();
        switchCall(call->getCallId());
717

718
    }
719
    /*
720
    else {
721
722
        addWaitingCall(call->getCallId());
    }
723
724
725
    */

    addWaitingCall(call->getCallId());
726
727
728
729
730
731
732
733
734
735
736
737
738

    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(">");
    }
739
740
741
742
743
744
745
746
747

    /*
    CallIDSet::iterator iter = _waitingCall.begin();
    while (iter != _waitingCall.end()) {
        CallID ident = *iter;
        _debug("ManagerImpl::incomingCall :: CALL iteration: %s \n",ident.c_str());
        ++iter;
    }
    */
748

749
    /* Broadcast a signal over DBus */
750
751
    if (_dbus) _dbus->getCallManager()->incomingCall(accountId, call->getCallId(), from);

752
    //if (_dbus) _dbus->getCallManager()->callStateChanged(call->getCallId(), "INCOMING");
753

754
755
756
757
758
    // 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();
    }
759

760
    return true;
jpbl's avatar
jpbl committed
761
762
}

yanmorin's avatar
   
yanmorin committed
763
764
765
//THREAD=VoIP
void
ManagerImpl::incomingMessage(const AccountID& accountId, const std::string& message) {
766
767
  if (_dbus) {
    _dbus->getCallManager()->incomingMessage(accountId, message);
jpbl's avatar
jpbl committed
768
769
770
  }
}

yanmorin's avatar
   
yanmorin committed
771
//THREAD=VoIP CALL=Outgoing
772
  void
yanmorin's avatar
   
yanmorin committed
773
ManagerImpl::peerAnsweredCall(const CallID& id)
jpbl's avatar
jpbl committed
774
{
Emmanuel Milou's avatar
Emmanuel Milou committed
775
776
777
    if (isCurrentCall(id)) {
        stopTone(false);
    }
778

Emmanuel Milou's avatar
Emmanuel Milou committed
779
    if (_dbus) _dbus->getCallManager()->callStateChanged(id, "CURRENT");
780

Alexandre Savard's avatar
Alexandre Savard committed
781
  std::string codecName = getCurrentCodecName(id);
Emmanuel Milou's avatar
Emmanuel Milou committed
782
  // _debug("ManagerImpl::hangupCall(): broadcast codec name %s \n",codecName.c_str());
Alexandre Savard's avatar
Alexandre Savard committed
783
  if (_dbus) _dbus->getCallManager()->currentSelectedCodec(id,codecName.c_str());
jpbl's avatar
jpbl committed
784
785
}

yanmorin's avatar
   
yanmorin committed
786
//THREAD=VoIP Call=Outgoing
787
  void
yanmorin's avatar
   
yanmorin committed
788
ManagerImpl::peerRingingCall(const CallID& id)
jpbl's avatar
jpbl committed
789
{
yanmorin's avatar
   
yanmorin committed
790
  if (isCurrentCall(id)) {
jpbl's avatar
jpbl committed
791
792
    ringback();
  }
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
793
  if (_dbus) _dbus->getCallManager()->callStateChanged(id, "RINGING");
jpbl's avatar
jpbl committed
794
795
}

yanmorin's avatar
   
yanmorin committed
796
//THREAD=VoIP Call=Outgoing/Ingoing
797
  void
yanmorin's avatar
   
yanmorin committed
798
ManagerImpl::peerHungupCall(const CallID& id)
jpbl's avatar
jpbl committed
799
{
800
801
    PulseLayer *pulselayer;
    AccountID accountid;
802
    bool returnValue;
803
804
805
806
807
808

    accountid = getAccountFromCall( id );
    if (accountid == AccountNULL) {
        _debug("peerHungupCall: Call doesn't exists\n");
        return;
    }
809

810
811
    /* Broadcast a signal over DBus */
    if (_dbus) _dbus->getCallManager()->callStateChanged(id, "HUNGUP");
812

813
814
815
816
817
    if (isCurrentCall(id)) {
        stopTone(true);
        switchCall("");
    }

818
    returnValue = getAccountLink(accountid)->peerHungup(id);
819

820
821
    removeWaitingCall(id);
    removeCallAccount(id);
822

823
824
825
826
    if( _audiodriver->getLayerType() == PULSEAUDIO && getConfigInt( PREFERENCES , CONFIG_PA_VOLUME_CTRL ) ) {
        pulselayer = dynamic_cast<PulseLayer *> (getAudioDriver());
        if(pulselayer)  pulselayer->restorePulseAppsVolume();
    }
jpbl's avatar
jpbl committed
827
828
}

yanmorin's avatar
   
yanmorin committed
829
//THREAD=VoIP
jpbl's avatar
jpbl committed
830
void
yanmorin's avatar
   
yanmorin committed
831
832
ManagerImpl::callBusy(const CallID& id) {
  _debug("Call busy\n");
833

834
  if (_dbus) _dbus->getCallManager()->callStateChanged(id, "BUSY");
yanmorin's avatar
   
yanmorin committed
835
836
837
  if (isCurrentCall(id) ) {
    playATone(Tone::TONE_BUSY);
    switchCall("");
jpbl's avatar
jpbl committed
838
  }
yanmorin's avatar
   
yanmorin committed
839
840
  removeCallAccount(id);
  removeWaitingCall(id);
jpbl's avatar
jpbl committed
841
842
}

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

jpbl's avatar
jpbl committed
856
857
}

yanmorin's avatar
   
yanmorin committed
858
//THREAD=VoIP
859
  void
Emmanuel Milou's avatar
Emmanuel Milou committed
860
ManagerImpl::startVoiceMessageNotification(const AccountID& accountId, int nb_msg)
jpbl's avatar
jpbl committed
861
{
Emmanuel Milou's avatar
Emmanuel Milou committed
862
  if (_dbus) _dbus->getCallManager()->voiceMailNotify(accountId, nb_msg) ;
jpbl's avatar
jpbl committed
863
864
}

865
void ManagerImpl::connectionStatusNotification(  )
866
{
867
868
    if (_dbus)
        _dbus->getConfigurationManager()->accountsChanged();
Emmanuel Milou's avatar
nothing    
Emmanuel Milou committed
869
870
}

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

881
    hasToPlayTone = getConfigInt(SIGNALISATION, PLAY_TONES);
Julien Bonjean's avatar