managerimpl.cpp 44.2 KB
Newer Older
jpbl's avatar
jpbl committed
1
/*
yanmorin's avatar
   
yanmorin committed
2
 *  Copyright (C) 2004-2006 Savoir-Faire Linux inc.
jpbl's avatar
jpbl committed
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
 *  Author: Yan Morin <yan.morin@savoirfairelinux.com>
 *  Author : Laurielle Lea <laurielle.lea@savoirfairelinux.com>
 *                                                                              
 *  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
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *                                                                              
 *  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.
 *                                                                              
 *  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"
#include "audio/audiolayer.h"
#include "audio/audiocodec.h"
#include "audio/tonelist.h"

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

#include "user_cfg.h"
#include "gui/guiframework.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;
69
  _gui = 0;
jpbl's avatar
jpbl committed
70

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

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

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

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

  // should be call before initConfigFile
  loadAccountMap();
jpbl's avatar
jpbl committed
94
95
96
97
98
99
100
101
}

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

#ifdef USE_ZEROCONF
102
  delete _DNSService; _DNSService = 0;
jpbl's avatar
jpbl committed
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#endif

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

void 
ManagerImpl::init() 
{
  initVolume();

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

117
118
119
  initAudioDriver();
  selectAudioDriver();

jpbl's avatar
jpbl committed
120
121
122
123
124
125
126
127
  initAudioCodec();

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

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

    _debugInit("Loading DTMF key");
131
    _dtmfKey = new DTMF(sampleRate);
jpbl's avatar
jpbl committed
132
133
134
135
136
137
138
139
140
141
142
  }

  // initRegisterVoIP was here, but we doing it after the gui loaded... 
  // 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
143
  unloadAccountMap();
jpbl's avatar
jpbl committed
144
145
146
147
148

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

  _debug("Unload Audio Driver\n");
149
  delete _audiodriver; _audiodriver = 0;
jpbl's avatar
jpbl committed
150
151
152
153
154

  _debug("Unload Telephone Tone\n");
  delete _telephoneTone; _telephoneTone = 0;
}

yanmorin's avatar
   
yanmorin committed
155
156
157
158
bool
ManagerImpl::isCurrentCall(const CallID& callId) {
  ost::MutexLock m(_currentCallMutex);
  return (_currentCallId2 == callId ? true : false);
jpbl's avatar
jpbl committed
159
160
}

yanmorin's avatar
   
yanmorin committed
161
162
163
164
165
bool
ManagerImpl::hasCurrentCall() {
  ost::MutexLock m(_currentCallMutex);
  if ( _currentCallId2 != "") {
    return true;
jpbl's avatar
jpbl committed
166
  }
yanmorin's avatar
   
yanmorin committed
167
  return false;
jpbl's avatar
jpbl committed
168
169
}

yanmorin's avatar
   
yanmorin committed
170
171
172
173
const CallID& 
ManagerImpl::getCurrentCallId() {
  ost::MutexLock m(_currentCallMutex);
  return _currentCallId2;
jpbl's avatar
jpbl committed
174
175
176
}

void
yanmorin's avatar
   
yanmorin committed
177
178
179
ManagerImpl::switchCall(const CallID& id ) {
  ost::MutexLock m(_currentCallMutex);
  _currentCallId2 = id;
jpbl's avatar
jpbl committed
180
181
182
183
184
185
}


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

yanmorin's avatar
   
yanmorin committed
213
214
215
//THREAD=Main : for outgoing Call
bool
ManagerImpl::answerCall(const CallID& id)
jpbl's avatar
jpbl committed
216
{
217
  stopTone(false); 
jpbl's avatar
jpbl committed
218

yanmorin's avatar
   
yanmorin committed
219
220
221
222
  AccountID accountid = getAccountFromCall( id );
  if (accountid == AccountNULL) {
    _debug("Answering Call: Call doesn't exists\n");
    return false;
jpbl's avatar
jpbl committed
223
  }
yanmorin's avatar
   
yanmorin committed
224
225
226
227
228

  if (!getAccountLink(accountid)->answer(id)) {
    // error when receiving...
    removeCallAccount(id);
    return false;
jpbl's avatar
jpbl committed
229
  }
yanmorin's avatar
   
yanmorin committed
230
231
232
233
234

  // if it was waiting, it's waiting no more
  removeWaitingCall(id);
  switchCall(id);
  return true;
jpbl's avatar
jpbl committed
235
236
}

yanmorin's avatar
   
yanmorin committed
237
238
239
//THREAD=Main
bool 
ManagerImpl::sendTextMessage(const AccountID& accountId, const std::string& to, const std::string& message) 
jpbl's avatar
jpbl committed
240
{
yanmorin's avatar
   
yanmorin committed
241
242
  if (accountExists(accountId)) {
    return getAccountLink(accountId)->sendMessage(to, message);
jpbl's avatar
jpbl committed
243
  }
yanmorin's avatar
   
yanmorin committed
244
  return false;
jpbl's avatar
jpbl committed
245
246
}

yanmorin's avatar
   
yanmorin committed
247
248
249
//THREAD=Main
bool
ManagerImpl::hangupCall(const CallID& id)
jpbl's avatar
jpbl committed
250
{
251
  stopTone(true);
yanmorin's avatar
   
yanmorin committed
252
253
254

  AccountID accountid = getAccountFromCall( id );
  if (accountid == AccountNULL) {
255
    _debug("! Manager Hangup Call: Call doesn't exists\n");
yanmorin's avatar
   
yanmorin committed
256
    return false;
jpbl's avatar
jpbl committed
257
  }
yanmorin's avatar
   
yanmorin committed
258
259
260
261
262
263

  bool returnValue = getAccountLink(accountid)->hangup(id);
  removeCallAccount(id);
  switchCall("");

  return returnValue;
jpbl's avatar
jpbl committed
264
265
}

yanmorin's avatar
   
yanmorin committed
266
267
268
//THREAD=Main
bool
ManagerImpl::cancelCall (const CallID& id)
jpbl's avatar
jpbl committed
269
{
270
  stopTone(true);
yanmorin's avatar
   
yanmorin committed
271
272
  AccountID accountid = getAccountFromCall( id );
  if (accountid == AccountNULL) {
273
    _debug("! Manager Cancel Call: Call doesn't exists\n");
yanmorin's avatar
   
yanmorin committed
274
    return false;
jpbl's avatar
jpbl committed
275
  }
yanmorin's avatar
   
yanmorin committed
276
277
278
279
280
281
282
283

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

yanmorin's avatar
   
yanmorin committed
286
287
288
//THREAD=Main
bool
ManagerImpl::onHoldCall(const CallID& id)
jpbl's avatar
jpbl committed
289
{
290
  stopTone(true);
yanmorin's avatar
   
yanmorin committed
291
292
  AccountID accountid = getAccountFromCall( id );
  if (accountid == AccountNULL) {
293
    _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
294
    return false;
jpbl's avatar
jpbl committed
295
  }
yanmorin's avatar
   
yanmorin committed
296
297
298
299
300
301
302
303
304
305
306
307

  bool returnValue = getAccountLink(accountid)->onhold(id);
  removeWaitingCall(id);
  switchCall("");
  
  return returnValue;
}

//THREAD=Main
bool
ManagerImpl::offHoldCall(const CallID& id)
{
308
  stopTone(false);
yanmorin's avatar
   
yanmorin committed
309
310
  AccountID accountid = getAccountFromCall( id );
  if (accountid == AccountNULL) {
311
    _debug("5 Manager OffHold Call: Call doesn't exists\n");
yanmorin's avatar
   
yanmorin committed
312
    return false;
jpbl's avatar
jpbl committed
313
  }
yanmorin's avatar
   
yanmorin committed
314
315
316
317
  bool returnValue = getAccountLink(accountid)->offhold(id);
  switchCall(id);

  if (returnValue) {
jpbl's avatar
jpbl committed
318
319
320
    try {
      getAudioDriver()->startStream();
    } catch(...) {
321
      _debugException("! Manager Off hold could not start audio stream");
jpbl's avatar
jpbl committed
322
323
324
325
326
    }
  }
  return returnValue;
}

yanmorin's avatar
   
yanmorin committed
327
328
329
//THREAD=Main
bool
ManagerImpl::transferCall(const CallID& id, const std::string& to)
jpbl's avatar
jpbl committed
330
{
331
  stopTone(true);
yanmorin's avatar
   
yanmorin committed
332
333
  AccountID accountid = getAccountFromCall( id );
  if (accountid == AccountNULL) {
334
    _debug("! Manager Transfer Call: Call doesn't exists\n");
yanmorin's avatar
   
yanmorin committed
335
    return false;
jpbl's avatar
jpbl committed
336
  }
yanmorin's avatar
   
yanmorin committed
337
338
339
340
341
342
  bool returnValue = getAccountLink(accountid)->transfer(id, to);
  removeWaitingCall(id);
  removeCallAccount(id);
  switchCall("");

  return returnValue;
jpbl's avatar
jpbl committed
343
344
}

yanmorin's avatar
   
yanmorin committed
345
//THREAD=Main
jpbl's avatar
jpbl committed
346
347
348
349
350
351
void
ManagerImpl::mute() {
  _mic_volume_before_mute = _mic_volume;
  setMicVolume(0);
}

yanmorin's avatar
   
yanmorin committed
352
//THREAD=Main
jpbl's avatar
jpbl committed
353
354
355
356
357
358
359
void
ManagerImpl::unmute() {
  if ( _mic_volume == 0 ) {
    setMicVolume(_mic_volume_before_mute);
  }
}

yanmorin's avatar
   
yanmorin committed
360
361
362
//THREAD=Main : Call:Incoming
bool
ManagerImpl::refuseCall (const CallID& id)
jpbl's avatar
jpbl committed
363
{
364
  stopTone(true);
yanmorin's avatar
   
yanmorin committed
365
366
  AccountID accountid = getAccountFromCall( id );
  if (accountid == AccountNULL) {
367
    _debug("! Manager OffHold Call: Call doesn't exists\n");
yanmorin's avatar
   
yanmorin committed
368
369
370
    return false;
  }
  bool returnValue = getAccountLink(accountid)->refuse(id);
yanmorin's avatar
   
yanmorin committed
371
372
373
374
375
376
377
  // if the call was outgoing or established, we didn't refuse it
  // so the method did nothing
  if (returnValue) {
    removeWaitingCall(id);
    removeCallAccount(id);
    switchCall("");
  }
yanmorin's avatar
   
yanmorin committed
378
  return returnValue;
jpbl's avatar
jpbl committed
379
380
}

yanmorin's avatar
   
yanmorin committed
381
//THREAD=Main
jpbl's avatar
jpbl committed
382
383
384
385
386
387
388
389
390
391
392
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
393
//THREAD=Main
jpbl's avatar
jpbl committed
394
395
396
bool
ManagerImpl::initRegisterVoIPLink() 
{
397
  _debugInit("Initiate VoIP Links Registration");
yanmorin's avatar
   
yanmorin committed
398
399
400
401
402
  AccountMap::iterator iter = _accountMap.begin();
  while( iter != _accountMap.end() ) {
    if ( iter->second) {
      iter->second->loadConfig();
      if ( iter->second->shouldInitOnStart() ) {
403
404
        if ( iter->second->init() && iter->second->shouldRegisterOnStart()) {
            iter->second->registerAccount();
yanmorin's avatar
   
yanmorin committed
405
        }
406
407
        // init only the first account
        break;
jpbl's avatar
jpbl committed
408
409
      }
    }
yanmorin's avatar
   
yanmorin committed
410
    iter++;
jpbl's avatar
jpbl committed
411
  }
yanmorin's avatar
   
yanmorin committed
412
  return true;
jpbl's avatar
jpbl committed
413
414
}

yanmorin's avatar
   
yanmorin committed
415
//THREAD=Main
jpbl's avatar
jpbl committed
416
bool
yanmorin's avatar
   
yanmorin committed
417
ManagerImpl::registerVoIPLink(const AccountID& accountId)
jpbl's avatar
jpbl committed
418
419
420
{
  _debug("Register VoIP Link\n");
  int returnValue = false;
421
422
423
424
425
426
427
428
429
430
431
432
433
  // 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 ) {
        iter->second->unregisterAccount();
        iter->second->terminate();
      }
      iter++;
    }
    returnValue = account->registerAccount();
jpbl's avatar
jpbl committed
434
435
436
437
  }
  return returnValue;
}

yanmorin's avatar
   
yanmorin committed
438
//THREAD=Main
jpbl's avatar
jpbl committed
439
bool 
yanmorin's avatar
   
yanmorin committed
440
ManagerImpl::unregisterVoIPLink(const AccountID& accountId)
jpbl's avatar
jpbl committed
441
442
{
  _debug("Unregister VoIP Link\n");
yanmorin's avatar
   
yanmorin committed
443
444
  int returnValue = false;
  if (accountExists( accountId ) ) {
445
    returnValue = getAccount(accountId)->unregisterAccount();
yanmorin's avatar
   
yanmorin committed
446
447
  }
  return returnValue;
jpbl's avatar
jpbl committed
448
449
}

yanmorin's avatar
   
yanmorin committed
450
//THREAD=Main
jpbl's avatar
jpbl committed
451
bool 
yanmorin's avatar
   
yanmorin committed
452
ManagerImpl::sendDtmf(const CallID& id, char code)
jpbl's avatar
jpbl committed
453
{
yanmorin's avatar
   
yanmorin committed
454
455
456
457
458
459
  AccountID accountid = getAccountFromCall( id );
  if (accountid == AccountNULL) {
    _debug("Send DTMF: call doesn't exists\n");
    return false;
  }

jpbl's avatar
jpbl committed
460
  int sendType = getConfigInt(SIGNALISATION, SEND_DTMF_AS);
yanmorin's avatar
   
yanmorin committed
461
  bool returnValue = false;
jpbl's avatar
jpbl committed
462
463
464
  switch (sendType) {
  case 0: // SIP INFO
    playDtmf(code);
yanmorin's avatar
   
yanmorin committed
465
    returnValue = getAccountLink(accountid)->carryingDTMFdigits(id, code);
jpbl's avatar
jpbl committed
466
467
468
469
470
471
472
473
474
475
476
477
    break;

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

yanmorin's avatar
   
yanmorin committed
478
//THREAD=Main | VoIPLink
jpbl's avatar
jpbl committed
479
480
481
bool
ManagerImpl::playDtmf(char code)
{
482
483
484
485
  // HERE are the variable:
  // - boolean variable to play or not (config)
  // - length in milliseconds to play
  // - sample of audiolayer
486
  stopTone(false);
yanmorin's avatar
   
yanmorin committed
487
488
  int hasToPlayTone = getConfigInt(SIGNALISATION, PLAY_DTMF);
  if (!hasToPlayTone) return false;
jpbl's avatar
jpbl committed
489
490
491
492
493
494
495
496
497
498
499

  // 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; }
500
501
502
503
  // number of data sampling in one pulselen depends on samplerate
  // size (n sampling) = time_ms * sampling/s 
  //                     ---------------------
  //                            ms/s
504
505
  int size = (int)(pulselen * ((float)audiolayer->getSampleRate()/1000));

506
507
508
  // 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
509
510
511
512
513
  bool returnValue = false;

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

514
  // copy the sound
515
  if ( _dtmfKey->generateDTMF(_buf, size) ) {
jpbl's avatar
jpbl committed
516
517
518

    // Put buffer to urgentRingBuffer 
    // put the size in bytes...
519
520
    // so size * 1 channel (mono) * sizeof (bytes for the data)
    audiolayer->putUrgent(_buf, size * sizeof(SFLDataFormat));
jpbl's avatar
jpbl committed
521
522
523
524
525
526
527
528
529
530
531
532
533

    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;
  }
534
535

  // TODO: add caching
jpbl's avatar
jpbl committed
536
537
538
539
  delete[] _buf; _buf = 0;
  return returnValue;
}

yanmorin's avatar
   
yanmorin committed
540
541
542


// Multi-thread 
jpbl's avatar
jpbl committed
543
544
bool
ManagerImpl::incomingCallWaiting() {
yanmorin's avatar
   
yanmorin committed
545
  ost::MutexLock m(_waitingCallMutex);
jpbl's avatar
jpbl committed
546
547
548
549
  return (_nbIncomingWaitingCall > 0) ? true : false;
}

void
yanmorin's avatar
   
yanmorin committed
550
551
552
ManagerImpl::addWaitingCall(const CallID& id) {
  ost::MutexLock m(_waitingCallMutex);
  _waitingCall.insert(id);
jpbl's avatar
jpbl committed
553
554
555
556
  _nbIncomingWaitingCall++;
}

void
yanmorin's avatar
   
yanmorin committed
557
558
559
560
561
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
562
563
564
565
  }
}

bool
yanmorin's avatar
   
yanmorin committed
566
567
568
569
570
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
571
  }
yanmorin's avatar
   
yanmorin committed
572
  return true;
jpbl's avatar
jpbl committed
573
574
575
576
}



yanmorin's avatar
   
yanmorin committed
577
578
579
580
581
582
///////////////////////////////////////////////////////////////////////////////
// Management of event peer IP-phone 
////////////////////////////////////////////////////////////////////////////////
// SipEvent Thread 
bool 
ManagerImpl::incomingCall(Call* call, const AccountID& accountId) 
jpbl's avatar
jpbl committed
583
{
yanmorin's avatar
   
yanmorin committed
584
585
586
587
  _debug("Incoming call\n");
  associateCallToAccount(call->getCallId(), accountId);
  if ( !hasCurrentCall() ) {
    call->setConnectionState(Call::Ringing);
jpbl's avatar
jpbl committed
588
    ringtone();
yanmorin's avatar
   
yanmorin committed
589
    switchCall(call->getCallId());
jpbl's avatar
jpbl committed
590
  } else {
yanmorin's avatar
   
yanmorin committed
591
     addWaitingCall(call->getCallId());
jpbl's avatar
jpbl committed
592
593
  }

yanmorin's avatar
   
yanmorin committed
594
595
596
  std::string from = call->getPeerName();
  std::string number = call->getPeerNumber();

jpbl's avatar
jpbl committed
597
598
599
600
601
  if ( !number.empty() ) {
    from.append(" <");
    from.append(number);
    from.append(">");
  }
yanmorin's avatar
   
yanmorin committed
602
603
604
  _gui->incomingCall(accountId, call->getCallId(), from);

  return true;
jpbl's avatar
jpbl committed
605
606
}

yanmorin's avatar
   
yanmorin committed
607
608
609
//THREAD=VoIP
void
ManagerImpl::incomingMessage(const AccountID& accountId, const std::string& message) {
jpbl's avatar
jpbl committed
610
  if (_gui) {
yanmorin's avatar
   
yanmorin committed
611
    _gui->incomingMessage(accountId, message);
jpbl's avatar
jpbl committed
612
613
614
  }
}

yanmorin's avatar
   
yanmorin committed
615
616
617
//THREAD=VoIP CALL=Outgoing
void
ManagerImpl::peerAnsweredCall(const CallID& id)
jpbl's avatar
jpbl committed
618
{
yanmorin's avatar
   
yanmorin committed
619
  if (isCurrentCall(id)) {
620
    stopTone(false);
jpbl's avatar
jpbl committed
621
  }
yanmorin's avatar
   
yanmorin committed
622
  if (_gui) _gui->peerAnsweredCall(id);
jpbl's avatar
jpbl committed
623
624
}

yanmorin's avatar
   
yanmorin committed
625
626
627
//THREAD=VoIP Call=Outgoing
void
ManagerImpl::peerRingingCall(const CallID& id)
jpbl's avatar
jpbl committed
628
{
yanmorin's avatar
   
yanmorin committed
629
  if (isCurrentCall(id)) {
jpbl's avatar
jpbl committed
630
631
    ringback();
  }
yanmorin's avatar
   
yanmorin committed
632
  if (_gui) _gui->peerRingingCall(id);
jpbl's avatar
jpbl committed
633
634
}

yanmorin's avatar
   
yanmorin committed
635
636
637
//THREAD=VoIP Call=Outgoing/Ingoing
void
ManagerImpl::peerHungupCall(const CallID& id)
jpbl's avatar
jpbl committed
638
{
yanmorin's avatar
   
yanmorin committed
639
640
641
642
  AccountID accountid = getAccountFromCall( id );
  if (accountid == AccountNULL) {
    _debug("peerHungupCall: Call doesn't exists\n");
    return;
jpbl's avatar
jpbl committed
643
  }
yanmorin's avatar
   
yanmorin committed
644
  if (isCurrentCall(id)) {
645
    stopTone(true);
yanmorin's avatar
   
yanmorin committed
646
    switchCall("");
jpbl's avatar
jpbl committed
647
  }
yanmorin's avatar
   
yanmorin committed
648
649
  removeWaitingCall(id);
  removeCallAccount(id);
yanmorin's avatar
   
yanmorin committed
650
  if (_gui) _gui->peerHungupCall(id);
jpbl's avatar
jpbl committed
651
652
}

yanmorin's avatar
   
yanmorin committed
653
//THREAD=VoIP
jpbl's avatar
jpbl committed
654
void
yanmorin's avatar
   
yanmorin committed
655
656
657
658
659
ManagerImpl::callBusy(const CallID& id) {
  _debug("Call busy\n");
  if (isCurrentCall(id) ) {
    playATone(Tone::TONE_BUSY);
    switchCall("");
jpbl's avatar
jpbl committed
660
  }
yanmorin's avatar
   
yanmorin committed
661
662
  removeCallAccount(id);
  removeWaitingCall(id);
yanmorin's avatar
   
yanmorin committed
663
  if(_gui) _gui->displayErrorText( id, "Call is busy");
jpbl's avatar
jpbl committed
664
665
}

yanmorin's avatar
   
yanmorin committed
666
//THREAD=VoIP
jpbl's avatar
jpbl committed
667
void
yanmorin's avatar
   
yanmorin committed
668
669
670
671
672
673
674
ManagerImpl::callFailure(const CallID& id) 
{
  _debug("Call failed\n");
  if (isCurrentCall(id) ) {
    playATone(Tone::TONE_BUSY);
    switchCall("");
  }
jpbl's avatar
jpbl committed
675
676
677
  if (_gui) {
    _gui->callFailure(id);
  }
yanmorin's avatar
   
yanmorin committed
678
679
  removeCallAccount(id);
  removeWaitingCall(id);
jpbl's avatar
jpbl committed
680
681
}

yanmorin's avatar
   
yanmorin committed
682
//THREAD=VoIP
jpbl's avatar
jpbl committed
683
void 
yanmorin's avatar
   
yanmorin committed
684
ManagerImpl::displayTextMessage(const CallID& id, const std::string& message)
jpbl's avatar
jpbl committed
685
686
{
  if(_gui) {
yanmorin's avatar
   
yanmorin committed
687
   _gui->displayTextMessage(id, message);
jpbl's avatar
jpbl committed
688
689
690
  }
}

yanmorin's avatar
   
yanmorin committed
691
//THREAD=VoIP
jpbl's avatar
jpbl committed
692
void 
yanmorin's avatar
   
yanmorin committed
693
ManagerImpl::displayErrorText(const CallID& id, const std::string& message)
jpbl's avatar
jpbl committed
694
695
696
697
698
699
700
701
{
  if(_gui) {
    _gui->displayErrorText(id, message);
  } else {
    std::cerr << message << std::endl;
  }
}

yanmorin's avatar
   
yanmorin committed
702
//THREAD=VoIP
jpbl's avatar
jpbl committed
703
void 
yanmorin's avatar
   
yanmorin committed
704
ManagerImpl::displayError (const std::string& error)
jpbl's avatar
jpbl committed
705
706
{
  if(_gui) {
yanmorin's avatar
   
yanmorin committed
707
    _gui->displayError(error);
jpbl's avatar
jpbl committed
708
709
710
  }
}

yanmorin's avatar
   
yanmorin committed
711
//THREAD=VoIP
jpbl's avatar
jpbl committed
712
void 
yanmorin's avatar
   
yanmorin committed
713
ManagerImpl::displayStatus(const std::string& status)
jpbl's avatar
jpbl committed
714
715
716
717
718
719
{
  if(_gui) {
    _gui->displayStatus(status);
  }
}

yanmorin's avatar
   
yanmorin committed
720
//THREAD=VoIP
jpbl's avatar
jpbl committed
721
722
723
724
725
726
727
728
void 
ManagerImpl::displayConfigError (const std::string& message)
{
  if(_gui) {
    _gui->displayConfigError(message);
  }
}

yanmorin's avatar
   
yanmorin committed
729
//THREAD=VoIP
jpbl's avatar
jpbl committed
730
void
yanmorin's avatar
   
yanmorin committed
731
ManagerImpl::startVoiceMessageNotification(const AccountID& accountId, const std::string& nb_msg)
jpbl's avatar
jpbl committed
732
{
yanmorin's avatar
   
yanmorin committed
733
  if (_gui) _gui->sendVoiceNbMessage(accountId, nb_msg);
jpbl's avatar
jpbl committed
734
735
}

yanmorin's avatar
   
yanmorin committed
736
//THREAD=VoIP
jpbl's avatar
jpbl committed
737
void
yanmorin's avatar
   
yanmorin committed
738
ManagerImpl::stopVoiceMessageNotification(const AccountID& accountId)
jpbl's avatar
jpbl committed
739
{
yanmorin's avatar
   
yanmorin committed
740
  if (_gui) _gui->sendVoiceNbMessage(accountId, std::string("0"));
741
} 
jpbl's avatar
jpbl committed
742

yanmorin's avatar
   
yanmorin committed
743
//THREAD=VoIP
jpbl's avatar
jpbl committed
744
void 
yanmorin's avatar
   
yanmorin committed
745
ManagerImpl::registrationSucceed(const AccountID& accountid)
jpbl's avatar
jpbl committed
746
{
747
748
749
750
751
  Account* acc = getAccount(accountid);
  if ( acc ) { 
    acc->setState(true); 
    if (_gui) _gui->sendRegistrationState(accountid, true);
  }
jpbl's avatar
jpbl committed
752
753
}

yanmorin's avatar
   
yanmorin committed
754
//THREAD=VoIP
jpbl's avatar
jpbl committed
755
void 
yanmorin's avatar
   
yanmorin committed
756
ManagerImpl::registrationFailed(const AccountID& accountid)
jpbl's avatar
jpbl committed
757
{
758
759
760
761
762
  Account* acc = getAccount(accountid);
  if ( acc ) { 
    acc->setState(false);
    if (_gui) _gui->sendRegistrationState(accountid, false);
  }
jpbl's avatar
jpbl committed
763
764
765
766
767
768
769
}

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

jpbl's avatar
jpbl committed
773
774
775
776
777
778
  if (_telephoneTone != 0) {
    _toneMutex.enterMutex();
    _telephoneTone->setCurrentTone(toneId);
    _toneMutex.leaveMutex();

    try {
779
780
      AudioLayer* audiolayer = getAudioDriver();
      if (audiolayer) { audiolayer->startStream(); }
jpbl's avatar
jpbl committed
781
782
    } catch(...) {
      _debugException("Off hold could not start audio stream");
783
      return false;
jpbl's avatar
jpbl committed
784
785
786
787
788
789
790
791
792
    }
  }
  return true;
}

/**
 * Multi Thread
 */
void 
793
ManagerImpl::stopTone(bool stopAudio=true) {
yanmorin's avatar
   
yanmorin committed
794
795
796
  int hasToPlayTone = getConfigInt(SIGNALISATION, PLAY_TONES);
  if (!hasToPlayTone) return;

797
798
799
800
801
802
803
  if (stopAudio) {
    try {
      AudioLayer* audiolayer = getAudioDriver();
      if (audiolayer) { audiolayer->stopStream(); }
    } catch(...) {
      _debugException("Stop tone and stop stream");
    }
jpbl's avatar
jpbl committed
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
  }

  _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()
{
824
825
  //return playATone(Tone::TONE_DIALTONE);
  playATone(Tone::TONE_DIALTONE);
jpbl's avatar
jpbl committed
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
}

/**
 * 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
850
  int hasToPlayTone = getConfigInt(SIGNALISATION, PLAY_TONES);
851
  if (!hasToPlayTone) { return; }
yanmorin's avatar
   
yanmorin committed
852

jpbl's avatar
jpbl committed
853
854
855
856
857
858
  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; 
  }
859
860
861
862
863

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

jpbl's avatar
jpbl committed
864
  _toneMutex.enterMutex(); 
865
  bool loadFile = _audiofile.loadFile(ringchoice, sampleRate);
jpbl's avatar
jpbl committed
866
867
868
869
870
871
  _toneMutex.leaveMutex(); 
  if (loadFile) {
    _toneMutex.enterMutex(); 
    _audiofile.start();
    _toneMutex.leaveMutex(); 
    try {
872
      audiolayer->startStream();
jpbl's avatar
jpbl committed
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
    } 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
910
ManagerImpl::notificationIncomingCall(void) {
jpbl's avatar
jpbl committed
911
912
913

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

918
919
920
    Tone tone(frequency.str(), samplerate);
    unsigned int nbSampling = tone.getSize();
    SFLDataFormat buf[nbSampling];
jpbl's avatar
jpbl committed
921
    tone.getNext(buf, tone.getSize());
922
    audiolayer->putUrgent(buf, sizeof(SFLDataFormat)*nbSampling);
jpbl's avatar
jpbl committed
923
924
925
926
927
928
  }
}

/**
 * Multi Thread
 */
yanmorin's avatar
   
yanmorin committed
929
930
bool
ManagerImpl::getStunInfo (StunAddress4& stunSvrAddr, int port) 
jpbl's avatar
jpbl committed
931
932
933
934
{
  StunAddress4 mappedAddr;
  struct in_addr in;
  char* addr;
yanmorin's avatar
   
yanmorin committed
935
936
937
938
939

  //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
940
  if (ok) {
yanmorin's avatar
   
yanmorin committed
941
942
943
    closesocket(fd1);
    //closesocket(fd3);
    //closesocket(fd4);
jpbl's avatar
jpbl committed
944
945
946
947
948
949
    _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
950
    return true;
jpbl's avatar
jpbl committed
951
952
953
  } else {
    _debug("Opening a stun socket pair failed\n");
  }
yanmorin's avatar
   
yanmorin committed
954
  return false;
jpbl's avatar
jpbl committed
955
956
957
}

bool
yanmorin's avatar
   
yanmorin committed
958
ManagerImpl::behindNat(const std::string& svr, int port)
yanmorin's avatar
   
yanmorin committed
959
960
961
962
963
964
965
966
967
{
  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
968
  }
yanmorin's avatar
   
yanmorin committed
969
970
971
972
  
  // Firewall address
  //_debug("STUN server: %s\n", svr.data());
  return getStunInfo(stunSvrAddr, port);
jpbl's avatar
jpbl committed
973
974
}

yanmorin's avatar
   
yanmorin committed
975

jpbl's avatar
jpbl committed
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
///////////////////////////////////////////////////////////////////////////////
// Private functions
///////////////////////////////////////////////////////////////////////////////
/**
 * Initialization: Main Thread
 * @return 1: ok
          -1: error directory
           0: unable to load the setting
           2: file doesn't exist yet
 */
int
ManagerImpl::createSettingsPath (void) {
  _path = std::string(HOMEDIR) + DIR_SEPARATOR_STR + "." + PROGDIR;

  if (mkdir (_path.data(), 0755) != 0) {
    // If directory	creation failed
    if (errno != EEXIST) {
      _debug("Cannot create directory: %s\n", strerror(errno));
      return -1;
    }
  }

  // Load user's configuration
  _path = _path + DIR_SEPARATOR_STR + PROGNAME + "rc";
  return _config.populateFromFile(_path);