managerimpl.cpp 63.3 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
29
30
31
32
33
34
35
36
37
38
 *  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"
39
#include "account.h"
jpbl's avatar
jpbl committed
40
41
42
#include "audio/audiolayer.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

#include "user_cfg.h"

48
49
#include "contact/presencestatus.h"

jpbl's avatar
jpbl committed
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#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;
73
  _dbus = NULL;
jpbl's avatar
jpbl committed
74

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

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

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

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

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

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

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

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

112
  void 
jpbl's avatar
jpbl committed
113
114
ManagerImpl::init() 
{
115
116
117
  // Load accounts, init map
  loadAccountMap();

jpbl's avatar
jpbl committed
118
119
120
121
122
123
  initVolume();

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

124
125
126
  initAudioDriver();
  selectAudioDriver();

127
  // Initialize the list of supported audio codecs
jpbl's avatar
jpbl committed
128
129
  initAudioCodec();

130
131
  getAudioInputDeviceList();

jpbl's avatar
jpbl committed
132
133
134
135
136
137
  AudioLayer *audiolayer = getAudioDriver();
  if (audiolayer!=0) {
    unsigned int sampleRate = audiolayer->getSampleRate();

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

    _debugInit("Loading DTMF key");
141
    _dtmfKey = new DTMF(sampleRate);
jpbl's avatar
jpbl committed
142
143
  }

144
  // initRegisterAccounts was here, but we doing it after the gui loaded... 
jpbl's avatar
jpbl committed
145
146
147
148
149
150
151
152
  // 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
153
  unloadAccountMap();
jpbl's avatar
jpbl committed
154
155
156
157
158

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

  _debug("Unload Audio Driver\n");
159
  delete _audiodriver; _audiodriver = NULL;
jpbl's avatar
jpbl committed
160
161

  _debug("Unload Telephone Tone\n");
162
  delete _telephoneTone; _telephoneTone = NULL;
163
164
165

  _debug("Unload Audio Codecs\n");
  _codecDescriptorMap.deleteHandlePointer();
jpbl's avatar
jpbl committed
166
167
}

yanmorin's avatar
   
yanmorin committed
168
169
170
171
bool
ManagerImpl::isCurrentCall(const CallID& callId) {
  ost::MutexLock m(_currentCallMutex);
  return (_currentCallId2 == callId ? true : false);
jpbl's avatar
jpbl committed
172
173
}

yanmorin's avatar
   
yanmorin committed
174
175
176
bool
ManagerImpl::hasCurrentCall() {
  ost::MutexLock m(_currentCallMutex);
Emmanuel Milou's avatar
Bug fix    
Emmanuel Milou committed
177
  _debug("Current call ID = %s\n", _currentCallId2.c_str());
yanmorin's avatar
   
yanmorin committed
178
179
  if ( _currentCallId2 != "") {
    return true;
jpbl's avatar
jpbl committed
180
  }
yanmorin's avatar
   
yanmorin committed
181
  return false;
jpbl's avatar
jpbl committed
182
183
}

yanmorin's avatar
   
yanmorin committed
184
185
186
187
const CallID& 
ManagerImpl::getCurrentCallId() {
  ost::MutexLock m(_currentCallMutex);
  return _currentCallId2;
jpbl's avatar
jpbl committed
188
189
190
}

void
yanmorin's avatar
   
yanmorin committed
191
192
193
ManagerImpl::switchCall(const CallID& id ) {
  ost::MutexLock m(_currentCallMutex);
  _currentCallId2 = id;
jpbl's avatar
jpbl committed
194
195
196
197
198
199
}


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

yanmorin's avatar
   
yanmorin committed
227
//THREAD=Main : for outgoing Call
228
  bool
yanmorin's avatar
   
yanmorin committed
229
ManagerImpl::answerCall(const CallID& id)
jpbl's avatar
jpbl committed
230
{
231
  stopTone(false); 
Emmanuel Milou's avatar
Bug fix    
Emmanuel Milou committed
232
  /*if (hasCurrentCall()) 
233
    { 
234
    onHoldCall(getCurrentCallId());
235
    }*/
yanmorin's avatar
   
yanmorin committed
236
237
238
239
  AccountID accountid = getAccountFromCall( id );
  if (accountid == AccountNULL) {
    _debug("Answering Call: Call doesn't exists\n");
    return false;
jpbl's avatar
jpbl committed
240
  }
yanmorin's avatar
   
yanmorin committed
241
242
243
244
245

  if (!getAccountLink(accountid)->answer(id)) {
    // error when receiving...
    removeCallAccount(id);
    return false;
jpbl's avatar
jpbl committed
246
  }
247
  
248
  //Place current call on hold if it isn't
249
250


yanmorin's avatar
   
yanmorin committed
251
  // if it was waiting, it's waiting no more
252
  if (_dbus) _dbus->getCallManager()->callStateChanged(id, "CURRENT");
yanmorin's avatar
   
yanmorin committed
253
254
255
  removeWaitingCall(id);
  switchCall(id);
  return true;
jpbl's avatar
jpbl committed
256
257
}

yanmorin's avatar
   
yanmorin committed
258
//THREAD=Main
259
  bool 
yanmorin's avatar
   
yanmorin committed
260
ManagerImpl::sendTextMessage(const AccountID& accountId, const std::string& to, const std::string& message) 
jpbl's avatar
jpbl committed
261
{
yanmorin's avatar
   
yanmorin committed
262
263
  if (accountExists(accountId)) {
    return getAccountLink(accountId)->sendMessage(to, message);
jpbl's avatar
jpbl committed
264
  }
yanmorin's avatar
   
yanmorin committed
265
  return false;
jpbl's avatar
jpbl committed
266
267
}

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

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


yanmorin's avatar
   
yanmorin committed
287
  return returnValue;
jpbl's avatar
jpbl committed
288
289
}

yanmorin's avatar
   
yanmorin committed
290
//THREAD=Main
291
  bool
yanmorin's avatar
   
yanmorin committed
292
ManagerImpl::cancelCall (const CallID& id)
jpbl's avatar
jpbl committed
293
{
294
  stopTone(true);
yanmorin's avatar
   
yanmorin committed
295
296
  AccountID accountid = getAccountFromCall( id );
  if (accountid == AccountNULL) {
297
    _debug("! Manager Cancel Call: Call doesn't exists\n");
yanmorin's avatar
   
yanmorin committed
298
    return false;
jpbl's avatar
jpbl committed
299
  }
yanmorin's avatar
   
yanmorin committed
300
301
302
303
304
305

  bool returnValue = getAccountLink(accountid)->cancel(id);
  // it could be a waiting call?
  removeWaitingCall(id);
  removeCallAccount(id);
  switchCall("");
306

yanmorin's avatar
   
yanmorin committed
307
  return returnValue;
jpbl's avatar
jpbl committed
308
309
}

yanmorin's avatar
   
yanmorin committed
310
//THREAD=Main
311
  bool
yanmorin's avatar
   
yanmorin committed
312
ManagerImpl::onHoldCall(const CallID& id)
jpbl's avatar
jpbl committed
313
{
314
  stopTone(true);
yanmorin's avatar
   
yanmorin committed
315
316
  AccountID accountid = getAccountFromCall( id );
  if (accountid == AccountNULL) {
317
    _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
318
    return false;
jpbl's avatar
jpbl committed
319
  }
yanmorin's avatar
   
yanmorin committed
320

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

yanmorin's avatar
   
yanmorin committed
323
  bool returnValue = getAccountLink(accountid)->onhold(id);
324

yanmorin's avatar
   
yanmorin committed
325
  removeWaitingCall(id);
326
  if (_dbus) _dbus->getCallManager()->callStateChanged(id, "HOLD");
yanmorin's avatar
   
yanmorin committed
327
  switchCall("");
328

yanmorin's avatar
   
yanmorin committed
329
330
331
332
  return returnValue;
}

//THREAD=Main
333
  bool
yanmorin's avatar
   
yanmorin committed
334
335
ManagerImpl::offHoldCall(const CallID& id)
{
336
  stopTone(false);
yanmorin's avatar
   
yanmorin committed
337
338
  AccountID accountid = getAccountFromCall( id );
  if (accountid == AccountNULL) {
339
    _debug("5 Manager OffHold Call: Call doesn't exists\n");
yanmorin's avatar
   
yanmorin committed
340
    return false;
jpbl's avatar
jpbl committed
341
  }
342

343
344
345
346
347
  //Place current call on hold if it isn't
  if (hasCurrentCall()) 
  { 
    onHoldCall(getCurrentCallId());
  }
348

349
350
  _debug("Setting OFFHOLD, Account %s, callid %s\n", accountid.c_str(), id.c_str());

yanmorin's avatar
   
yanmorin committed
351
  bool returnValue = getAccountLink(accountid)->offhold(id);
352
  if (_dbus) _dbus->getCallManager()->callStateChanged(id, "UNHOLD");
yanmorin's avatar
   
yanmorin committed
353
354
  switchCall(id);
  if (returnValue) {
jpbl's avatar
jpbl committed
355
    try {
356
      //getAudioDriver()->startStream();
jpbl's avatar
jpbl committed
357
    } catch(...) {
358
      _debugException("! Manager Off hold could not start audio stream");
jpbl's avatar
jpbl committed
359
360
361
362
363
    }
  }
  return returnValue;
}

yanmorin's avatar
   
yanmorin committed
364
//THREAD=Main
365
  bool
yanmorin's avatar
   
yanmorin committed
366
ManagerImpl::transferCall(const CallID& id, const std::string& to)
jpbl's avatar
jpbl committed
367
{
368
  stopTone(true);
yanmorin's avatar
   
yanmorin committed
369
370
  AccountID accountid = getAccountFromCall( id );
  if (accountid == AccountNULL) {
371
    _debug("! Manager Transfer Call: Call doesn't exists\n");
yanmorin's avatar
   
yanmorin committed
372
    return false;
jpbl's avatar
jpbl committed
373
  }
yanmorin's avatar
   
yanmorin committed
374
375
376
  bool returnValue = getAccountLink(accountid)->transfer(id, to);
  removeWaitingCall(id);
  removeCallAccount(id);
377
  if (_dbus) _dbus->getCallManager()->callStateChanged(id, "HUNGUP");
yanmorin's avatar
   
yanmorin committed
378
379
  switchCall("");

Emmanuel Milou's avatar
Emmanuel Milou committed
380

yanmorin's avatar
   
yanmorin committed
381
  return returnValue;
jpbl's avatar
jpbl committed
382
383
}

yanmorin's avatar
   
yanmorin committed
384
//THREAD=Main
jpbl's avatar
jpbl committed
385
386
387
388
389
390
void
ManagerImpl::mute() {
  _mic_volume_before_mute = _mic_volume;
  setMicVolume(0);
}

yanmorin's avatar
   
yanmorin committed
391
//THREAD=Main
jpbl's avatar
jpbl committed
392
393
394
395
396
397
398
void
ManagerImpl::unmute() {
  if ( _mic_volume == 0 ) {
    setMicVolume(_mic_volume_before_mute);
  }
}

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

yanmorin's avatar
   
yanmorin committed
421
//THREAD=Main
422
  bool
jpbl's avatar
jpbl committed
423
424
425
426
427
428
429
430
431
432
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
433
//THREAD=Main
434
  bool
435
ManagerImpl::initRegisterAccounts() 
jpbl's avatar
jpbl committed
436
{
Emmanuel Milou's avatar
Emmanuel Milou committed
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
  _debugInit("Initiate VoIP Links Registration");
  AccountMap::iterator iter = _accountMap.begin();
  while( iter != _accountMap.end() ) {
    if ( iter->second) {
      iter->second->loadConfig();
      if ( iter->second->isEnabled() ) {
	// NOW
	iter->second->registerVoIPLink();
	iter->second->loadContacts();
	iter->second->publishPresence(PRESENCE_ONLINE);
	iter->second->subscribeContactsPresence();
      }
    }
    iter++;
  }
452
  // calls the client notification here in case of errors at startup...
Emmanuel Milou's avatar
Emmanuel Milou committed
453
  if( _audiodriver -> getErrorMessage() != -1 )
454
    notifyErrClient( _audiodriver -> getErrorMessage() );
Emmanuel Milou's avatar
Emmanuel Milou committed
455
  return true;
jpbl's avatar
jpbl committed
456
457
}

yanmorin's avatar
   
yanmorin committed
458
//THREAD=Main
459
// Currently unused
460
  bool
461
ManagerImpl::registerAccount(const AccountID& accountId)
jpbl's avatar
jpbl committed
462
{
463
464
  _debug("Register one VoIP Link\n");

465
466
467
468
469
470
471
  // 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 ) {
472
	iter->second->unregisterVoIPLink();
473
474
475
      }
      iter++;
    }
476
    // NOW
477
    account->registerVoIPLink();
478
479
480
    account->loadContacts();
    account->publishPresence(PRESENCE_ONLINE);
    account->subscribeContactsPresence();
jpbl's avatar
jpbl committed
481
  }
482
  return true;
jpbl's avatar
jpbl committed
483
484
}

yanmorin's avatar
   
yanmorin committed
485
//THREAD=Main
486
// Currently unused
487
  bool 
488
ManagerImpl::unregisterAccount(const AccountID& accountId)
jpbl's avatar
jpbl committed
489
{
490
491
  _debug("Unregister one VoIP Link\n");

yanmorin's avatar
   
yanmorin committed
492
  if (accountExists( accountId ) ) {
493
    getAccount(accountId)->unregisterVoIPLink();
yanmorin's avatar
   
yanmorin committed
494
  }
495
  return true;
jpbl's avatar
jpbl committed
496
497
}

yanmorin's avatar
   
yanmorin committed
498
//THREAD=Main
499
  bool 
yanmorin's avatar
   
yanmorin committed
500
ManagerImpl::sendDtmf(const CallID& id, char code)
jpbl's avatar
jpbl committed
501
{
yanmorin's avatar
   
yanmorin committed
502
503
  AccountID accountid = getAccountFromCall( id );
  if (accountid == AccountNULL) {
Emmanuel Milou's avatar
Emmanuel Milou committed
504
505
    //_debug("Send DTMF: call doesn't exists\n");
    playDtmf(code, false);
yanmorin's avatar
   
yanmorin committed
506
507
508
    return false;
  }

jpbl's avatar
jpbl committed
509
  int sendType = getConfigInt(SIGNALISATION, SEND_DTMF_AS);
yanmorin's avatar
   
yanmorin committed
510
  bool returnValue = false;
jpbl's avatar
jpbl committed
511
  switch (sendType) {
512
    case 0: // SIP INFO
Emmanuel Milou's avatar
Emmanuel Milou committed
513
      playDtmf(code , true);
514
515
516
517
518
519
520
521
522
      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
523
524
525
526
  }
  return returnValue;
}

yanmorin's avatar
   
yanmorin committed
527
//THREAD=Main | VoIPLink
528
  bool
Emmanuel Milou's avatar
Emmanuel Milou committed
529
ManagerImpl::playDtmf(char code, bool isTalking)
jpbl's avatar
jpbl committed
530
{
531
532
533
534
  // HERE are the variable:
  // - boolean variable to play or not (config)
  // - length in milliseconds to play
  // - sample of audiolayer
535
  stopTone(false);
yanmorin's avatar
   
yanmorin committed
536
537
  int hasToPlayTone = getConfigInt(SIGNALISATION, PLAY_DTMF);
  if (!hasToPlayTone) return false;
jpbl's avatar
jpbl committed
538
539
540
541
542
543
544
545
546
547
548

  // 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; }
549
550
551
552
  // number of data sampling in one pulselen depends on samplerate
  // size (n sampling) = time_ms * sampling/s 
  //                     ---------------------
  //                            ms/s
553
554
  int size = (int)(pulselen * ((float)audiolayer->getSampleRate()/1000));

555
556
557
  // 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
558
559
560
561
562
  bool returnValue = false;

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

563
  // copy the sound
564
  if ( _dtmfKey->generateDTMF(_buf, size) ) {
jpbl's avatar
jpbl committed
565
566
567

    // Put buffer to urgentRingBuffer 
    // put the size in bytes...
568
    // so size * 1 channel (mono) * sizeof (bytes for the data)
Emmanuel Milou's avatar
Emmanuel Milou committed
569
    audiolayer->playSamples(_buf, size * sizeof(SFLDataFormat), isTalking);
570
    //audiolayer->putUrgent(_buf, size * sizeof(SFLDataFormat));
jpbl's avatar
jpbl committed
571

572
    // We activate the stream if it's not active yet.
573
    //if (!audiolayer->isStreamActive()) {
Emmanuel Milou's avatar
Emmanuel Milou committed
574
    //audiolayer->startStream();
575
    //} else {
Emmanuel Milou's avatar
Emmanuel Milou committed
576
577
    //_debugAlsa("send dtmf - sleep\n");
    //audiolayer->sleep(pulselen); // in milliseconds
578
    //}
jpbl's avatar
jpbl committed
579
  }
580
  returnValue = true;
581

Emmanuel Milou's avatar
Emmanuel Milou committed
582
583
584
  // TODO: add caching
  delete[] _buf; _buf = 0;
  return returnValue;
jpbl's avatar
jpbl committed
585
586
}

yanmorin's avatar
   
yanmorin committed
587
// Multi-thread 
jpbl's avatar
jpbl committed
588
589
bool
ManagerImpl::incomingCallWaiting() {
yanmorin's avatar
   
yanmorin committed
590
  ost::MutexLock m(_waitingCallMutex);
jpbl's avatar
jpbl committed
591
592
593
594
  return (_nbIncomingWaitingCall > 0) ? true : false;
}

void
yanmorin's avatar
   
yanmorin committed
595
596
597
ManagerImpl::addWaitingCall(const CallID& id) {
  ost::MutexLock m(_waitingCallMutex);
  _waitingCall.insert(id);
jpbl's avatar
jpbl committed
598
599
600
601
  _nbIncomingWaitingCall++;
}

void
yanmorin's avatar
   
yanmorin committed
602
603
604
605
606
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
607
608
609
610
  }
}

bool
yanmorin's avatar
   
yanmorin committed
611
612
613
614
615
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
616
  }
yanmorin's avatar
   
yanmorin committed
617
  return true;
jpbl's avatar
jpbl committed
618
619
620
621
}



yanmorin's avatar
   
yanmorin committed
622
623
624
625
///////////////////////////////////////////////////////////////////////////////
// Management of event peer IP-phone 
////////////////////////////////////////////////////////////////////////////////
// SipEvent Thread 
626
  bool 
yanmorin's avatar
   
yanmorin committed
627
ManagerImpl::incomingCall(Call* call, const AccountID& accountId) 
jpbl's avatar
jpbl committed
628
{
yanmorin's avatar
   
yanmorin committed
629
  _debug("Incoming call\n");
630

yanmorin's avatar
   
yanmorin committed
631
  associateCallToAccount(call->getCallId(), accountId);
632

yanmorin's avatar
   
yanmorin committed
633
634
  if ( !hasCurrentCall() ) {
    call->setConnectionState(Call::Ringing);
jpbl's avatar
jpbl committed
635
    ringtone();
yanmorin's avatar
   
yanmorin committed
636
    switchCall(call->getCallId());
jpbl's avatar
jpbl committed
637
  } else {
638
    addWaitingCall(call->getCallId());
jpbl's avatar
jpbl committed
639
640
  }

yanmorin's avatar
   
yanmorin committed
641
642
643
  std::string from = call->getPeerName();
  std::string number = call->getPeerNumber();

644
  if (from != "" && number != "") {
jpbl's avatar
jpbl committed
645
646
647
    from.append(" <");
    from.append(number);
    from.append(">");
648
649
650
651
  } else if ( from.empty() ) {
    from.append("<");
    from.append(number);
    from.append(">");
jpbl's avatar
jpbl committed
652
  }
653
  _dbus->getCallManager()->incomingCall(accountId, call->getCallId(), from);
yanmorin's avatar
   
yanmorin committed
654
  return true;
jpbl's avatar
jpbl committed
655
656
}

yanmorin's avatar
   
yanmorin committed
657
658
659
//THREAD=VoIP
void
ManagerImpl::incomingMessage(const AccountID& accountId, const std::string& message) {
660
661
  if (_dbus) {
    _dbus->getCallManager()->incomingMessage(accountId, message);
jpbl's avatar
jpbl committed
662
663
664
  }
}

yanmorin's avatar
   
yanmorin committed
665
//THREAD=VoIP CALL=Outgoing
666
  void
yanmorin's avatar
   
yanmorin committed
667
ManagerImpl::peerAnsweredCall(const CallID& id)
jpbl's avatar
jpbl committed
668
{
yanmorin's avatar
   
yanmorin committed
669
  if (isCurrentCall(id)) {
670
    stopTone(false);
jpbl's avatar
jpbl committed
671
  }
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
672
  if (_dbus) _dbus->getCallManager()->callStateChanged(id, "CURRENT");
jpbl's avatar
jpbl committed
673
674
}

yanmorin's avatar
   
yanmorin committed
675
//THREAD=VoIP Call=Outgoing
676
  void
yanmorin's avatar
   
yanmorin committed
677
ManagerImpl::peerRingingCall(const CallID& id)
jpbl's avatar
jpbl committed
678
{
yanmorin's avatar
   
yanmorin committed
679
  if (isCurrentCall(id)) {
jpbl's avatar
jpbl committed
680
681
    ringback();
  }
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
682
  if (_dbus) _dbus->getCallManager()->callStateChanged(id, "RINGING");
jpbl's avatar
jpbl committed
683
684
}

yanmorin's avatar
   
yanmorin committed
685
//THREAD=VoIP Call=Outgoing/Ingoing
686
  void
yanmorin's avatar
   
yanmorin committed
687
ManagerImpl::peerHungupCall(const CallID& id)
jpbl's avatar
jpbl committed
688
{
yanmorin's avatar
   
yanmorin committed
689
690
691
692
  AccountID accountid = getAccountFromCall( id );
  if (accountid == AccountNULL) {
    _debug("peerHungupCall: Call doesn't exists\n");
    return;
jpbl's avatar
jpbl committed
693
  }
694
  if (_dbus) _dbus->getCallManager()->callStateChanged(id, "HUNGUP");
yanmorin's avatar
   
yanmorin committed
695
  if (isCurrentCall(id)) {
696
    stopTone(true);
yanmorin's avatar
   
yanmorin committed
697
    switchCall("");
jpbl's avatar
jpbl committed
698
  }
yanmorin's avatar
   
yanmorin committed
699
700
  removeWaitingCall(id);
  removeCallAccount(id);
701

jpbl's avatar
jpbl committed
702
703
}

yanmorin's avatar
   
yanmorin committed
704
//THREAD=VoIP
jpbl's avatar
jpbl committed
705
void
yanmorin's avatar
   
yanmorin committed
706
707
ManagerImpl::callBusy(const CallID& id) {
  _debug("Call busy\n");
708

709
  if (_dbus) _dbus->getCallManager()->callStateChanged(id, "BUSY");
yanmorin's avatar
   
yanmorin committed
710
711
712
  if (isCurrentCall(id) ) {
    playATone(Tone::TONE_BUSY);
    switchCall("");
jpbl's avatar
jpbl committed
713
  }
yanmorin's avatar
   
yanmorin committed
714
715
  removeCallAccount(id);
  removeWaitingCall(id);
jpbl's avatar
jpbl committed
716
717
}

yanmorin's avatar
   
yanmorin committed
718
//THREAD=VoIP
719
  void
yanmorin's avatar
   
yanmorin committed
720
721
ManagerImpl::callFailure(const CallID& id) 
{
722
  if (_dbus) _dbus->getCallManager()->callStateChanged(id, "FAILURE");
Emmanuel Milou's avatar
Emmanuel Milou committed
723
  _debug("CALL ID = %s\n" , id.c_str());
yanmorin's avatar
   
yanmorin committed
724
725
726
727
728
729
  if (isCurrentCall(id) ) {
    playATone(Tone::TONE_BUSY);
    switchCall("");
  }
  removeCallAccount(id);
  removeWaitingCall(id);
730

jpbl's avatar
jpbl committed
731
732
}

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

yanmorin's avatar
   
yanmorin committed
742
//THREAD=VoIP
743
  void 
yanmorin's avatar
   
yanmorin committed
744
ManagerImpl::displayErrorText(const CallID& id, const std::string& message)
jpbl's avatar
jpbl committed
745
{
746
  /*if(_gui) {
jpbl's avatar
jpbl committed
747
    _gui->displayErrorText(id, message);
748
    } else {
jpbl's avatar
jpbl committed
749
    std::cerr << message << std::endl;
750
    }*/
jpbl's avatar
jpbl committed
751
752
}

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

yanmorin's avatar
   
yanmorin committed
762
//THREAD=VoIP
763
  void 
yanmorin's avatar
   
yanmorin committed
764
ManagerImpl::displayStatus(const std::string& status)
jpbl's avatar
jpbl committed
765
{
766
  /*if(_gui) {
jpbl's avatar
jpbl committed
767
    _gui->displayStatus(status);
768
    }*/
jpbl's avatar
jpbl committed
769
770
}

yanmorin's avatar
   
yanmorin committed
771
//THREAD=VoIP
772
  void 
jpbl's avatar
jpbl committed
773
774
ManagerImpl::displayConfigError (const std::string& message)
{
775
  /*if(_gui) {
jpbl's avatar
jpbl committed
776
    _gui->displayConfigError(message);
777
    }*/
jpbl's avatar
jpbl committed
778
779
}

yanmorin's avatar
   
yanmorin committed
780
//THREAD=VoIP
781
  void
yanmorin's avatar
   
yanmorin committed
782
ManagerImpl::startVoiceMessageNotification(const AccountID& accountId, const std::string& nb_msg)
jpbl's avatar
jpbl committed
783
{
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
784
  if (_dbus) _dbus->getCallManager()->voiceMailNotify(accountId, atoi(nb_msg.c_str()) );
jpbl's avatar
jpbl committed
785
786
}

yanmorin's avatar
   
yanmorin committed
787
//THREAD=VoIP
788
  void
yanmorin's avatar
   
yanmorin committed
789
ManagerImpl::stopVoiceMessageNotification(const AccountID& accountId)
jpbl's avatar
jpbl committed
790
{
Emmanuel Milou's avatar
nothing    
Emmanuel Milou committed
791
  // TODO : do not notify when no messages
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
792
  if (_dbus) _dbus->getCallManager()->voiceMailNotify(accountId, 0 );
793
} 
jpbl's avatar
jpbl committed
794

yanmorin's avatar
   
yanmorin committed
795
//THREAD=VoIP
796
  void 
yanmorin's avatar
   
yanmorin committed
797
ManagerImpl::registrationSucceed(const AccountID& accountid)
jpbl's avatar
jpbl committed
798
{
799
  Account* acc = getAccount(accountid);
800
  if ( acc ) { 
801
    _debug("REGISTRATION SUCCEED\n");
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
802
    if (_dbus) _dbus->getConfigurationManager()->accountsChanged();
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
803
  }
jpbl's avatar
jpbl committed
804
805
}

806
807
808
809
//THREAD=VoIP
  void 
ManagerImpl::unregistrationSucceed(const AccountID& accountid)
{
810
811
  _debug("UNREGISTRATION SUCCEED\n");
  if (_dbus) _dbus->getConfigurationManager()->accountsChanged();
812
813
}

yanmorin's avatar
   
yanmorin committed
814
//THREAD=VoIP
815
  void 
yanmorin's avatar
   
yanmorin committed
816
ManagerImpl::registrationFailed(const AccountID& accountid)
jpbl's avatar
jpbl committed
817
{
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
818
  Account* acc = getAccount(accountid);
819
  if ( acc ) { 
820
    _debug("REGISTRATION FAILED\n");
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
821
    if (_dbus) _dbus->getConfigurationManager()->accountsChanged();
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
822
  }
jpbl's avatar
jpbl committed
823
824
}

Emmanuel Milou's avatar
nothing    
Emmanuel Milou committed
825
826
827
828
829
830
831
832
833
834
835
//THREAD=VoIP
  void 
ManagerImpl::registrationTrying(const AccountID& accountid)
{
  Account* acc = getAccount(accountid);
  if ( acc ) { 
    _debug("REGISTRATION TRYING\n");
    if (_dbus) _dbus->getConfigurationManager()->accountsChanged();
  }
}

jpbl's avatar
jpbl committed
836
837
838
839
840
/**
 * Multi Thread
 */
bool 
ManagerImpl::playATone(Tone::TONEID toneId) {
yanmorin's avatar
   
yanmorin committed
841
842
843
  int hasToPlayTone = getConfigInt(SIGNALISATION, PLAY_TONES);
  if (!hasToPlayTone) return false;

jpbl's avatar
jpbl committed
844
845
846
847
848
  if (_telephoneTone != 0) {
    _toneMutex.enterMutex();
    _telephoneTone->setCurrentTone(toneId);
    _toneMutex.leaveMutex();

849
850
851
852
    AudioLoop* audioloop = getTelephoneTone();
    unsigned int nbSampling = audioloop->getSize();
    AudioLayer* audiolayer = getAudioDriver();
    SFLDataFormat buf[nbSampling];
853
    if ( audiolayer ) { 
854
      audiolayer->putUrgent( buf, nbSampling );
jpbl's avatar
jpbl committed
855
    }
856
857
    else 
      return false;
jpbl's avatar
jpbl committed
858
  }
859
  return true;
jpbl's avatar
jpbl committed
860
861
862
863
864
865
}

/**
 * Multi Thread
 */
void 
866
ManagerImpl::stopTone(bool stopAudio=true) {
yanmorin's avatar
   
yanmorin committed
867
868
869
  int hasToPlayTone = getConfigInt(SIGNALISATION, PLAY_TONES);
  if (!hasToPlayTone) return;

870
  if (stopAudio) {
871
872
    AudioLayer* audiolayer = getAudioDriver();
    if (audiolayer) { audiolayer->stopStream(); }
jpbl's avatar
jpbl committed
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
  }

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

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

/**
 * Multi Thread
 */
890
  bool
jpbl's avatar
jpbl committed
891
892
ManagerImpl::playTone()
{
893
  playATone(Tone::TONE_DIALTONE);
jpbl's avatar
jpbl committed
894
895
}

896
897
898
899
900
901
902
903
904
/**
 * Multi Thread
 */
  bool
ManagerImpl::playToneWithMessage()
{
  playATone(Tone::TONE_CONGESTION);
}

jpbl's avatar
jpbl committed
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
/**
 * Multi Thread
 */
void
ManagerImpl::congestion () {
  playATone(Tone::TONE_CONGESTION);
}

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

/**
 * Multi Thread
 */
924
  void
jpbl's avatar
jpbl committed
925
926
ManagerImpl::ringtone() 
{
Emmanuel Milou's avatar
Emmanuel Milou committed
927
  // int hasToPlayTone = getConfigInt(SIGNALISATION, PLAY_TONES);
928
929
  if( isRingtoneEnabled() )
  {
Emmanuel Milou's avatar
Emmanuel Milou committed
930
931
932
933
934
935
936
937
938
939
940
    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; 
    }

    AudioLayer* audiolayer = getAudioDriver();
    if (audiolayer==0) { return; }
    int sampleRate  = audiolayer->getSampleRate();
    AudioCodec* codecForTone = _codecDescriptorMap.getFirstCodecAvailable();
941

942
    _toneMutex.enterMutex(); 
Emmanuel Milou's avatar
Emmanuel Milou committed
943
    bool loadFile = _audiofile.loadFile(ringchoice, codecForTone , sampleRate);
944
    _toneMutex.leaveMutex(); 
Emmanuel Milou's avatar
Emmanuel Milou committed
945
946
947
948
949
950
951
952
953
954
955
956
957
958
    if (loadFile) {
      _toneMutex.enterMutex(); 
      _audiofile.start();
      _toneMutex.leaveMutex(); 
      int size = _audiofile.getSize();
      SFLDataFormat output[ size ];
      _audiofile.getNext(output, size , 100);
      audiolayer->putUrgent( output , size );
    } else {
      ringback();
    }
  }
  else
  {