managerimpl.cpp 90.8 KB
Newer Older
jpbl's avatar
jpbl committed
1
/*
2
 *  Copyright (C) 2004, 2005, 2006, 2008, 2009, 2010, 2011 Savoir-Faire Linux Inc.
3
 *  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: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
8
 *  Author: Guillaume Carmel-Archambault <guillaume.carmel-archambault@savoirfairelinux.com>
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
 *  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.
22
23
24
25
26
27
28
29
30
31
32
 *
 *  Additional permission under GNU GPL version 3 section 7:
 *
 *  If you modify this program, or any covered work, by linking or
 *  combining it with the OpenSSL project's OpenSSL library (or a
 *  modified version of that library), containing parts covered by the
 *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
 *  grants you additional permission to convey the resulting work.
 *  Corresponding Source for a non-source form of such a combination
 *  shall include the source code for the parts of OpenSSL used as well
 *  as that of the covered work.
jpbl's avatar
jpbl committed
33
34
 */

35
36
#include "config.h"

37
38
39
40
#include "managerimpl.h"

#include "account.h"
#include "dbus/callmanager.h"
41
#include "global.h"
42
#include "sip/sipaccount.h"
43
#include "im/InstantMessaging.h"
44
#include "iax/iaxaccount.h"
45
#include "numbercleaner.h"
46

47
48
49
#include "audio/alsa/alsalayer.h"
#include "audio/pulseaudio/pulselayer.h"
#include "audio/sound/tonelist.h"
50
51
#include "audio/sound/audiofile.h"
#include "audio/sound/dtmf.h"
52
53
#include "history/historymanager.h"
#include "sip/sipvoiplink.h"
54
#include "iax/iaxvoiplink.h"
55
#include "manager.h"
56

57
58
#include "dbus/configurationmanager.h"

59
60
#include "conference.h"

61
62
#include <cerrno>
#include <ctime>
jpbl's avatar
jpbl committed
63
64
65
#include <cstdlib>
#include <iostream>
#include <fstream>
66
#include <sstream>
jpbl's avatar
jpbl committed
67
#include <sys/types.h> // mkdir(2)
68
#include <sys/stat.h>  // mkdir(2)
69

70
ManagerImpl::ManagerImpl (void) :
Alexandre Savard's avatar
Alexandre Savard committed
71
    _hasTriedToRegister (false), _config(), _currentCallId2(),
72
    _currentCallMutex(), _audiodriver (0),
73
    _dtmfKey (0), _toneMutex(),
74
    _telephoneTone (0), _audiofile (0), _spkr_volume (0),
75
    _mic_volume (0), _waitingCall(),
Alexandre Savard's avatar
Alexandre Savard committed
76
    _waitingCallMutex(), _nbIncomingWaitingCall (0), _path (""),
77
    _callAccountMap(),
Alexandre Savard's avatar
Alexandre Savard committed
78
    _callAccountMapMutex(), _callConfigMap(), _accountMap(),
79
    _history (new HistoryManager), _imModule(new sfl::InstantMessaging)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
80
{
81
82
    // initialize random generator for call id
    srand (time (NULL));
jpbl's avatar
jpbl committed
83
84
85
}

// never call if we use only the singleton...
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
86
87
ManagerImpl::~ManagerImpl (void)
{
88
    delete _imModule;
89
90
    delete _history;
	delete _audiofile;
jpbl's avatar
jpbl committed
91
92
}

93
void ManagerImpl::init (std::string config_file)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
94
{
95
96
97
98
99
100
	if (config_file.empty())
		config_file = getConfigFile();
    _path = config_file;

    _debug ("Manager: configuration file path: %s", _path.c_str());

101
    Conf::YamlParser *parser = NULL;
102
103
104
105
106
107
108
109

	try {
		parser = new Conf::YamlParser (_path.c_str());
		parser->serializeEvents();
		parser->composeEvents();
		parser->constructNativeData();
	} catch (Conf::YamlParserException &e) {
		_error ("Manager: %s", e.what());
110
		fflush(stderr);
111
112
113
114
115
116
117
		delete parser;
		parser = NULL;
	}

	loadAccountMap(parser);
	delete parser;

118
119
    initVolume();
    initAudioDriver();
120

121
122
    audioLayerMutexLock();

123
    if (_audiodriver) {
124
125
        _telephoneTone = new TelephoneTone (preferences.getZoneToneChoice(), _audiodriver->getSampleRate());
        _dtmfKey = new DTMF (8000);
126
    }
127

128
129
    audioLayerMutexUnlock();

Julien Bonjean's avatar
Julien Bonjean committed
130
    _history->load_history (preferences.getHistoryLimit());
131
    registerAccounts();
jpbl's avatar
jpbl committed
132
133
}

Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
134
135
void ManagerImpl::terminate ()
{
136
    std::vector<std::string> callList(getCallList());
137
    _debug ("Manager: Hangup %zu remaining call", callList.size());
138

139
140
    std::vector<std::string>::iterator iter;
    for (iter = callList.begin(); iter != callList.end(); ++iter)
141
142
        hangupCall (*iter);

143
    unloadAccountMap();
144

145
    delete _dtmfKey;
jpbl's avatar
jpbl committed
146

147
148
    delete _telephoneTone;
    _telephoneTone = NULL;
149

150
151
    audioLayerMutexLock();

152
153
    delete _audiodriver;
    _audiodriver = NULL;
jpbl's avatar
jpbl committed
154

155
    audioLayerMutexUnlock();
jpbl's avatar
jpbl committed
156
157
}

158
bool ManagerImpl::isCurrentCall (const std::string& callId)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
159
{
Rafaël Carré's avatar
Rafaël Carré committed
160
    return _currentCallId2 == callId;
jpbl's avatar
jpbl committed
161
162
}

Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
163
164
bool ManagerImpl::hasCurrentCall ()
{
165
	return not _currentCallId2.empty();
jpbl's avatar
jpbl committed
166
167
}

168
const std::string&
169
ManagerImpl::getCurrentCallId () const
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
170
{
171
    return _currentCallId2;
jpbl's avatar
jpbl committed
172
173
}

174
void ManagerImpl::switchCall (const std::string& id)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
175
{
176
177
178
    ost::MutexLock m (_currentCallMutex);
    _debug ("----- Switch current call id to %s -----", id.c_str());
    _currentCallId2 = id;
jpbl's avatar
jpbl committed
179
180
181
182
183
}

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

186
bool ManagerImpl::outgoingCall (const std::string& account_id,
187
                                const std::string& call_id, const std::string& to, const std::string& conf_id)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
188
{
189
190
191
192
    if (call_id.empty()) {
        _debug ("Manager: New outgoing call abbort, missing callid");
        return false;
    }
Emmanuel Lepage's avatar
Emmanuel Lepage committed
193
194
195
196
197
    
    if (account_id.empty()) {
        _debug ("Manager: New outgoing call abbort, missing account");
        return false;
    }
198

199
    // Call ID must be unique
200
    if (not getAccountFromCall (call_id).empty()) {
201
202
203
204
        _error ("Manager: Error: Call id already exists in outgoing call");
        return false;
    }

205
    _debug ("Manager: New outgoing call %s to %s", call_id.c_str(), to.c_str());
206

207
208
    stopTone();

209
    std::string current_call_id(getCurrentCallId());
210

211
    std::string prefix;
212
    if (hookPreference.getNumberEnabled())
213
        prefix = hookPreference.getNumberAddPrefix();
214

215
    std::string to_cleaned(NumberCleaner::clean(to, prefix));
Emmanuel Milou's avatar
Emmanuel Milou committed
216

217
    Call::CallConfiguration callConfig;
218
    /* Check what kind of call we are dealing with */
219
    checkCallConfiguration (call_id, to_cleaned, &callConfig);
220

221
222
223
    // in any cases we have to detach from current communication
    if (hasCurrentCall()) {
        _debug ("Manager: Has current call (%s) put it onhold", current_call_id.c_str());
224

225
        // if this is not a conferenceand this and is not a conference participant
226
        if (!isConference (current_call_id) && !participToConference (current_call_id))
227
       	    onHoldCall (current_call_id);
228
        else if (isConference (current_call_id) && !participToConference (call_id))
229
            detachParticipant (Call::DEFAULT_ID, current_call_id);
230
    }
231

232
233
234
    if (callConfig == Call::IPtoIP) {
        _debug ("Manager: Start IP2IP call");
        /* We need to retrieve the sip voiplink instance */
235
        if (SIPVoIPLink::instance()->SIPNewIpToIpCall(call_id, to_cleaned)) {
236
237
            switchCall (call_id);
            return true;
238
        } else
239
            callFailure (call_id);
240

241
242
        return false;
    }
243

244
    _debug ("Manager: Selecting account %s", account_id.c_str());
245

246
    // Is this account exist
247
248
249
250
    if (!accountExists (account_id)) {
        _error ("Manager: Error: Account doesn't exist in new outgoing call");
        return false;
    }
251

252
    if(!associateCallToAccount (call_id, account_id))
253
    	_warn("Manager: Warning: Could not associate call id %s to account id %s", call_id.c_str(), account_id.c_str());
254

255
    try {
256
        Call *call = getAccountLink(account_id)->newOutgoingCall (call_id, to_cleaned);
Emmanuel Lepage's avatar
Emmanuel Lepage committed
257
	
258
        switchCall (call_id);
259
        call->setConfId(conf_id);
260
    } catch (const VoipLinkException &e) {
261
        callFailure (call_id);
262
        _error ("Manager: %s", e.what());
263
        return false;
264
265
    }

Alexandre Savard's avatar
Alexandre Savard committed
266
267
    getMainBuffer()->stateInfo();

268
    return true;
jpbl's avatar
jpbl committed
269
270
}

yanmorin's avatar
   
yanmorin committed
271
//THREAD=Main : for outgoing Call
272
bool ManagerImpl::answerCall (const std::string& call_id)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
273
{
274
    _debug ("Manager: Answer call %s", call_id.c_str());
275

276
    // If sflphone is ringing
277
    stopTone();
278

279
    // store the current call id
280
    std::string current_call_id(getCurrentCallId());
281

282
    // Retreive call coresponding to this id
283
    std::string account_id = getAccountFromCall (call_id);
284
    Call *call = getAccountLink (account_id)->getCall (call_id);
285
    if (call == NULL) {
286
        _error("Manager: Error: Call is null");
287
    }
288

289
290
    // in any cases we have to detach from current communication
    if (hasCurrentCall()) {
291

292
        _debug ("Manager: Currently conversing with %s", current_call_id.c_str());
293

294
295
296
        if (!isConference(current_call_id) && !participToConference (current_call_id)) {
            // if it is not a conference and is not a conference participant
            _debug ("Manager: Answer call: Put the current call (%s) on hold", current_call_id.c_str());
297
            onHoldCall (current_call_id);
298
299
300
        } else if (isConference (current_call_id) && !participToConference (call_id)) {
            // if we are talking to a conference and we are answering an incoming call
            _debug ("Manager: Detach main participant from conference");
301
            detachParticipant (Call::DEFAULT_ID, current_call_id);
302
303
        }
    }
304

305
    try {
306
        getAccountLink (account_id)->answer (call);
307
    }
308
    catch (const VoipLinkException &e) {
309
    	_error("Manager: Error: %s", e.what());
310
    }
Alexandre Savard's avatar
Alexandre Savard committed
311

312
    // if it was waiting, it's waiting no more
313
    removeWaitingCall (call_id);
314

315
    // if we dragged this call into a conference already
316
    if (participToConference (call_id))
317
        switchCall (call->getConfId());
318
    else
319
        switchCall (call_id);
320

321
322
323
    // Connect streams
    addStream (call_id);

Alexandre Savard's avatar
Alexandre Savard committed
324
325
    getMainBuffer()->stateInfo();

326
    // Start recording if set in preference
327
    if (audioPreference.getIsAlwaysRecording())
328
329
330
    	setRecordingCall(call_id);

    // update call state on client side
331
    if (audioPreference.getIsAlwaysRecording())
332
        _dbus.getCallManager()->callStateChanged (call_id, "RECORD");
333
    else
334
    	_dbus.getCallManager()->callStateChanged(call_id, "CURRENT");
335

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

yanmorin's avatar
   
yanmorin committed
339
//THREAD=Main
340
void ManagerImpl::hangupCall (const std::string& callId)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
341
{
342
343
    _info ("Manager: Hangup call %s", callId.c_str());

344
    // First stop audio layer if there is no call anymore
345
    if (getCallList().empty()) {
346
347
348

    	audioLayerMutexLock();

349
        if(_audiodriver == NULL) {
350
        	audioLayerMutexUnlock();
351
        	_error("Manager: Error: Audio layer was not instantiated");
352
        	return;
353
354
        }

355
        _debug ("Manager: stop audio stream, there is no call remaining");
356
        _audiodriver->stopStream();
357
        audioLayerMutexUnlock();
358
359
    }

360
    // store the current call id
361
    std::string currentCallId(getCurrentCallId());
yanmorin's avatar
   
yanmorin committed
362

363
    stopTone();
364

365
    /* Broadcast a signal over DBus */
366
    _debug ("Manager: Send DBUS call state change (HUNGUP) for id %s", callId.c_str());
367
    _dbus.getCallManager()->callStateChanged (callId, "HUNGUP");
368

369
    if (not isValidCall(callId) and not getConfigFromCall(callId) == Call::IPtoIP) {
370
    	_error("Manager: Error: Could not hang up call, call not valid");
371
        return;
372
373
    }

374
375
376
    // Disconnect streams
    removeStream(callId);

377
    if (participToConference (callId)) {
378
    	Conference *conf = getConferenceFromCallID (callId);
379
380
        if (conf != NULL) {
            // remove this participant
381
382
            removeParticipant (callId);
            processRemainingParticipant (currentCallId, conf);
383
384
385
        }
    } else {
        // we are not participating to a conference, current call switched to ""
386
        if (!isConference (currentCallId))
387
388
            switchCall ("");
    }
389

390
391
    if (getConfigFromCall (callId) == Call::IPtoIP) {
        /* Direct IP to IP call */
392
        try {
393
            SIPVoIPLink::instance()->hangup (callId);
394
395
396
397
398
        }
        catch (const VoipLinkException &e)
        {
            _error("%s", e.what());
        }
399
400
    }
    else {
401
    	std::string accountId (getAccountFromCall (callId));
402
        getAccountLink (accountId)->hangup (callId);
403
        removeCallAccount (callId);
404
    }
405

Alexandre Savard's avatar
Alexandre Savard committed
406
    getMainBuffer()->stateInfo();
jpbl's avatar
jpbl committed
407
408
}

409
bool ManagerImpl::hangupConference (const std::string& id)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
410
{
411
    _debug ("Manager: Hangup conference %s", id.c_str());
Alexandre Savard's avatar
Alexandre Savard committed
412

413
    ConferenceMap::iterator iter_conf = _conferencemap.find (id);
Alexandre Savard's avatar
Alexandre Savard committed
414

415
    std::string currentAccountId;
Alexandre Savard's avatar
Alexandre Savard committed
416

417
    if (iter_conf != _conferencemap.end()) {
418
        Conference *conf = iter_conf->second;
Alexandre Savard's avatar
Alexandre Savard committed
419

420
421
422
423
        const ParticipantSet &participants = conf->getParticipantList();
        ParticipantSet::const_iterator iter;
        for (iter = participants.begin(); iter != participants.end(); ++iter)
            hangupCall (*iter);
424
    }
Alexandre Savard's avatar
Alexandre Savard committed
425

426
    switchCall ("");
427

Alexandre Savard's avatar
Alexandre Savard committed
428
    getMainBuffer()->stateInfo();
429

430
    return true;
Alexandre Savard's avatar
Alexandre Savard committed
431
432
}

jpbl's avatar
jpbl committed
433

yanmorin's avatar
   
yanmorin committed
434
//THREAD=Main
435
void ManagerImpl::onHoldCall (const std::string& callId)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
436
{
437
    _debug ("Manager: Put call %s on hold", callId.c_str());
438

439
    stopTone();
440

441
    std::string current_call_id(getCurrentCallId());
442

443
444
445
    try {
    	if (getConfigFromCall (callId) == Call::IPtoIP) {
    		/* Direct IP to IP call */
446
            SIPVoIPLink::instance ()-> onhold (callId);
447
448
449
    	}
    	else {
    		/* Classic call, attached to an account */
450
            std::string account_id(getAccountFromCall (callId));
451

452
453
454
455
456
            if (account_id.empty()) {
                _debug ("Manager: Account ID %s or callid %s doesn't exists in call onHold", account_id.c_str(), callId.c_str());
                return;
            }
    		getAccountLink(account_id)->onhold(callId);
457
458
    	}
    }
459
    catch (const VoipLinkException &e) {
460
    	_error("Manager: Error: %s", e.what());
461
    }
462

463
    // Unbind calls in main buffer
464
    removeStream (callId);
465

466
    // Remove call from teh queue if it was still there
467
    removeWaitingCall (callId);
468

469
    // keeps current call id if the action is not holding this call or a new outgoing call
470
    // this could happen in case of a conference
471
    if (current_call_id == callId)
472
        switchCall ("");
473

474
    _dbus.getCallManager()->callStateChanged (callId, "HOLD");
475

Alexandre Savard's avatar
Alexandre Savard committed
476
    getMainBuffer()->stateInfo();
yanmorin's avatar
   
yanmorin committed
477
478
479
}

//THREAD=Main
480
void ManagerImpl::offHoldCall (const std::string& callId)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
481
{
482
    std::string accountId;
483
    std::string codecName;
484

485
    _debug ("Manager: Put call %s off hold", callId.c_str());
486

487
    stopTone();
488

489
    std::string currentCallId(getCurrentCallId());
490

491
    //Place current call on hold if it isn't
492

493
    if (hasCurrentCall()) {
494

495
        // if this is not a conference and this and is not a conference participant
496
497
498
        if (!isConference (currentCallId) && !participToConference (currentCallId)) {
        	_debug ("Manager: Has current call (%s), put on hold", currentCallId.c_str());
            onHoldCall (currentCallId);
499
        } else if (isConference (currentCallId) && !participToConference (callId))
500
            detachParticipant (Call::DEFAULT_ID, currentCallId);
501
    }
alexandresavard's avatar
alexandresavard committed
502

503
504
    bool isRec = false;

505
    /* Direct IP to IP call */
506
    if (getConfigFromCall (callId) == Call::IPtoIP)
507
        SIPVoIPLink::instance ()-> offhold (callId);
508
    else {
509
        /* Classic call, attached to an account */
510
        accountId = getAccountFromCall (callId);
511

512
        _debug ("Manager: Setting offhold, Account %s, callid %s", accountId.c_str(), callId.c_str());
513

514
515
516
517
        Call * call = getAccountLink (accountId)->getCall (callId);
        if (call)
        {
            isRec = call->isRecording();
518
            getAccountLink(accountId)->offhold(callId);
519
        }
520
    }
521

522
    _dbus.getCallManager()->callStateChanged (callId, isRec ? "UNHOLD_RECORD" : "UNHOLD_CURRENT");
523
524

    if (participToConference (callId)) {
525
        std::string currentAccountId(getAccountFromCall(callId));
526
        Call *call = getAccountLink (currentAccountId)->getCall (callId);
527

528
529
        if (call)
            switchCall (call->getConfId());
530

531
    } else
532
        switchCall (callId);
533

534
535
    addStream(callId);

Alexandre Savard's avatar
Alexandre Savard committed
536
    getMainBuffer()->stateInfo();
jpbl's avatar
jpbl committed
537
538
}

yanmorin's avatar
   
yanmorin committed
539
//THREAD=Main
540
bool ManagerImpl::transferCall (const std::string& callId, const std::string& to)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
541
{
542
    bool returnValue = false;;
543

544
545
    _info ("Manager: Transfer call %s", callId.c_str());

546
    std::string currentCallId = getCurrentCallId();
547

548
549
550
551
    if (participToConference(callId)) {
        Conference *conf = getConferenceFromCallID(callId);
        if (conf == NULL)
            _error("Manager: Error: Could not find conference from call id");
552

553
554
        removeParticipant (callId);
        processRemainingParticipant (callId, conf);
555
    }
556
    else if (!isConference(currentCallId))
557
            switchCall("");
558

559
    // Direct IP to IP call
560
    if (getConfigFromCall (callId) == Call::IPtoIP)
561
        returnValue = SIPVoIPLink::instance ()-> transfer (callId, to);
562
    else {
563
        std::string accountid (getAccountFromCall (callId));
564

565
        if (accountid == "") {
566
567
568
            _warn ("Manager: Call doesn't exists");
            return false;
        }
569

570
        returnValue = getAccountLink (accountid)->transfer (callId, to);
571
    }
572

573
    // remove waiting call in case we make transfer without even answer
574
    removeWaitingCall (callId);
575

Alexandre Savard's avatar
Alexandre Savard committed
576
577
    getMainBuffer()->stateInfo();

578
    return returnValue;
jpbl's avatar
jpbl committed
579
580
}

Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
581
582
void ManagerImpl::transferFailed ()
{
583
	_dbus.getCallManager()->transferFailed();
584
585
}

Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
586
587
void ManagerImpl::transferSucceded ()
{
588
	_dbus.getCallManager()->transferSucceded();
589
590
}

591
bool ManagerImpl::attendedTransfer(const std::string& transferID, const std::string& targetID)
592
{
Rafaël Carré's avatar
Rafaël Carré committed
593
    bool returnValue;;
594

595
    // Direct IP to IP call
596
    if (getConfigFromCall (transferID) == Call::IPtoIP)
597
        returnValue = SIPVoIPLink::instance ()-> attendedTransfer(transferID, targetID);
598
    else {	// Classic call, attached to an account
599
        std::string accountid = getAccountFromCall (transferID);
Rafaël Carré's avatar
Rafaël Carré committed
600
        if (accountid.empty())
601
            return false;
602

603
604
        returnValue = getAccountLink (accountid)->attendedTransfer (transferID, targetID);
    }
605

606
    getMainBuffer()->stateInfo();
Alexandre Savard's avatar
Alexandre Savard committed
607

608
    return returnValue;
609
610
}

yanmorin's avatar
   
yanmorin committed
611
//THREAD=Main : Call:Incoming
612
bool ManagerImpl::refuseCall (const std::string& id)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
613
{
614
    bool returnValue;
615

616
    stopTone();
617

Rafaël Carré's avatar
Rafaël Carré committed
618
    if (getCallList().size() <= 1) {
619
        audioLayerMutexLock();
620
        _audiodriver->stopStream();
621
        audioLayerMutexUnlock();
622
    }
Emmanuel Milou's avatar
Emmanuel Milou committed
623

624
    /* Direct IP to IP call */
625

626
    if (getConfigFromCall (id) == Call::IPtoIP)
627
        returnValue = SIPVoIPLink::instance ()-> refuse (id);
628
    else {
629
        /* Classic call, attached to an account */
Rafaël Carré's avatar
Rafaël Carré committed
630
631
        std::string accountid = getAccountFromCall (id);
        if (accountid.empty())
632
            return false;
633

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

636
637
        removeCallAccount (id);
    }
638

639
640
641
642
    // if the call was outgoing or established, we didn't refuse it
    // so the method did nothing
    if (returnValue) {
        removeWaitingCall (id);
643
        _dbus.getCallManager()->callStateChanged (id, "HUNGUP");
644
    }
645

646
    // Disconnect streams
647
    removeStream(id);
648

Alexandre Savard's avatar
Alexandre Savard committed
649
650
    getMainBuffer()->stateInfo();

651
    return returnValue;
jpbl's avatar
jpbl committed
652
653
}

654
Conference*
655
ManagerImpl::createConference (const std::string& id1, const std::string& id2)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
656
{
657
    typedef std::pair<std::string, Conference*> ConferenceEntry;
658
    _debug ("Manager: Create conference with call %s and %s", id1.c_str(), id2.c_str());
659

660
    Conference* conf = new Conference;
661

662
663
    conf->add (id1);
    conf->add (id2);
664

665
    // Add conference to map
666
    _conferencemap.insert (ConferenceEntry (conf->getConfID(), conf));
Alexandre Savard's avatar
Alexandre Savard committed
667

668
    // broadcast a signal over dbus
669
    _dbus.getCallManager()->conferenceCreated (conf->getConfID());
670

671
    return conf;
672
673
}

674