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

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

38
39
#include "conference.h"

jpbl's avatar
jpbl committed
40
#include "manager.h"
41
#include "account.h"
42
#include "sipaccount.h"
jpbl's avatar
jpbl committed
43
#include "audio/audiolayer.h"
44
45
#include "audio/alsalayer.h"
#include "audio/pulselayer.h"
jpbl's avatar
jpbl committed
46
47
#include "audio/tonelist.h"

yanmorin's avatar
   
yanmorin committed
48
#include "accountcreator.h" // create new account
49
50
#include "sipvoiplink.h"

jpbl's avatar
jpbl committed
51
52
53
54
55
56
57
#include "user_cfg.h"

#define fill_config_str(name, value) \
  (_config.addConfigTreeItem(section, Conf::ConfigTreeItem(std::string(name), std::string(value), type_str)))
#define fill_config_int(name, value) \
  (_config.addConfigTreeItem(section, Conf::ConfigTreeItem(std::string(name), std::string(value), type_int)))

58
ManagerImpl::ManagerImpl (void)
59
        : _hasTriedToRegister (false)
Yun Liu's avatar
Yun Liu committed
60
        , _config()
61
        , _currentCallId2()
62
        , _currentCallMutex()
63
64
65
        , _codecBuilder (NULL)
        , _audiodriver (NULL)
        , _dtmfKey (NULL)
Yun Liu's avatar
Yun Liu committed
66
        , _codecDescriptorMap()
67
        , _toneMutex()
68
        , _telephoneTone (NULL)
Yun Liu's avatar
Yun Liu committed
69
        , _audiofile()
70
71
        , _spkr_volume (0)
        , _mic_volume (0)
72
        , _mutex()
73
        , _dbus (NULL)
Yun Liu's avatar
Yun Liu committed
74
        , _waitingCall()
75
        , _waitingCallMutex()
76
77
78
79
        , _nbIncomingWaitingCall (0)
        , _path ("")
        , _exist (0)
        , _setupLoaded (false)
Yun Liu's avatar
Yun Liu committed
80
        , _firewallPort()
81
82
        , _firewallAddr ("")
        , _hasZeroconf (false)
Yun Liu's avatar
Yun Liu committed
83
        , _callAccountMap()
84
        , _callAccountMapMutex()
Emmanuel Milou's avatar
Emmanuel Milou committed
85
        , _callConfigMap()
Yun Liu's avatar
Yun Liu committed
86
        , _accountMap()
87
        , _cleaner (NULL)
88
        , _history (NULL)
jpbl's avatar
jpbl committed
89
{
90

91
    // initialize random generator for call id
92
    srand (time (NULL));
yanmorin's avatar
   
yanmorin committed
93

94
    _cleaner = new NumberCleaner ();
95
    _history = new HistoryManager ();
96

yanmorin's avatar
   
yanmorin committed
97
#ifdef TEST
98
99
100
101
    testAccountMap();
    loadAccountMap();
    testCallAccountMap();
    unloadAccountMap();
yanmorin's avatar
   
yanmorin committed
102
103
#endif

104
105
    // should be call before initConfigFile
    // loadAccountMap();, called in init() now.
jpbl's avatar
jpbl committed
106
107
108
}

// never call if we use only the singleton...
109
ManagerImpl::~ManagerImpl (void)
jpbl's avatar
jpbl committed
110
{
111
    // terminate();
112
113
114
    delete _cleaner;
    _cleaner=0;
    _debug ("%s stop correctly.\n", PROGNAME);
jpbl's avatar
jpbl committed
115
116
}

117
void
118
ManagerImpl::init()
jpbl's avatar
jpbl committed
119
{
120
121
    // Load accounts, init map
    loadAccountMap();
122

123
    initVolume();
124

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

129
    initAudioDriver();
130

131
    selectAudioDriver();
jpbl's avatar
jpbl committed
132

133
134
    // Initialize the list of supported audio codecs
    initAudioCodec();
135

136
    AudioLayer *audiolayer = getAudioDriver();
137

138
    if (audiolayer != 0) {
139
        unsigned int sampleRate = audiolayer->getSampleRate();
jpbl's avatar
jpbl committed
140

141
142
143
        _debugInit ("Load Telephone Tone");
        std::string country = getConfigString (PREFERENCES, ZONE_TONE);
        _telephoneTone = new TelephoneTone (country, sampleRate);
jpbl's avatar
jpbl committed
144

145
146
        _debugInit ("Loading DTMF key");
        _dtmfKey = new DTMF (sampleRate);
147
    }
148
149

    if (audiolayer == 0)
150
        audiolayer->stopStream();
151
152
153


    // Load the history
154
    _history->load_history (getConfigInt (PREFERENCES, CONFIG_HISTORY_LIMIT));
jpbl's avatar
jpbl committed
155
156
157
158
}

void ManagerImpl::terminate()
{
159
    _debug ("ManagerImpl::terminate \n");
160
    saveConfig();
jpbl's avatar
jpbl committed
161

162
    unloadAccountMap();
163

164
    _debug ("Unload DTMF Key \n");
165
    delete _dtmfKey;
jpbl's avatar
jpbl committed
166

167
168
169
    _debug ("Unload Audio Driver \n");
    delete _audiodriver;
    _audiodriver = NULL;
jpbl's avatar
jpbl committed
170

171
172
173
    _debug ("Unload Telephone Tone \n");
    delete _telephoneTone;
    _telephoneTone = NULL;
174

175
    _debug ("Unload Audio Codecs \n");
176
    _codecDescriptorMap.deleteHandlePointer();
177

jpbl's avatar
jpbl committed
178
179
}

yanmorin's avatar
   
yanmorin committed
180
bool
181
182
183
ManagerImpl::isCurrentCall (const CallID& callId)
{
    return (_currentCallId2 == callId ? true : false);
jpbl's avatar
jpbl committed
184
185
}

yanmorin's avatar
   
yanmorin committed
186
bool
187
188
ManagerImpl::hasCurrentCall()
{
189
    _debug ("ManagerImpl::hasCurrentCall current call ID = %s\n", _currentCallId2.c_str());
190
191
192
193
194
195

    if (_currentCallId2 != "") {
        return true;
    }

    return false;
jpbl's avatar
jpbl committed
196
197
}

198
const CallID&
199
200
201
ManagerImpl::getCurrentCallId()
{
    return _currentCallId2;
jpbl's avatar
jpbl committed
202
203
204
}

void
205
206
207
ManagerImpl::switchCall (const CallID& id)
{
    ost::MutexLock m (_currentCallMutex);
208
    _debug("------------------------- SWITCH %s ---------------------------\n", id.c_str());
209
    _currentCallId2 = id;
jpbl's avatar
jpbl committed
210
211
212
213
214
215
}


///////////////////////////////////////////////////////////////////////////////
// Management of events' IP-phone user
///////////////////////////////////////////////////////////////////////////////
216
/* Main Thread */
Emmanuel Milou's avatar
Emmanuel Milou committed
217

218
219
bool
ManagerImpl::outgoingCall (const std::string& accountid, const CallID& id, const std::string& to)
yanmorin's avatar
   
yanmorin committed
220
{
221
    std::string pattern, to_cleaned;
Emmanuel Milou's avatar
Emmanuel Milou committed
222
223
    Call::CallConfiguration callConfig;
    SIPVoIPLink *siplink;
224

225
    _debug ("ManagerImpl::outgoingCall(%s)\n", id.c_str());
226

227
228
    if (getConfigString (HOOKS, PHONE_NUMBER_HOOK_ENABLED) ==  "1")
        _cleaner->set_phone_number_prefix (getConfigString (HOOKS, PHONE_NUMBER_HOOK_ADD_PREFIX));
229
230
    else
        _cleaner->set_phone_number_prefix ("");
231

232
    to_cleaned = _cleaner->clean (to);
Emmanuel Milou's avatar
Emmanuel Milou committed
233
234

    /* Check what kind of call we are dealing with */
235
    check_call_configuration (id, to_cleaned, &callConfig);
236

237
238
239
240
241
242
243
244
245
    if (hasCurrentCall()) {
	
	_debug ("ManagerImpl::outgoingCall() Has current call (id %s) put it onhold\n", getCurrentCallId().c_str());	
	// if this is not a conferenceand this and is not a conference participant
	if (!isConference(getCurrentCallId()) && !participToConference(getCurrentCallId()))
	{
	    _debug ("ManagerImpl::outgoingCall() Put the current call (ID=%s) on hold\n", getCurrentCallId().c_str());
	    onHoldCall (getCurrentCallId());
	}
Alexandre Savard's avatar
Alexandre Savard committed
246
	else if (isConference(getCurrentCallId()))
247
	{
Alexandre Savard's avatar
Alexandre Savard committed
248
249
	    _debug ("ManagerImpl::outgoingCall() detach main participant from conference\n");
	    detachParticipant();
250
251
252
	}
    }

Emmanuel Milou's avatar
Emmanuel Milou committed
253
    if (callConfig == Call::IPtoIP) {
254
        _debug ("ManagerImpl::outgoingCall Start IP to IP call\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
255
        /* We need to retrieve the sip voiplink instance */
256
257
        siplink = SIPVoIPLink::instance ("");

258
        if (siplink->new_ip_to_ip_call (id, to_cleaned)) {
Emmanuel Milou's avatar
Emmanuel Milou committed
259
260
            switchCall (id);
            return true;
261
        } else {
Emmanuel Milou's avatar
Emmanuel Milou committed
262
263
            callFailure (id);
        }
264

Emmanuel Milou's avatar
Emmanuel Milou committed
265
        return false;
266
    }
267

268
269
    if (!accountExists (accountid)) {
        _debug ("! Manager Error: Outgoing Call: account doesn't exist\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
270
271
        return false;
    }
272

273
274
    if (getAccountFromCall (id) != AccountNULL) {
        _debug ("! Manager Error: Outgoing Call: call id already exists\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
275
276
        return false;
    }
277
278


279
280
281
282
283
284
    _debug ("- Manager Action: Adding Outgoing Call %s on account %s\n", id.data(), accountid.data());

    associateCallToAccount (id, accountid);

    if (getAccountLink (accountid)->newOutgoingCall (id, to_cleaned)) {
        switchCall (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
285
286
        return true;
    } else {
287
288
        callFailure (id);
        _debug ("! Manager Error: An error occur, the call was not created\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
289
    }
290

Emmanuel Milou's avatar
Emmanuel Milou committed
291
    return false;
jpbl's avatar
jpbl committed
292
293
}

yanmorin's avatar
   
yanmorin committed
294
//THREAD=Main : for outgoing Call
295
296
bool
ManagerImpl::answerCall (const CallID& id)
jpbl's avatar
jpbl committed
297
{
298
299

    _debug("ManagerImpl::answerCall(%s)", id.c_str());
300
301

    stopTone (true);
302

303
304
305
306
307
308
309
310
311
312
313
314
    AccountID currentAccountId;
    currentAccountId = getAccountFromCall (id);
    if(currentAccountId == AccountNULL) {
        _debug("ManagerImpl::answerCall : AccountId is null\n");
        return false;
    }
    
    Call* currentCall = NULL;
    currentCall = getAccountLink (currentAccountId)->getCall (id);
    if (currentCall == NULL) {
        _debug("ManagerImpl::answerCall : currentCall is null\n");
    }
Alexandre Savard's avatar
Alexandre Savard committed
315
    /*
316
317
318
319
320
321
    Call* lastCall = NULL;
    if (!getCurrentCallId().empty()) {
        lastCall = getAccountLink (currentAccountId)->getCall (getCurrentCallId());
        if (lastCall == NULL) {
            _debug("ManagerImpl::answerCall : lastCall is null\n");
        }
322
    }
323

324
325
    _debug ("ManagerImpl::answerCall :: current call->getState %i \n", currentCall->getState());
    _debug ("Try to answer call: %s\n", id.data());
Yun Liu's avatar
Yun Liu committed
326

327
    if (lastCall != NULL ) {
328
        if (lastCall->getState() == Call::Active && !participToConference(getCurrentCallId())) {
329
330
331
            _debug ("* Manager Info: there is currently a call, try to hold it\n");
            onHoldCall (getCurrentCallId());
        }
Alexandre Savard's avatar
Alexandre Savard committed
332
	else if (isConference(getCurrentCallId()))
333
	{
334
	    _debug("Current call particips to a conference! Do not hold it!\n");
335
	}
336
    }
Alexandre Savard's avatar
Alexandre Savard committed
337
338
339
340
341
342
343
344
345
346
    */
    if (hasCurrentCall()) {
	
	_debug ("ManagerImpl::answerCall() Has current call (id %s) put it onhold\n", getCurrentCallId().c_str());	
	// if this is not a conferenceand this and is not a conference participant
	if (!isConference(getCurrentCallId()) && !participToConference(getCurrentCallId()))
	{
	    _debug ("ManagerImpl::answerCall() Put the current call (ID=%s) on hold\n", getCurrentCallId().c_str());
	    onHoldCall (getCurrentCallId());
	}
347
	else if (isConference(getCurrentCallId()) && !participToConference(id))
Alexandre Savard's avatar
Alexandre Savard committed
348
349
350
351
352
	{
	    _debug ("ManagerImpl::answerCall() detach main participant from conference\n");
	    detachParticipant();
	}
    }
353

354
    if (!getAccountLink (currentAccountId)->answer (id)) {
355
356
357
358
        // error when receiving...
        removeCallAccount (id);
        return false;
    }
Alexandre Savard's avatar
Alexandre Savard committed
359

360
361
    // if it was waiting, it's waiting no more
    if (_dbus) _dbus->getCallManager()->callStateChanged (id, "CURRENT");
362
363
364
365
        
    std::string codecName = Manager::instance().getCurrentCodecName (id);
    if (_dbus) _dbus->getCallManager()->currentSelectedCodec (id,codecName.c_str());
        
366
    removeWaitingCall (id);
367

368
369
370
    switchCall (id);

    return true;
jpbl's avatar
jpbl committed
371
372
}

yanmorin's avatar
   
yanmorin committed
373
//THREAD=Main
374
375
bool
ManagerImpl::hangupCall (const CallID& id)
jpbl's avatar
jpbl committed
376
{
377
    _debug ("ManagerImpl::hangupCall()\n");
378
379
380
    PulseLayer *pulselayer;
    AccountID accountid;
    bool returnValue;
381
    AudioLayer *audiolayer;
Emmanuel Milou's avatar
Emmanuel Milou committed
382

383
384
    CallID current_call_id = getCurrentCallId();

385
    stopTone (false);
386
    switchCall (id);
yanmorin's avatar
   
yanmorin committed
387

388
    /* Broadcast a signal over DBus */
389

390
    _debug("ManagerImpl::hangupCall: Send DBUS call state change (HUNGUP) for id %s\n", id.c_str());
391
392
    if (_dbus) _dbus->getCallManager()->callStateChanged (id, "HUNGUP");

393
394
    int nbCalls = getCallList().size();

395
    audiolayer = getAudioDriver();
396
    // stop streamx
397
398
399
    if (! (nbCalls >= 1))
    {
	_debug("ManagerImpl::stop audio stream, ther is only %i call(s) remaining\n", nbCalls);
400
        audiolayer->stopStream();
401
    }
402
   
403
404
    if(participToConference(id))
    {
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459

	AccountID currentAccountId;
	Call* call = NULL;

	currentAccountId = getAccountFromCall (id);
	call = getAccountLink (currentAccountId)->getCall (id);

	ConferenceMap::iterator iter = _conferencemap.find(call->getConfId());
	if(iter != _conferencemap.end())
	{

	    Conference *conf = iter->second;

	    removeParticipant(id);
	    
	    if(conf->getNbParticipants() > 1)
	    {
		switchCall(conf->getConfID());
	    }
	    else if (conf->getNbParticipants() == 1)
	    {
		AccountID currentAccountId;
		Call* call = NULL;
	    
		ParticipantSet participants = conf->getParticipantList();
		ParticipantSet::iterator iter_participant = participants.begin();
		
		// bind main participant to remaining conference call
		if (iter_participant != participants.end()) {
		    
		    // this call is no more a conference participant
		    currentAccountId = getAccountFromCall (*iter_participant);
		    call = getAccountLink (currentAccountId)->getCall (*iter_participant);
		    call->setConfId ("");
		    
		    if (current_call_id != conf->getConfID())
		    {
			onHoldCall(call->getCallId());
			switchCall(current_call_id);
		    }
		    else
		    {
			switchCall(*iter_participant);
		    }
		}
	    
		removeConference(conf->getConfID());
	    }
	    else
	    {
		removeConference(conf->getConfID());
		
		switchCall("");
	    }
	}
460
461
    }

Emmanuel Milou's avatar
Emmanuel Milou committed
462
463
    /* Direct IP to IP call */
    if (getConfigFromCall (id) == Call::IPtoIP) {
464
        returnValue = SIPVoIPLink::instance (AccountNULL)->hangup (id);
465
    }
466

Emmanuel Milou's avatar
Emmanuel Milou committed
467
    /* Classic call, attached to an account */
468
    else {
469
470
        accountid = getAccountFromCall (id);

471
472
        if (accountid == AccountNULL) 
	{
473
            _debug ("! Manager Hangup Call: Call doesn't exists\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
474
475
            return false;
        }
476
477
478
479

        returnValue = getAccountLink (accountid)->hangup (id);

        removeCallAccount (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
480
    }
481

482
    _debug("ManagerImpl::hangupCall CURRENT CALL ID %s\n", getCurrentCallId().c_str());
483

484
    switchCall ("");
485

486
    _debug("ManagerImpl::hangupCall CURRENT CALL ID %s\n", getCurrentCallId().c_str());
487

488
    if (_audiodriver->getLayerType() == PULSEAUDIO && getConfigInt (PREFERENCES , CONFIG_PA_VOLUME_CTRL)) {
489
        pulselayer = dynamic_cast<PulseLayer *> (getAudioDriver());
490
491

        if (pulselayer)  pulselayer->restorePulseAppsVolume();
492
    }
493

494
    return returnValue;
jpbl's avatar
jpbl committed
495
496
}

Alexandre Savard's avatar
Alexandre Savard committed
497
498
499
500
501
502
503
504
505
506
507

bool
ManagerImpl::hangupConference (const ConfID& id)
{
    _debug ("ManagerImpl::hangupConference()\n");

    Conference *conf;
    ConferenceMap::iterator iter_conf = _conferencemap.find(id);

    AccountID currentAccountId;

508
    // Call* call = NULL;
Alexandre Savard's avatar
Alexandre Savard committed
509
510
511
512
513

    if(iter_conf != _conferencemap.end())
    {
	conf = iter_conf->second;
 
514
515
	ParticipantSet participants = conf->getParticipantList();
	ParticipantSet::iterator iter_participant = participants.begin();
Alexandre Savard's avatar
Alexandre Savard committed
516

517
	while(iter_participant != participants.end())
Alexandre Savard's avatar
Alexandre Savard committed
518
	{
519
	    _debug("ManagerImpl::hangupConference participant %s\n", (*iter_participant).c_str());
Alexandre Savard's avatar
Alexandre Savard committed
520

521
	    hangupCall (*iter_participant);
Alexandre Savard's avatar
Alexandre Savard committed
522
523
524
525
526
527
528

	    iter_participant++;

	}

    }

529
530
    switchCall ("");

Alexandre Savard's avatar
Alexandre Savard committed
531
532
533
534
    return true;
}


yanmorin's avatar
   
yanmorin committed
535
//THREAD=Main
536
bool
yanmorin's avatar
   
yanmorin committed
537
ManagerImpl::cancelCall (const CallID& id)
jpbl's avatar
jpbl committed
538
{
Emmanuel Milou's avatar
Emmanuel Milou committed
539
540
    AccountID accountid;
    bool returnValue;
yanmorin's avatar
   
yanmorin committed
541

542
    stopTone (true);
543

Emmanuel Milou's avatar
Emmanuel Milou committed
544
    /* Direct IP to IP call */
545

Emmanuel Milou's avatar
Emmanuel Milou committed
546
    if (getConfigFromCall (id) == Call::IPtoIP) {
547
        returnValue = SIPVoIPLink::instance (AccountNULL)->cancel (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
548
549
550
    }

    /* Classic call, attached to an account */
551
    else {
552
553
        accountid = getAccountFromCall (id);

Emmanuel Milou's avatar
Emmanuel Milou committed
554
        if (accountid == AccountNULL) {
555
            _debug ("! Manager Cancel Call: Call doesn't exists\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
556
557
            return false;
        }
558
559
560
561

        returnValue = getAccountLink (accountid)->cancel (id);

        removeCallAccount (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
562
    }
563

Emmanuel Milou's avatar
Emmanuel Milou committed
564
    // it could be a waiting call?
565
566
567
    removeWaitingCall (id);

    switchCall ("");
Emmanuel Milou's avatar
Emmanuel Milou committed
568
569

    return returnValue;
jpbl's avatar
jpbl committed
570
571
}

yanmorin's avatar
   
yanmorin committed
572
//THREAD=Main
573
574
bool
ManagerImpl::onHoldCall (const CallID& id)
jpbl's avatar
jpbl committed
575
{
Emmanuel Milou's avatar
Emmanuel Milou committed
576
577
    AccountID accountid;
    bool returnValue;
578
    CallID call_id;
yanmorin's avatar
   
yanmorin committed
579

580
    stopTone (true);
581

582
583
    call_id = id;

584
    switchCall (id);
585

Emmanuel Milou's avatar
Emmanuel Milou committed
586
    /* Direct IP to IP call */
587

Emmanuel Milou's avatar
Emmanuel Milou committed
588
    if (getConfigFromCall (id) == Call::IPtoIP) {
589
        returnValue = SIPVoIPLink::instance (AccountNULL)-> onhold (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
590
    }
591

Emmanuel Milou's avatar
Emmanuel Milou committed
592
    /* Classic call, attached to an account */
593
    else {
594
595
        accountid = getAccountFromCall (id);

Emmanuel Milou's avatar
Emmanuel Milou committed
596
        if (accountid == AccountNULL) {
597
            _debug ("Manager On Hold Call: Account ID %s or callid %s doesn't exists\n", accountid.c_str(), id.c_str());
Emmanuel Milou's avatar
Emmanuel Milou committed
598
599
            return false;
        }
600
601

        returnValue = getAccountLink (accountid)->onhold (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
602
    }
603
    
604
605
606
    removeWaitingCall (id);

    switchCall ("");
607

608
    if (_dbus) _dbus->getCallManager()->callStateChanged (call_id, "HOLD");
609

Emmanuel Milou's avatar
Emmanuel Milou committed
610
    return returnValue;
yanmorin's avatar
   
yanmorin committed
611
612
613
}

//THREAD=Main
614
615
bool
ManagerImpl::offHoldCall (const CallID& id)
yanmorin's avatar
   
yanmorin committed
616
{
617

Emmanuel Milou's avatar
Emmanuel Milou committed
618
619
620
    AccountID accountid;
    bool returnValue, rec;
    std::string codecName;
621
    CallID call_id, current_call_id;
622

623
    stopTone (false);
624

625
    call_id = id;
626
    current_call_id = getCurrentCallId();
Emmanuel Milou's avatar
Emmanuel Milou committed
627
    //Place current call on hold if it isn't
628

629
    if (hasCurrentCall()) 
630
    {
631
632
633
	// if this is not a conferenceand this and is not a conference participant
	if (!isConference(current_call_id) && !participToConference(current_call_id))
	{
Alexandre Savard's avatar
Alexandre Savard committed
634
	    _debug ("ManagerImpl::offHoldCall put current call (ID=%s) on hold\n", current_call_id.c_str());
635
636
	    onHoldCall (current_call_id);
	}
Alexandre Savard's avatar
Alexandre Savard committed
637
	else if (isConference(current_call_id))
638
	{
Alexandre Savard's avatar
Alexandre Savard committed
639
640
	    _debug ("ManagerImpl::offHoldCall Put current conference (ID=%s) on hold\n", current_call_id.c_str());
	    detachParticipant();
641
	}
Emmanuel Milou's avatar
Emmanuel Milou committed
642
    }
643

644
    // switch current call id to id since sipvoip link need it to amke a call 
645
646
    switchCall(id);

Emmanuel Milou's avatar
Emmanuel Milou committed
647
648
649
    /* Direct IP to IP call */
    if (getConfigFromCall (id) == Call::IPtoIP) {
        rec = SIPVoIPLink::instance (AccountNULL)-> isRecording (id);
650
        returnValue = SIPVoIPLink::instance (AccountNULL)-> offhold (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
651
    }
alexandresavard's avatar
alexandresavard committed
652

Emmanuel Milou's avatar
Emmanuel Milou committed
653
    /* Classic call, attached to an account */
654
    else {
655
656
        accountid = getAccountFromCall (id);

Emmanuel Milou's avatar
Emmanuel Milou committed
657
        if (accountid == AccountNULL) {
658
            _debug ("Manager OffHold Call: Call doesn't exists\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
659
660
            return false;
        }
661
662
663
664
665

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

        rec = getAccountLink (accountid)->isRecording (id);
        returnValue = getAccountLink (accountid)->offhold (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
666
    }
alexandresavard's avatar
alexandresavard committed
667

668

669
    if (_dbus) {
Emmanuel Milou's avatar
Emmanuel Milou committed
670
        if (rec)
671
            _dbus->getCallManager()->callStateChanged (call_id, "UNHOLD_RECORD");
672
        else
673
            _dbus->getCallManager()->callStateChanged (call_id, "UNHOLD_CURRENT");
674

Emmanuel Milou's avatar
Emmanuel Milou committed
675
    }
676

677
    if ( participToConference(id) ) {
678
679
680
681
682
683
684
685
686

	 
	AccountID currentAccountId;
        Call* call = NULL;

	currentAccountId = getAccountFromCall (id);
	call = getAccountLink (currentAccountId)->getCall (id);
	
	switchCall(call->getConfId());
687
688
689
    }
    // else the 
  
690

691
    codecName = getCurrentCodecName (id);
692
    // _debug("ManagerImpl::hangupCall(): broadcast codec name %s \n",codecName.c_str());
693
694

    if (_dbus) _dbus->getCallManager()->currentSelectedCodec (id,codecName.c_str());
695

Emmanuel Milou's avatar
Emmanuel Milou committed
696
    return returnValue;
jpbl's avatar
jpbl committed
697
698
}

yanmorin's avatar
   
yanmorin committed
699
//THREAD=Main
700
701
bool
ManagerImpl::transferCall (const CallID& id, const std::string& to)
jpbl's avatar
jpbl committed
702
{
Emmanuel Milou's avatar
Emmanuel Milou committed
703
704
    AccountID accountid;
    bool returnValue;
705

706
    stopTone (true);
707

Emmanuel Milou's avatar
Emmanuel Milou committed
708
    /* Direct IP to IP call */
709

Emmanuel Milou's avatar
Emmanuel Milou committed
710
    if (getConfigFromCall (id) == Call::IPtoIP) {
711
        returnValue = SIPVoIPLink::instance (AccountNULL)-> transfer (id, to);
Emmanuel Milou's avatar
Emmanuel Milou committed
712
713
714
    }

    /* Classic call, attached to an account */
715
    else {
716
717
        accountid = getAccountFromCall (id);

Emmanuel Milou's avatar
Emmanuel Milou committed
718
        if (accountid == AccountNULL) {
719
            _debug ("! Manager Transfer Call: Call doesn't exists\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
720
721
            return false;
        }
722
723
724
725

        returnValue = getAccountLink (accountid)->transfer (id, to);

        removeCallAccount (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
726
    }
727

728
729
730
731
732
    removeWaitingCall (id);

    switchCall ("");

    if (_dbus) _dbus->getCallManager()->callStateChanged (id, "HUNGUP");
733

Emmanuel Milou's avatar
Emmanuel Milou committed
734
    return returnValue;
jpbl's avatar
jpbl committed
735
736
}

737
738
void ManagerImpl::transferFailed()
{
739
    if (_dbus) _dbus->getCallManager()->transferFailed();
740
741
742
743
}

void ManagerImpl::transferSucceded()
{
744
    if (_dbus) _dbus->getCallManager()->transferSucceded();
745
746
747
748

}


yanmorin's avatar
   
yanmorin committed
749
//THREAD=Main : Call:Incoming
750
bool
yanmorin's avatar
   
yanmorin committed
751
ManagerImpl::refuseCall (const CallID& id)
jpbl's avatar
jpbl committed
752
{
Emmanuel Milou's avatar
Emmanuel Milou committed
753
754
    AccountID accountid;
    bool returnValue;
755

756
757
758
    stopTone (true);

    /* Direct IP to IP call */
Emmanuel Milou's avatar
Emmanuel Milou committed
759
760

    if (getConfigFromCall (id) == Call::IPtoIP) {
761
        returnValue = SIPVoIPLink::instance (AccountNULL)-> refuse (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
762
763
764
    }

    /* Classic call, attached to an account */
765
    else {
766
767
        accountid = getAccountFromCall (id);

Emmanuel Milou's avatar
Emmanuel Milou committed
768
        if (accountid == AccountNULL) {
769
            _debug ("! Manager OffHold Call: Call doesn't exists\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
770
771
            return false;
        }
772
773
774
775

        returnValue = getAccountLink (accountid)->refuse (id);

        removeCallAccount (id);
776
777
    }

Emmanuel Milou's avatar
Emmanuel Milou committed
778
779
780
    // if the call was outgoing or established, we didn't refuse it
    // so the method did nothing
    if (returnValue) {
781
782
783
784
785
        removeWaitingCall (id);

        if (_dbus) _dbus->getCallManager()->callStateChanged (id, "HUNGUP");

        switchCall ("");
Emmanuel Milou's avatar
Emmanuel Milou committed
786
    }
787

Emmanuel Milou's avatar
Emmanuel Milou committed
788
    return returnValue;
jpbl's avatar
jpbl committed
789
790
}

791

792
Conference*
793
ManagerImpl::createConference(const CallID& id1, const CallID& id2)
794
795
{
    _debug("ManagerImpl::createConference()\n");
796
    
797
    Conference* conf = new Conference();
798

799
800
    // _conferencecall.insert(pair<CallID, Conference*>(id1, conf));
    // _conferencecall.insert(pair<CallID, Conference*>(id2, conf));
801
    _conferencemap.insert(pair<CallID, Conference*>(conf->getConfID(), conf));
802

803
804
    conf->add(id1);
    conf->add(id2);
805

806
    // broadcast a signal over dbus
807
    _dbus->getCallManager()->conferenceCreated(conf->getConfID());
808
809
    
    return conf;
810
811
812
}

void
813
ManagerImpl::removeConference(const ConfID& conference_id)
814
{
815
816
817

    _debug("ManagerImpl::removeConference(%s)\n", conference_id.c_str());

818
    Conference* conf = NULL;
819

820
    _debug("ManagerImpl::removeConference _conferencemap.size: %i\n", _conferencemap.size());
821
822
    ConferenceMap::iterator iter = _conferencemap.find(conference_id);

823
    if (iter != _conferencemap.end()) {
824
825
826
827
828
829
	_debug("Found conference id %s in conferencemap\n", conference_id.c_str());
        conf = iter->second;
    }

    if(conf == NULL)
	return;
830

831

832
    /*
833
834
835
    // unbind main participant from conference
    _audiodriver->getMainBuffer()->unBindAll(default_id);

836
    ParticipantSet participants = conf->getParticipantList();
837

838
839
840
    // bind main participant to remaining conference call
    ParticipantSet::iterator iter_p = participants.begin();
    if (iter_p != participants.end()) {
841

842
843
844
	// to avoid puting onhold the call
	// switchCall("");	
	_audiodriver->getMainBuffer()->bindCallID(*iter_p, default_id);
845
    }