managerimpl.cpp 52.9 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
 *
jpbl's avatar
jpbl committed
8
9
 *  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
10
 *  the Free Software Foundation; either version 3 of the License, or
jpbl's avatar
jpbl committed
11
 *  (at your option) any later version.
12
 *
jpbl's avatar
jpbl committed
13
14
15
16
 *  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.
17
 *
jpbl's avatar
jpbl committed
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
 *  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>

#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"
38
#include "account.h"
jpbl's avatar
jpbl committed
39
40
41
42
#include "audio/audiolayer.h"
#include "audio/audiocodec.h"
#include "audio/tonelist.h"

yanmorin's avatar
   
yanmorin committed
43
#include "accountcreator.h" // create new account
44
#include "voiplink.h"
jpbl's avatar
jpbl committed
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70

#include "user_cfg.h"

#ifdef USE_ZEROCONF
#include "zeroconf/DNSService.h"
#include "zeroconf/DNSServiceTXTRecord.h"
#endif

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

ManagerImpl::ManagerImpl (void)
{
  // Init private variables 
  _hasZeroconf = false;
#ifdef USE_ZEROCONF
  _hasZeroconf = true;
  _DNSService = new DNSService();
#endif

  // setup
  _path = ""; 
  _exist = 0;
  _setupLoaded = false;
71
  _dbus = NULL;
jpbl's avatar
jpbl committed
72

yanmorin's avatar
   
yanmorin committed
73
  // sound
Alexandre Bourget's avatar
Pouet    
Alexandre Bourget committed
74
  _audiodriver = NULL;
jpbl's avatar
jpbl committed
75
  _dtmfKey = 0;
76
  _spkr_volume = 0;  // Initialize after by init() -> initVolume()
yanmorin's avatar
   
yanmorin committed
77
78
  _mic_volume  = 0;  // Initialize after by init() -> initVolume()
  _mic_volume_before_mute = 0; 
jpbl's avatar
jpbl committed
79
80
81
82

  // Call
  _nbIncomingWaitingCall=0;
  _hasTriedToRegister = false;
yanmorin's avatar
   
yanmorin committed
83

jpbl's avatar
jpbl committed
84
85
  // initialize random generator for call id
  srand (time(NULL));
yanmorin's avatar
   
yanmorin committed
86
87
88
89
90
91
92
93
94

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

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

// never call if we use only the singleton...
ManagerImpl::~ManagerImpl (void) 
{
  terminate();

#ifdef USE_ZEROCONF
104
  delete _DNSService; _DNSService = 0;
jpbl's avatar
jpbl committed
105
106
107
108
109
110
111
112
#endif

  _debug("%s stop correctly.\n", PROGNAME);
}

void 
ManagerImpl::init() 
{
113
114
115
  // Load accounts, init map
  loadAccountMap();

jpbl's avatar
jpbl committed
116
117
118
119
120
121
  initVolume();

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

122
123
124
  initAudioDriver();
  selectAudioDriver();

jpbl's avatar
jpbl committed
125
126
127
128
129
130
131
132
  initAudioCodec();

  AudioLayer *audiolayer = getAudioDriver();
  if (audiolayer!=0) {
    unsigned int sampleRate = audiolayer->getSampleRate();

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

    _debugInit("Loading DTMF key");
136
    _dtmfKey = new DTMF(sampleRate);
jpbl's avatar
jpbl committed
137
138
  }

139
  // initRegisterAccounts was here, but we doing it after the gui loaded... 
jpbl's avatar
jpbl committed
140
141
142
143
144
145
146
147
  // the stun detection is long, so it's a better idea to do it after getEvents
  initZeroconf();
}

void ManagerImpl::terminate()
{
  saveConfig();

yanmorin's avatar
   
yanmorin committed
148
  unloadAccountMap();
jpbl's avatar
jpbl committed
149
150
151
152
153

  _debug("Unload DTMF Key\n");
  delete _dtmfKey;

  _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;
jpbl's avatar
jpbl committed
158
159
}

yanmorin's avatar
   
yanmorin committed
160
161
162
163
bool
ManagerImpl::isCurrentCall(const CallID& callId) {
  ost::MutexLock m(_currentCallMutex);
  return (_currentCallId2 == callId ? true : false);
jpbl's avatar
jpbl committed
164
165
}

yanmorin's avatar
   
yanmorin committed
166
167
168
169
170
bool
ManagerImpl::hasCurrentCall() {
  ost::MutexLock m(_currentCallMutex);
  if ( _currentCallId2 != "") {
    return true;
jpbl's avatar
jpbl committed
171
  }
yanmorin's avatar
   
yanmorin committed
172
  return false;
jpbl's avatar
jpbl committed
173
174
}

yanmorin's avatar
   
yanmorin committed
175
176
177
178
const CallID& 
ManagerImpl::getCurrentCallId() {
  ost::MutexLock m(_currentCallMutex);
  return _currentCallId2;
jpbl's avatar
jpbl committed
179
180
181
}

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


///////////////////////////////////////////////////////////////////////////////
// Management of events' IP-phone user
///////////////////////////////////////////////////////////////////////////////
yanmorin's avatar
   
yanmorin committed
191
192
193
194
195
/* Main Thread */ 
bool
ManagerImpl::outgoingCall(const std::string& accountid, const CallID& id, const std::string& to)
{
  if (!accountExists(accountid)) {
196
    _debug("! Manager Error: Outgoing Call: account doesn't exist\n");
yanmorin's avatar
   
yanmorin committed
197
198
199
    return false;
  }
  if (getAccountFromCall(id) != AccountNULL) {
200
    _debug("! Manager Error: Outgoing Call: call id already exists\n");
yanmorin's avatar
   
yanmorin committed
201
202
    return false;
  }
yanmorin's avatar
   
yanmorin committed
203
  if (hasCurrentCall()) {
204
    _debug("* Manager Info: there is currently a call, try to hold it\n");
yanmorin's avatar
   
yanmorin committed
205
206
    onHoldCall(getCurrentCallId());
  }
207
  _debug("- Manager Action: Adding Outgoing Call %s on account %s\n", id.data(), accountid.data());
yanmorin's avatar
   
yanmorin committed
208
209
210
211
  if ( getAccountLink(accountid)->newOutgoingCall(id, to) ) {
    associateCallToAccount( id, accountid );
    switchCall(id);
    return true;
jpbl's avatar
jpbl committed
212
  } else {
213
    _debug("! Manager Error: An error occur, the call was not created\n");
jpbl's avatar
jpbl committed
214
  }
yanmorin's avatar
   
yanmorin committed
215
  return false;
jpbl's avatar
jpbl committed
216
217
}

yanmorin's avatar
   
yanmorin committed
218
219
220
//THREAD=Main : for outgoing Call
bool
ManagerImpl::answerCall(const CallID& id)
jpbl's avatar
jpbl committed
221
{
222
  stopTone(false); 
223
224
225
226
  if (hasCurrentCall()) 
  { 
    onHoldCall(getCurrentCallId());
  }
yanmorin's avatar
   
yanmorin committed
227
228
229
230
  AccountID accountid = getAccountFromCall( id );
  if (accountid == AccountNULL) {
    _debug("Answering Call: Call doesn't exists\n");
    return false;
jpbl's avatar
jpbl committed
231
  }
yanmorin's avatar
   
yanmorin committed
232
233
234
235
236

  if (!getAccountLink(accountid)->answer(id)) {
    // error when receiving...
    removeCallAccount(id);
    return false;
jpbl's avatar
jpbl committed
237
  }
yanmorin's avatar
   
yanmorin committed
238

239
240
241
  //Place current call on hold if it isn't
  
  
yanmorin's avatar
   
yanmorin committed
242
  // if it was waiting, it's waiting no more
243
  if (_dbus) _dbus->getCallManager()->callStateChanged(id, "CURRENT");
yanmorin's avatar
   
yanmorin committed
244
245
246
  removeWaitingCall(id);
  switchCall(id);
  return true;
jpbl's avatar
jpbl committed
247
248
}

yanmorin's avatar
   
yanmorin committed
249
250
251
//THREAD=Main
bool 
ManagerImpl::sendTextMessage(const AccountID& accountId, const std::string& to, const std::string& message) 
jpbl's avatar
jpbl committed
252
{
yanmorin's avatar
   
yanmorin committed
253
254
  if (accountExists(accountId)) {
    return getAccountLink(accountId)->sendMessage(to, message);
jpbl's avatar
jpbl committed
255
  }
yanmorin's avatar
   
yanmorin committed
256
  return false;
jpbl's avatar
jpbl committed
257
258
}

yanmorin's avatar
   
yanmorin committed
259
260
261
//THREAD=Main
bool
ManagerImpl::hangupCall(const CallID& id)
jpbl's avatar
jpbl committed
262
{
263
  stopTone(true);
264
  if (_dbus) _dbus->getCallManager()->callStateChanged(id, "HUNGUP");
yanmorin's avatar
   
yanmorin committed
265
266
  AccountID accountid = getAccountFromCall( id );
  if (accountid == AccountNULL) {
267
268
    /** @todo We should tell the GUI that the call doesn't exist, so
     * it clears up. This can happen. */
269
    _debug("! Manager Hangup Call: Call doesn't exists\n");
yanmorin's avatar
   
yanmorin committed
270
    return false;
jpbl's avatar
jpbl committed
271
  }
yanmorin's avatar
   
yanmorin committed
272
273
274
275

  bool returnValue = getAccountLink(accountid)->hangup(id);
  removeCallAccount(id);
  switchCall("");
276
277
  
  
yanmorin's avatar
   
yanmorin committed
278
  return returnValue;
jpbl's avatar
jpbl committed
279
280
}

yanmorin's avatar
   
yanmorin committed
281
282
283
//THREAD=Main
bool
ManagerImpl::cancelCall (const CallID& id)
jpbl's avatar
jpbl committed
284
{
285
  stopTone(true);
yanmorin's avatar
   
yanmorin committed
286
287
  AccountID accountid = getAccountFromCall( id );
  if (accountid == AccountNULL) {
288
    _debug("! Manager Cancel Call: Call doesn't exists\n");
yanmorin's avatar
   
yanmorin committed
289
    return false;
jpbl's avatar
jpbl committed
290
  }
yanmorin's avatar
   
yanmorin committed
291
292
293
294
295
296
297
298

  bool returnValue = getAccountLink(accountid)->cancel(id);
  // it could be a waiting call?
  removeWaitingCall(id);
  removeCallAccount(id);
  switchCall("");
  
  return returnValue;
jpbl's avatar
jpbl committed
299
300
}

yanmorin's avatar
   
yanmorin committed
301
302
303
//THREAD=Main
bool
ManagerImpl::onHoldCall(const CallID& id)
jpbl's avatar
jpbl committed
304
{
305
  stopTone(true);
yanmorin's avatar
   
yanmorin committed
306
307
  AccountID accountid = getAccountFromCall( id );
  if (accountid == AccountNULL) {
308
    _debug("5 Manager On Hold Call: Account ID %s or callid %s desn't exists\n", accountid.c_str(), id.c_str());
yanmorin's avatar
   
yanmorin committed
309
    return false;
jpbl's avatar
jpbl committed
310
  }
yanmorin's avatar
   
yanmorin committed
311

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

yanmorin's avatar
   
yanmorin committed
314
  bool returnValue = getAccountLink(accountid)->onhold(id);
315
  
yanmorin's avatar
   
yanmorin committed
316
  removeWaitingCall(id);
317
  if (_dbus) _dbus->getCallManager()->callStateChanged(id, "HOLD");
yanmorin's avatar
   
yanmorin committed
318
319
320
321
322
323
324
325
326
  switchCall("");
  
  return returnValue;
}

//THREAD=Main
bool
ManagerImpl::offHoldCall(const CallID& id)
{
327
  stopTone(false);
yanmorin's avatar
   
yanmorin committed
328
329
  AccountID accountid = getAccountFromCall( id );
  if (accountid == AccountNULL) {
330
    _debug("5 Manager OffHold Call: Call doesn't exists\n");
yanmorin's avatar
   
yanmorin committed
331
    return false;
jpbl's avatar
jpbl committed
332
  }
333
334
335
336
337
338
339
  
  //Place current call on hold if it isn't
  if (hasCurrentCall()) 
  { 
    onHoldCall(getCurrentCallId());
  }
  
340
341
  _debug("Setting OFFHOLD, Account %s, callid %s\n", accountid.c_str(), id.c_str());

yanmorin's avatar
   
yanmorin committed
342
  bool returnValue = getAccountLink(accountid)->offhold(id);
343
  if (_dbus) _dbus->getCallManager()->callStateChanged(id, "UNHOLD");
yanmorin's avatar
   
yanmorin committed
344
345
  switchCall(id);
  if (returnValue) {
jpbl's avatar
jpbl committed
346
347
348
    try {
      getAudioDriver()->startStream();
    } catch(...) {
349
      _debugException("! Manager Off hold could not start audio stream");
jpbl's avatar
jpbl committed
350
351
352
353
354
    }
  }
  return returnValue;
}

yanmorin's avatar
   
yanmorin committed
355
356
357
//THREAD=Main
bool
ManagerImpl::transferCall(const CallID& id, const std::string& to)
jpbl's avatar
jpbl committed
358
{
359
  stopTone(true);
yanmorin's avatar
   
yanmorin committed
360
361
  AccountID accountid = getAccountFromCall( id );
  if (accountid == AccountNULL) {
362
    _debug("! Manager Transfer Call: Call doesn't exists\n");
yanmorin's avatar
   
yanmorin committed
363
    return false;
jpbl's avatar
jpbl committed
364
  }
yanmorin's avatar
   
yanmorin committed
365
366
367
  bool returnValue = getAccountLink(accountid)->transfer(id, to);
  removeWaitingCall(id);
  removeCallAccount(id);
368
  if (_dbus) _dbus->getCallManager()->callStateChanged(id, "HUNGUP");
yanmorin's avatar
   
yanmorin committed
369
370
371
  switchCall("");

  return returnValue;
jpbl's avatar
jpbl committed
372
373
}

yanmorin's avatar
   
yanmorin committed
374
//THREAD=Main
jpbl's avatar
jpbl committed
375
376
377
378
379
380
void
ManagerImpl::mute() {
  _mic_volume_before_mute = _mic_volume;
  setMicVolume(0);
}

yanmorin's avatar
   
yanmorin committed
381
//THREAD=Main
jpbl's avatar
jpbl committed
382
383
384
385
386
387
388
void
ManagerImpl::unmute() {
  if ( _mic_volume == 0 ) {
    setMicVolume(_mic_volume_before_mute);
  }
}

yanmorin's avatar
   
yanmorin committed
389
390
391
//THREAD=Main : Call:Incoming
bool
ManagerImpl::refuseCall (const CallID& id)
jpbl's avatar
jpbl committed
392
{
393
  stopTone(true);
yanmorin's avatar
   
yanmorin committed
394
395
  AccountID accountid = getAccountFromCall( id );
  if (accountid == AccountNULL) {
396
    _debug("! Manager OffHold Call: Call doesn't exists\n");
yanmorin's avatar
   
yanmorin committed
397
398
399
    return false;
  }
  bool returnValue = getAccountLink(accountid)->refuse(id);
yanmorin's avatar
   
yanmorin committed
400
401
402
403
404
  // if the call was outgoing or established, we didn't refuse it
  // so the method did nothing
  if (returnValue) {
    removeWaitingCall(id);
    removeCallAccount(id);
405
    if (_dbus) _dbus->getCallManager()->callStateChanged(id, "HUNGUP");
yanmorin's avatar
   
yanmorin committed
406
407
    switchCall("");
  }
yanmorin's avatar
   
yanmorin committed
408
  return returnValue;
jpbl's avatar
jpbl committed
409
410
}

yanmorin's avatar
   
yanmorin committed
411
//THREAD=Main
jpbl's avatar
jpbl committed
412
413
414
415
416
417
418
419
420
421
422
bool
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
423
//THREAD=Main
jpbl's avatar
jpbl committed
424
bool
425
ManagerImpl::initRegisterAccounts() 
jpbl's avatar
jpbl committed
426
{
427
  _debugInit("Initiate VoIP Links Registration");
yanmorin's avatar
   
yanmorin committed
428
429
430
431
  AccountMap::iterator iter = _accountMap.begin();
  while( iter != _accountMap.end() ) {
    if ( iter->second) {
      iter->second->loadConfig();
432
      if ( iter->second->isEnabled() ) {
433
	iter->second->registerVoIPLink();
jpbl's avatar
jpbl committed
434
435
      }
    }
yanmorin's avatar
   
yanmorin committed
436
    iter++;
jpbl's avatar
jpbl committed
437
  }
yanmorin's avatar
   
yanmorin committed
438
  return true;
jpbl's avatar
jpbl committed
439
440
}

yanmorin's avatar
   
yanmorin committed
441
//THREAD=Main
442
// Currently unused
jpbl's avatar
jpbl committed
443
bool
444
ManagerImpl::registerAccount(const AccountID& accountId)
jpbl's avatar
jpbl committed
445
{
446
447
  _debug("Register one VoIP Link\n");

448
449
450
451
452
453
454
  // right now, we don't support two SIP account
  // so we close everything before registring a new account
  Account* account = getAccount(accountId);
  if (account != 0) {
    AccountMap::iterator iter = _accountMap.begin();
    while ( iter != _accountMap.end() ) {
      if ( iter->second ) {
455
        iter->second->unregisterVoIPLink();
456
457
458
      }
      iter++;
    }
459
    account->registerVoIPLink();
jpbl's avatar
jpbl committed
460
  }
461
  return true;
jpbl's avatar
jpbl committed
462
463
}

yanmorin's avatar
   
yanmorin committed
464
//THREAD=Main
465
// Currently unused
jpbl's avatar
jpbl committed
466
bool 
467
ManagerImpl::unregisterAccount(const AccountID& accountId)
jpbl's avatar
jpbl committed
468
{
469
470
  _debug("Unregister one VoIP Link\n");

yanmorin's avatar
   
yanmorin committed
471
  if (accountExists( accountId ) ) {
472
    getAccount(accountId)->unregisterVoIPLink();
yanmorin's avatar
   
yanmorin committed
473
  }
474
  return true;
jpbl's avatar
jpbl committed
475
476
}

yanmorin's avatar
   
yanmorin committed
477
//THREAD=Main
jpbl's avatar
jpbl committed
478
bool 
yanmorin's avatar
   
yanmorin committed
479
ManagerImpl::sendDtmf(const CallID& id, char code)
jpbl's avatar
jpbl committed
480
{
yanmorin's avatar
   
yanmorin committed
481
482
483
484
485
486
  AccountID accountid = getAccountFromCall( id );
  if (accountid == AccountNULL) {
    _debug("Send DTMF: call doesn't exists\n");
    return false;
  }

jpbl's avatar
jpbl committed
487
  int sendType = getConfigInt(SIGNALISATION, SEND_DTMF_AS);
yanmorin's avatar
   
yanmorin committed
488
  bool returnValue = false;
jpbl's avatar
jpbl committed
489
490
491
  switch (sendType) {
  case 0: // SIP INFO
    playDtmf(code);
yanmorin's avatar
   
yanmorin committed
492
    returnValue = getAccountLink(accountid)->carryingDTMFdigits(id, code);
jpbl's avatar
jpbl committed
493
494
495
496
497
498
499
500
501
502
503
504
    break;

  case 1: // Audio way
    break;
  case 2: // rfc 2833
    break;
  default: // unknown - error config?
    break;
  }
  return returnValue;
}

yanmorin's avatar
   
yanmorin committed
505
//THREAD=Main | VoIPLink
jpbl's avatar
jpbl committed
506
507
508
bool
ManagerImpl::playDtmf(char code)
{
509
510
511
512
  // HERE are the variable:
  // - boolean variable to play or not (config)
  // - length in milliseconds to play
  // - sample of audiolayer
513
  stopTone(false);
yanmorin's avatar
   
yanmorin committed
514
515
  int hasToPlayTone = getConfigInt(SIGNALISATION, PLAY_DTMF);
  if (!hasToPlayTone) return false;
jpbl's avatar
jpbl committed
516
517
518
519
520
521
522
523
524
525
526

  // length in milliseconds
  int pulselen = getConfigInt(SIGNALISATION, PULSE_LENGTH);
  if (!pulselen) { return false; }

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

  // fast return, no sound, so no dtmf
  if (audiolayer==0 || _dtmfKey == 0) { return false; }
527
528
529
530
  // number of data sampling in one pulselen depends on samplerate
  // size (n sampling) = time_ms * sampling/s 
  //                     ---------------------
  //                            ms/s
531
532
  int size = (int)(pulselen * ((float)audiolayer->getSampleRate()/1000));

533
534
535
  // this buffer is for mono
  // TODO <-- this should be global and hide if same size
  SFLDataFormat* _buf = new SFLDataFormat[size];
jpbl's avatar
jpbl committed
536
537
538
539
540
  bool returnValue = false;

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

541
  // copy the sound
542
  if ( _dtmfKey->generateDTMF(_buf, size) ) {
jpbl's avatar
jpbl committed
543
544
545

    // Put buffer to urgentRingBuffer 
    // put the size in bytes...
546
547
    // so size * 1 channel (mono) * sizeof (bytes for the data)
    audiolayer->putUrgent(_buf, size * sizeof(SFLDataFormat));
jpbl's avatar
jpbl committed
548
549
550
551
552
553
554
555
556
557
558
559
560

    try {
      // We activate the stream if it's not active yet.
      if (!audiolayer->isStreamActive()) {
        audiolayer->startStream();
      } else {
        audiolayer->sleep(pulselen); // in milliseconds
      }
    } catch(...) {
      _debugException("Portaudio exception when playing a dtmf");
    }
    returnValue = true;
  }
561
562

  // TODO: add caching
jpbl's avatar
jpbl committed
563
564
565
566
  delete[] _buf; _buf = 0;
  return returnValue;
}

yanmorin's avatar
   
yanmorin committed
567
// Multi-thread 
jpbl's avatar
jpbl committed
568
569
bool
ManagerImpl::incomingCallWaiting() {
yanmorin's avatar
   
yanmorin committed
570
  ost::MutexLock m(_waitingCallMutex);
jpbl's avatar
jpbl committed
571
572
573
574
  return (_nbIncomingWaitingCall > 0) ? true : false;
}

void
yanmorin's avatar
   
yanmorin committed
575
576
577
ManagerImpl::addWaitingCall(const CallID& id) {
  ost::MutexLock m(_waitingCallMutex);
  _waitingCall.insert(id);
jpbl's avatar
jpbl committed
578
579
580
581
  _nbIncomingWaitingCall++;
}

void
yanmorin's avatar
   
yanmorin committed
582
583
584
585
586
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
587
588
589
590
  }
}

bool
yanmorin's avatar
   
yanmorin committed
591
592
593
594
595
ManagerImpl::isWaitingCall(const CallID& id) {
  ost::MutexLock m(_waitingCallMutex);
  CallIDSet::iterator iter = _waitingCall.find(id);
  if (iter != _waitingCall.end()) {
    return false;
jpbl's avatar
jpbl committed
596
  }
yanmorin's avatar
   
yanmorin committed
597
  return true;
jpbl's avatar
jpbl committed
598
599
600
601
}



yanmorin's avatar
   
yanmorin committed
602
603
604
605
606
607
///////////////////////////////////////////////////////////////////////////////
// Management of event peer IP-phone 
////////////////////////////////////////////////////////////////////////////////
// SipEvent Thread 
bool 
ManagerImpl::incomingCall(Call* call, const AccountID& accountId) 
jpbl's avatar
jpbl committed
608
{
yanmorin's avatar
   
yanmorin committed
609
  _debug("Incoming call\n");
610

yanmorin's avatar
   
yanmorin committed
611
  associateCallToAccount(call->getCallId(), accountId);
612

yanmorin's avatar
   
yanmorin committed
613
614
  if ( !hasCurrentCall() ) {
    call->setConnectionState(Call::Ringing);
jpbl's avatar
jpbl committed
615
    ringtone();
yanmorin's avatar
   
yanmorin committed
616
    switchCall(call->getCallId());
jpbl's avatar
jpbl committed
617
  } else {
yanmorin's avatar
   
yanmorin committed
618
     addWaitingCall(call->getCallId());
jpbl's avatar
jpbl committed
619
620
  }

yanmorin's avatar
   
yanmorin committed
621
622
623
  std::string from = call->getPeerName();
  std::string number = call->getPeerNumber();

624
  if (from != "" && number != "") {
jpbl's avatar
jpbl committed
625
626
627
    from.append(" <");
    from.append(number);
    from.append(">");
628
629
630
631
  } else if ( from.empty() ) {
    from.append("<");
    from.append(number);
    from.append(">");
jpbl's avatar
jpbl committed
632
  }
633
  _dbus->getCallManager()->incomingCall(accountId, call->getCallId(), from);
yanmorin's avatar
   
yanmorin committed
634
  return true;
jpbl's avatar
jpbl committed
635
636
}

yanmorin's avatar
   
yanmorin committed
637
638
639
//THREAD=VoIP
void
ManagerImpl::incomingMessage(const AccountID& accountId, const std::string& message) {
640
641
  if (_dbus) {
    _dbus->getCallManager()->incomingMessage(accountId, message);
jpbl's avatar
jpbl committed
642
643
644
  }
}

yanmorin's avatar
   
yanmorin committed
645
646
647
//THREAD=VoIP CALL=Outgoing
void
ManagerImpl::peerAnsweredCall(const CallID& id)
jpbl's avatar
jpbl committed
648
{
yanmorin's avatar
   
yanmorin committed
649
  if (isCurrentCall(id)) {
650
    stopTone(false);
jpbl's avatar
jpbl committed
651
  }
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
652
  if (_dbus) _dbus->getCallManager()->callStateChanged(id, "CURRENT");
jpbl's avatar
jpbl committed
653
654
}

yanmorin's avatar
   
yanmorin committed
655
656
657
//THREAD=VoIP Call=Outgoing
void
ManagerImpl::peerRingingCall(const CallID& id)
jpbl's avatar
jpbl committed
658
{
yanmorin's avatar
   
yanmorin committed
659
  if (isCurrentCall(id)) {
jpbl's avatar
jpbl committed
660
661
    ringback();
  }
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
662
  if (_dbus) _dbus->getCallManager()->callStateChanged(id, "RINGING");
jpbl's avatar
jpbl committed
663
664
}

yanmorin's avatar
   
yanmorin committed
665
666
667
//THREAD=VoIP Call=Outgoing/Ingoing
void
ManagerImpl::peerHungupCall(const CallID& id)
jpbl's avatar
jpbl committed
668
{
yanmorin's avatar
   
yanmorin committed
669
670
671
672
  AccountID accountid = getAccountFromCall( id );
  if (accountid == AccountNULL) {
    _debug("peerHungupCall: Call doesn't exists\n");
    return;
jpbl's avatar
jpbl committed
673
  }
674
  if (_dbus) _dbus->getCallManager()->callStateChanged(id, "HUNGUP");
yanmorin's avatar
   
yanmorin committed
675
  if (isCurrentCall(id)) {
676
    stopTone(true);
yanmorin's avatar
   
yanmorin committed
677
    switchCall("");
jpbl's avatar
jpbl committed
678
  }
yanmorin's avatar
   
yanmorin committed
679
680
  removeWaitingCall(id);
  removeCallAccount(id);
681
  
jpbl's avatar
jpbl committed
682
683
}

yanmorin's avatar
   
yanmorin committed
684
//THREAD=VoIP
jpbl's avatar
jpbl committed
685
void
yanmorin's avatar
   
yanmorin committed
686
687
ManagerImpl::callBusy(const CallID& id) {
  _debug("Call busy\n");
688
689
  
  if (_dbus) _dbus->getCallManager()->callStateChanged(id, "BUSY");
yanmorin's avatar
   
yanmorin committed
690
691
692
  if (isCurrentCall(id) ) {
    playATone(Tone::TONE_BUSY);
    switchCall("");
jpbl's avatar
jpbl committed
693
  }
yanmorin's avatar
   
yanmorin committed
694
695
  removeCallAccount(id);
  removeWaitingCall(id);
jpbl's avatar
jpbl committed
696
697
}

yanmorin's avatar
   
yanmorin committed
698
//THREAD=VoIP
jpbl's avatar
jpbl committed
699
void
yanmorin's avatar
   
yanmorin committed
700
701
702
ManagerImpl::callFailure(const CallID& id) 
{
  _debug("Call failed\n");
703
  if (_dbus) _dbus->getCallManager()->callStateChanged(id, "FAILURE");
yanmorin's avatar
   
yanmorin committed
704
705
706
707
708
709
  if (isCurrentCall(id) ) {
    playATone(Tone::TONE_BUSY);
    switchCall("");
  }
  removeCallAccount(id);
  removeWaitingCall(id);
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
710
  
jpbl's avatar
jpbl committed
711
712
}

yanmorin's avatar
   
yanmorin committed
713
//THREAD=VoIP
jpbl's avatar
jpbl committed
714
void 
yanmorin's avatar
   
yanmorin committed
715
ManagerImpl::displayTextMessage(const CallID& id, const std::string& message)
jpbl's avatar
jpbl committed
716
{
717
  /*if(_gui) {
yanmorin's avatar
   
yanmorin committed
718
   _gui->displayTextMessage(id, message);
719
  }*/
jpbl's avatar
jpbl committed
720
721
}

yanmorin's avatar
   
yanmorin committed
722
//THREAD=VoIP
jpbl's avatar
jpbl committed
723
void 
yanmorin's avatar
   
yanmorin committed
724
ManagerImpl::displayErrorText(const CallID& id, const std::string& message)
jpbl's avatar
jpbl committed
725
{
726
  /*if(_gui) {
jpbl's avatar
jpbl committed
727
728
729
    _gui->displayErrorText(id, message);
  } else {
    std::cerr << message << std::endl;
730
  }*/
jpbl's avatar
jpbl committed
731
732
}

yanmorin's avatar
   
yanmorin committed
733
//THREAD=VoIP
jpbl's avatar
jpbl committed
734
void 
yanmorin's avatar
   
yanmorin committed
735
ManagerImpl::displayError (const std::string& error)
jpbl's avatar
jpbl committed
736
{
737
  /*if(_gui) {
yanmorin's avatar
   
yanmorin committed
738
    _gui->displayError(error);
739
  }*/
jpbl's avatar
jpbl committed
740
741
}

yanmorin's avatar
   
yanmorin committed
742
//THREAD=VoIP
jpbl's avatar
jpbl committed
743
void 
yanmorin's avatar
   
yanmorin committed
744
ManagerImpl::displayStatus(const std::string& status)
jpbl's avatar
jpbl committed
745
{
746
  /*if(_gui) {
jpbl's avatar
jpbl committed
747
    _gui->displayStatus(status);
748
  }*/
jpbl's avatar
jpbl committed
749
750
}

yanmorin's avatar
   
yanmorin committed
751
//THREAD=VoIP
jpbl's avatar
jpbl committed
752
753
754
void 
ManagerImpl::displayConfigError (const std::string& message)
{
755
  /*if(_gui) {
jpbl's avatar
jpbl committed
756
    _gui->displayConfigError(message);
757
  }*/
jpbl's avatar
jpbl committed
758
759
}

yanmorin's avatar
   
yanmorin committed
760
//THREAD=VoIP
jpbl's avatar
jpbl committed
761
void
yanmorin's avatar
   
yanmorin committed
762
ManagerImpl::startVoiceMessageNotification(const AccountID& accountId, const std::string& nb_msg)
jpbl's avatar
jpbl committed
763
{
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
764
  if (_dbus) _dbus->getCallManager()->voiceMailNotify(accountId, atoi(nb_msg.c_str()) );
jpbl's avatar
jpbl committed
765
766
}

yanmorin's avatar
   
yanmorin committed
767
//THREAD=VoIP
jpbl's avatar
jpbl committed
768
void
yanmorin's avatar
   
yanmorin committed
769
ManagerImpl::stopVoiceMessageNotification(const AccountID& accountId)
jpbl's avatar
jpbl committed
770
{
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
771
  if (_dbus) _dbus->getCallManager()->voiceMailNotify(accountId, 0 );
772
} 
jpbl's avatar
jpbl committed
773

yanmorin's avatar
   
yanmorin committed
774
//THREAD=VoIP
jpbl's avatar
jpbl committed
775
void 
yanmorin's avatar
   
yanmorin committed
776
ManagerImpl::registrationSucceed(const AccountID& accountid)
jpbl's avatar
jpbl committed
777
{
778
  Account* acc = getAccount(accountid);
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
779
 if ( acc ) { 
780
    //acc->setState(true); 
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
781
    if (_dbus) _dbus->getConfigurationManager()->accountsChanged();
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
782
  }
jpbl's avatar
jpbl committed
783
784
}

yanmorin's avatar
   
yanmorin committed
785
//THREAD=VoIP
jpbl's avatar
jpbl committed
786
void 
yanmorin's avatar
   
yanmorin committed
787
ManagerImpl::registrationFailed(const AccountID& accountid)
jpbl's avatar
jpbl committed
788
{
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
789
  Account* acc = getAccount(accountid);
790
  if ( acc ) { 
791
    //acc->setState(false);
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
792
    if (_dbus) _dbus->getConfigurationManager()->accountsChanged();
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
793
  }
jpbl's avatar
jpbl committed
794
795
796
797
798
799
800
}

/**
 * Multi Thread
 */
bool 
ManagerImpl::playATone(Tone::TONEID toneId) {
yanmorin's avatar
   
yanmorin committed
801
802
803
  int hasToPlayTone = getConfigInt(SIGNALISATION, PLAY_TONES);
  if (!hasToPlayTone) return false;

jpbl's avatar
jpbl committed
804
805
806
807
808
809
  if (_telephoneTone != 0) {
    _toneMutex.enterMutex();
    _telephoneTone->setCurrentTone(toneId);
    _toneMutex.leaveMutex();

    try {
810
811
      AudioLayer* audiolayer = getAudioDriver();
      if (audiolayer) { audiolayer->startStream(); }
jpbl's avatar
jpbl committed
812
813
    } catch(...) {
      _debugException("Off hold could not start audio stream");
814
      return false;
jpbl's avatar
jpbl committed
815
816
817
818
819
820
821
822
823
    }
  }
  return true;
}

/**
 * Multi Thread
 */
void 
824
ManagerImpl::stopTone(bool stopAudio=true) {
yanmorin's avatar
   
yanmorin committed
825
826
827
  int hasToPlayTone = getConfigInt(SIGNALISATION, PLAY_TONES);
  if (!hasToPlayTone) return;

828
829
830
831
832
833
834
  if (stopAudio) {
    try {
      AudioLayer* audiolayer = getAudioDriver();
      if (audiolayer) { audiolayer->stopStream(); }
    } catch(...) {
      _debugException("Stop tone and stop stream");
    }
jpbl's avatar
jpbl committed
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
  }

  _toneMutex.enterMutex();
  if (_telephoneTone != 0) {
    _telephoneTone->setCurrentTone(Tone::TONE_NULL);
  }
  _toneMutex.leaveMutex();

  // for ringing tone..
  _toneMutex.enterMutex();
  _audiofile.stop();
  _toneMutex.leaveMutex();
}

/**
 * Multi Thread
 */
bool
ManagerImpl::playTone()
{
855
856
  //return playATone(Tone::TONE_DIALTONE);
  playATone(Tone::TONE_DIALTONE);
jpbl's avatar
jpbl committed
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
}

/**
 * Multi Thread
 */
void
ManagerImpl::congestion () {
  playATone(Tone::TONE_CONGESTION);
}

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

/**
 * Multi Thread
 */
void
ManagerImpl::ringtone() 
{
yanmorin's avatar
   
yanmorin committed
881
  int hasToPlayTone = getConfigInt(SIGNALISATION, PLAY_TONES);
882
  if (!hasToPlayTone) { return; }
yanmorin's avatar
   
yanmorin committed
883

jpbl's avatar
jpbl committed
884
885
886
887
888
889
  std::string ringchoice = getConfigString(AUDIO, RING_CHOICE);
  //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; 
  }
890
891
892
893
894

  AudioLayer* audiolayer = getAudioDriver();
  if (audiolayer==0) { return; }
  int sampleRate  = audiolayer->getSampleRate();

jpbl's avatar
jpbl committed
895
  _toneMutex.enterMutex(); 
896
  bool loadFile = _audiofile.loadFile(ringchoice, sampleRate);
jpbl's avatar
jpbl committed
897
898
899
900
901
902
  _toneMutex.leaveMutex(); 
  if (loadFile) {
    _toneMutex.enterMutex(); 
    _audiofile.start();
    _toneMutex.leaveMutex(); 
    try {
903
      audiolayer->startStream();
jpbl's avatar
jpbl committed
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
    } catch(...) {
      _debugException("Audio file couldn't start audio stream");
    }
  } else {
    ringback();
  }
}

AudioLoop*
ManagerImpl::getTelephoneTone()
{
  if(_telephoneTone != 0) {
    ost::MutexLock m(_toneMutex);
    return _telephoneTone->getCurrentTone();
  }
  else {
    return 0;
  }
}

AudioLoop*
ManagerImpl::getTelephoneFile()
{
  ost::MutexLock m(_toneMutex);
  if(_audiofile.isStarted()) {
    return &_audiofile;
  } else {
    return 0;
  }
}


/**
 * Use Urgent Buffer
 * By AudioRTP thread
 */
void
yanmorin's avatar
   
yanmorin committed
941
ManagerImpl::notificationIncomingCall(void) {
jpbl's avatar
jpbl committed
942
943
944

  AudioLayer* audiolayer = getAudioDriver();
  if (audiolayer != 0) {
yanmorin's avatar
   
yanmorin committed
945
    unsigned int samplerate = audiolayer->getSampleRate();
jpbl's avatar
jpbl committed
946
947
948
    std::ostringstream frequency;
    frequency << "440/" << FRAME_PER_BUFFER;

949
950
951
    Tone tone(frequency.str(), samplerate);
    unsigned int nbSampling = tone.getSize();
    SFLDataFormat buf[nbSampling];
jpbl's avatar
jpbl committed
952
    tone.getNext(buf, tone.getSize());
953
    audiolayer->putUrgent(buf, sizeof(SFLDataFormat)*nbSampling);
jpbl's avatar
jpbl committed
954
955
956
957
958
959
  }
}

/**
 * Multi Thread
 */
yanmorin's avatar
   
yanmorin committed
960
961
bool
ManagerImpl::getStunInfo (StunAddress4& stunSvrAddr, int port) 
jpbl's avatar
jpbl committed
962
963
964
965
{
  StunAddress4 mappedAddr;
  struct in_addr in;
  char* addr;
yanmorin's avatar
   
yanmorin committed
966
967
968
969
970

  //int fd3, fd4;
  // bool ok = stunOpenSocketPair(stunSvrAddr, &mappedAddr, &fd3, &fd4, port);
  int fd1 = stunOpenSocket(stunSvrAddr, &mappedAddr, port);
  bool ok = (fd1 == -1 || fd1 == INVALID_SOCKET) ? false : true;
jpbl's avatar
jpbl committed
971
  if (ok) {
yanmorin's avatar
   
yanmorin committed
972
973
974
    closesocket(fd1);
    //closesocket(fd3);
    //closesocket(fd4);
jpbl's avatar
jpbl committed
975
976
977
978
979
980
    _firewallPort = mappedAddr.port;
    // Convert ipv4 address to host byte ordering
    in.s_addr = ntohl (mappedAddr.addr);
    addr = inet_ntoa(in);
    _firewallAddr = std::string(addr);
    _debug("STUN Firewall: [%s:%d]\n", _firewallAddr.data(), _firewallPort);
yanmorin's avatar
   
yanmorin committed
981
    return true;
jpbl's avatar
jpbl committed
982
983
984
  } else {
    _debug("Opening a stun socket pair failed\n");
  }
yanmorin's avatar
   
yanmorin committed
985
  return false;
jpbl's avatar
jpbl committed
986
987
988
}

bool
yanmorin's avatar
   
yanmorin committed
989
ManagerImpl::behindNat(const std::string& svr, int port)
yanmorin's avatar
   
yanmorin committed
990
991
992
993
994
995
996
997
998
{
  StunAddress4 stunSvrAddr;
  stunSvrAddr.addr = 0;
  
  // Convert char* to StunAddress4 structure
  bool ret = stunParseServerName ((char*)svr.data(), stunSvrAddr);
  if (!ret) {
    _debug("SIP: Stun server address (%s) is not valid\n", svr.data());
    return 0;
jpbl's avatar
jpbl committed
999
  }
yanmorin's avatar
   
yanmorin committed
1000