managerimpl.cpp 87.7 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
71
72
73
74
75
76
ManagerImpl::ManagerImpl() :
    hasTriedToRegister_(false), config_(), currentCallId_(),
    currentCallMutex_(), audiodriver_(0), dtmfKey_(0), toneMutex_(),
    telephoneTone_(0), audiofile_(0), speakerVolume_(0), micVolume_(0),
    waitingCall_(), waitingCallMutex_(), nbIncomingWaitingCall_(0), path_(""),
    callAccountMap_(), callAccountMapMutex_(), callConfigMap_(), accountMap_(),
    history_(new HistoryManager), imModule_(new sfl::InstantMessaging)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
77
{
78
    // initialize random generator for call id
79
    srand(time(NULL));
jpbl's avatar
jpbl committed
80
81
82
}

// never call if we use only the singleton...
83
ManagerImpl::~ManagerImpl()
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
84
{
85
86
87
    delete imModule_;
    delete history_;
    delete audiofile_;
jpbl's avatar
jpbl committed
88
89
}

90
void ManagerImpl::init(std::string config_file)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
91
{
92
93
94
    if (config_file.empty())
        config_file = getConfigFile();

95
    path_ = config_file;
96

97
    _debug("Manager: configuration file path: %s", path_.c_str());
98

99
    Conf::YamlParser *parser = NULL;
100

101
    try {
102
        parser = new Conf::YamlParser(path_.c_str());
103
104
105
106
107
108
109
110
111
112
113
114
        parser->serializeEvents();
        parser->composeEvents();
        parser->constructNativeData();
    } catch (Conf::YamlParserException &e) {
        _error("Manager: %s", e.what());
        fflush(stderr);
        delete parser;
        parser = NULL;
    }

    loadAccountMap(parser);
    delete parser;
115

116
117
    initVolume();
    initAudioDriver();
118

119
120
    audioLayerMutexLock();

121
122
123
    if (audiodriver_) {
        telephoneTone_ = new TelephoneTone(preferences.getZoneToneChoice(), audiodriver_->getSampleRate());
        dtmfKey_ = new DTMF(8000);
124
    }
125

126
127
    audioLayerMutexUnlock();

128
    history_->load_history(preferences.getHistoryLimit());
129
    registerAccounts();
jpbl's avatar
jpbl committed
130
131
}

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

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

140
    unloadAccountMap();
141

142
    delete SIPVoIPLink::instance();
143
144
145
    delete dtmfKey_;
    delete telephoneTone_;
    telephoneTone_ = NULL;
146

147
148
    audioLayerMutexLock();

149
150
    delete audiodriver_;
    audiodriver_ = NULL;
jpbl's avatar
jpbl committed
151

152
    audioLayerMutexUnlock();
jpbl's avatar
jpbl committed
153
154
}

155
bool ManagerImpl::isCurrentCall(const std::string& callId) const
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
156
{
157
    return currentCallId_ == callId;
jpbl's avatar
jpbl committed
158
159
}

160
bool ManagerImpl::hasCurrentCall() const
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
161
{
162
    return not currentCallId_.empty();
jpbl's avatar
jpbl committed
163
164
}

165
std::string
166
ManagerImpl::getCurrentCallId() const
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
167
{
168
    return currentCallId_;
jpbl's avatar
jpbl committed
169
170
}

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

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

183
bool ManagerImpl::outgoingCall(const std::string& account_id,
184
185
186
                               const std::string& call_id,
                               const std::string& to,
                               const std::string& conf_id)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
187
{
188
    if (call_id.empty()) {
189
        _debug("Manager: New outgoing call abort, missing callid");
190
191
192
        return false;
    }

193
    // Call ID must be unique
194
195
    if (not getAccountFromCall(call_id).empty()) {
        _error("Manager: Error: Call id already exists in outgoing call");
196
197
198
        return false;
    }

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

201
202
    stopTone();

203
    std::string current_call_id(getCurrentCallId());
204

205
    std::string prefix;
206
    if (hookPreference.getNumberEnabled())
207
        prefix = hookPreference.getNumberAddPrefix();
208

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

211
    Call::CallConfiguration callConfig = (to_cleaned.find(SIP_SCHEME) == 0 or to_cleaned.find(SIPS_SCHEME) == 0) ? Call::IPtoIP : Call::Classic;
Rafaël Carré's avatar
Rafaël Carré committed
212

213
    associateConfigToCall(call_id, callConfig);
214

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

219
        // if this is not a conferenceand this and is not a conference participant
220
221
222
223
        if (!isConference(current_call_id) && !participToConference(current_call_id))
            onHoldCall(current_call_id);
        else if (isConference(current_call_id) && !participToConference(call_id))
            detachParticipant(Call::DEFAULT_ID, current_call_id);
224
    }
225

226
    if (callConfig == Call::IPtoIP) {
227
228
        _debug("Manager: Start IP2IP call");

229
        /* We need to retrieve the sip voiplink instance */
230
        if (SIPVoIPLink::instance()->SIPNewIpToIpCall(call_id, to_cleaned)) {
231
            switchCall(call_id);
232
            return true;
233
        } else
234
            callFailure(call_id);
235

236
237
        return false;
    }
238

239
    _debug("Manager: Selecting account %s", account_id.c_str());
240

241
    // Is this account exist
242
243
    if (!accountExists(account_id)) {
        _error("Manager: Error: Account doesn't exist in new outgoing call");
244
245
        return false;
    }
246

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

250
    try {
251
252
253
        Call *call = getAccountLink(account_id)->newOutgoingCall(call_id, to_cleaned);

        switchCall(call_id);
254
        call->setConfId(conf_id);
255
    } catch (const VoipLinkException &e) {
256
257
        callFailure(call_id);
        _error("Manager: %s", e.what());
258
        return false;
259
260
    }

Alexandre Savard's avatar
Alexandre Savard committed
261
262
    getMainBuffer()->stateInfo();

263
    return true;
jpbl's avatar
jpbl committed
264
265
}

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

271
    // If sflphone is ringing
272
    stopTone();
273

274
    // store the current call id
275
    std::string current_call_id(getCurrentCallId());
276

277
    // Retreive call coresponding to this id
278
279
280
    std::string account_id = getAccountFromCall(call_id);
    Call *call = getAccountLink(account_id)->getCall(call_id);

281
    if (call == NULL) {
282
        _error("Manager: Error: Call is null");
283
    }
284

285
286
    // in any cases we have to detach from current communication
    if (hasCurrentCall()) {
287

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

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

301
    try {
302
303
304
        getAccountLink(account_id)->answer(call);
    } catch (const VoipLinkException &e) {
        _error("Manager: Error: %s", e.what());
305
    }
Alexandre Savard's avatar
Alexandre Savard committed
306

307
    // if it was waiting, it's waiting no more
308
    removeWaitingCall(call_id);
309

310
    // if we dragged this call into a conference already
311
312
    if (participToConference(call_id))
        switchCall(call->getConfId());
313
    else
314
        switchCall(call_id);
315

316
    // Connect streams
317
    addStream(call_id);
318

Alexandre Savard's avatar
Alexandre Savard committed
319
320
    getMainBuffer()->stateInfo();

321
    // Start recording if set in preference
322
    if (audioPreference.getIsAlwaysRecording())
323
        setRecordingCall(call_id);
324
325

    // update call state on client side
326
    if (audioPreference.getIsAlwaysRecording())
327
        dbus_.getCallManager()->callStateChanged(call_id, "RECORD");
328
    else
329
        dbus_.getCallManager()->callStateChanged(call_id, "CURRENT");
330

331
    return true;
jpbl's avatar
jpbl committed
332
333
}

yanmorin's avatar
   
yanmorin committed
334
//THREAD=Main
335
void ManagerImpl::hangupCall(const std::string& callId)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
336
{
337
    _info("Manager: Hangup call %s", callId.c_str());
338

339
    // store the current call id
340
    std::string currentCallId(getCurrentCallId());
yanmorin's avatar
   
yanmorin committed
341

342
    stopTone();
343

344
    /* Broadcast a signal over DBus */
345
    _debug("Manager: Send DBUS call state change (HUNGUP) for id %s", callId.c_str());
346
    dbus_.getCallManager()->callStateChanged(callId, "HUNGUP");
347

348
    if (not isValidCall(callId) and not getConfigFromCall(callId) == Call::IPtoIP) {
349
        _error("Manager: Error: Could not hang up call, call not valid");
350
        return;
351
352
    }

353
354
355
    // Disconnect streams
    removeStream(callId);

356
357
358
    if (participToConference(callId)) {
        Conference *conf = getConferenceFromCallID(callId);

359
360
        if (conf != NULL) {
            // remove this participant
361
            removeParticipant(callId);
362
            processRemainingParticipants(currentCallId, conf);
363
364
365
        }
    } else {
        // we are not participating to a conference, current call switched to ""
366
367
        if (!isConference(currentCallId))
            switchCall("");
368
    }
369

370
    if (getConfigFromCall(callId) == Call::IPtoIP) {
371
        /* Direct IP to IP call */
372
        try {
373
374
            SIPVoIPLink::instance()->hangup(callId);
        } catch (const VoipLinkException &e) {
375
376
            _error("%s", e.what());
        }
377
378
379
380
    } else {
        std::string accountId(getAccountFromCall(callId));
        getAccountLink(accountId)->hangup(callId);
        removeCallAccount(callId);
381
    }
382

Alexandre Savard's avatar
Alexandre Savard committed
383
    getMainBuffer()->stateInfo();
jpbl's avatar
jpbl committed
384
385
}

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

390
    ConferenceMap::iterator iter_conf = conferenceMap_.find(id);
Alexandre Savard's avatar
Alexandre Savard committed
391

392
    if (iter_conf != conferenceMap_.end()) {
393
        Conference *conf = iter_conf->second;
394

395
396
        if (conf) {
            ParticipantSet participants(conf->getParticipantList());
397

398
399
400
            for (ParticipantSet::const_iterator iter = participants.begin();
                    iter != participants.end(); ++iter)
                hangupCall(*iter);
401
        } else {
402
403
404
            _error("Manager: No such conference %s", id.c_str());
            return false;
        }
405
    }
Alexandre Savard's avatar
Alexandre Savard committed
406

407
    switchCall("");
408

Alexandre Savard's avatar
Alexandre Savard committed
409
    getMainBuffer()->stateInfo();
410

411
    return true;
Alexandre Savard's avatar
Alexandre Savard committed
412
413
}

jpbl's avatar
jpbl committed
414

yanmorin's avatar
   
yanmorin committed
415
//THREAD=Main
416
void ManagerImpl::onHoldCall(const std::string& callId)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
417
{
418
    _debug("Manager: Put call %s on hold", callId.c_str());
419

420
    stopTone();
421

422
    std::string current_call_id(getCurrentCallId());
423

424
    try {
425
426
427
428
429
430
        if (getConfigFromCall(callId) == Call::IPtoIP) {
            /* Direct IP to IP call */
            SIPVoIPLink::instance()-> onhold(callId);
        } else {
            /* Classic call, attached to an account */
            std::string account_id(getAccountFromCall(callId));
431

432
            if (account_id.empty()) {
433
                _debug("Manager: Account ID %s or callid %s doesn't exists in call onHold", account_id.c_str(), callId.c_str());
434
435
                return;
            }
436
437
438
439
440

            getAccountLink(account_id)->onhold(callId);
        }
    } catch (const VoipLinkException &e) {
        _error("Manager: Error: %s", e.what());
441
    }
442

443
    // Unbind calls in main buffer
444
    removeStream(callId);
445

446
    // Remove call from teh queue if it was still there
447
    removeWaitingCall(callId);
448

449
    // keeps current call id if the action is not holding this call or a new outgoing call
450
    // this could happen in case of a conference
451
    if (current_call_id == callId)
452
        switchCall("");
453

454
    dbus_.getCallManager()->callStateChanged(callId, "HOLD");
455

Alexandre Savard's avatar
Alexandre Savard committed
456
    getMainBuffer()->stateInfo();
yanmorin's avatar
   
yanmorin committed
457
458
459
}

//THREAD=Main
460
void ManagerImpl::offHoldCall(const std::string& callId)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
461
{
462
    std::string accountId;
463
    std::string codecName;
464

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

467
    stopTone();
468

469
    std::string currentCallId(getCurrentCallId());
470

471
    //Place current call on hold if it isn't
472

473
    if (hasCurrentCall()) {
474

475
        // if this is not a conference and this and is not a conference participant
476
477
478
479
480
        if (!isConference(currentCallId) && !participToConference(currentCallId)) {
            _debug("Manager: Has current call (%s), put on hold", currentCallId.c_str());
            onHoldCall(currentCallId);
        } else if (isConference(currentCallId) && !participToConference(callId))
            detachParticipant(Call::DEFAULT_ID, currentCallId);
481
    }
alexandresavard's avatar
alexandresavard committed
482

483
484
    bool isRec = false;

485
    /* Direct IP to IP call */
486
487
    if (getConfigFromCall(callId) == Call::IPtoIP)
        SIPVoIPLink::instance()-> offhold(callId);
488
    else {
489
        /* Classic call, attached to an account */
490
        accountId = getAccountFromCall(callId);
491

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

494
495
496
        Call * call = getAccountLink(accountId)->getCall(callId);

        if (call) {
497
            isRec = call->isRecording();
498
            getAccountLink(accountId)->offhold(callId);
499
        }
500
    }
501

502
    dbus_.getCallManager()->callStateChanged(callId, isRec ? "UNHOLD_RECORD" : "UNHOLD_CURRENT");
503

504
    if (participToConference(callId)) {
505
        std::string currentAccountId(getAccountFromCall(callId));
506
        Call *call = getAccountLink(currentAccountId)->getCall(callId);
507

508
        if (call)
509
            switchCall(call->getConfId());
510

511
    } else
512
        switchCall(callId);
513

514
515
    addStream(callId);

Alexandre Savard's avatar
Alexandre Savard committed
516
    getMainBuffer()->stateInfo();
jpbl's avatar
jpbl committed
517
518
}

yanmorin's avatar
   
yanmorin committed
519
//THREAD=Main
520
bool ManagerImpl::transferCall(const std::string& callId, const std::string& to)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
521
{
522
    if (participToConference(callId)) {
523
        removeParticipant(callId);
524
525
526
        Conference *conf = getConferenceFromCallID(callId);
        processRemainingParticipants(callId, conf);
    } else if (not isConference(getCurrentCallId()))
527
        switchCall("");
528

529
    // Direct IP to IP call
530
    if (getConfigFromCall(callId) == Call::IPtoIP)
531
        SIPVoIPLink::instance()->transfer(callId, to);
532
    else {
533
534
        std::string accountid(getAccountFromCall(callId));

535
        if (accountid.empty()) 
536
            return false;
537

538
        getAccountLink(accountid)->transfer(callId, to);
539
    }
540

541
    // remove waiting call in case we make transfer without even answer
542
    removeWaitingCall(callId);
543

Alexandre Savard's avatar
Alexandre Savard committed
544
545
    getMainBuffer()->stateInfo();

546
    return true;
jpbl's avatar
jpbl committed
547
548
}

549
void ManagerImpl::transferFailed()
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
550
{
551
    dbus_.getCallManager()->transferFailed();
552
553
}

554
void ManagerImpl::transferSucceded()
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
555
{
556
    dbus_.getCallManager()->transferSucceded();
557
558
}

559
bool ManagerImpl::attendedTransfer(const std::string& transferID, const std::string& targetID)
560
{
Rafaël Carré's avatar
Rafaël Carré committed
561
562
    if (getConfigFromCall(transferID) == Call::IPtoIP)
        return SIPVoIPLink::instance()->attendedTransfer(transferID, targetID);
563

Rafaël Carré's avatar
Rafaël Carré committed
564
    // Classic call, attached to an account
565
    std::string accountid(getAccountFromCall(transferID));
Alexandre Savard's avatar
Alexandre Savard committed
566

567
568
569
570
    if (accountid.empty())
        return false;

    return getAccountLink(accountid)->attendedTransfer(transferID, targetID);
571
572
}

yanmorin's avatar
   
yanmorin committed
573
//THREAD=Main : Call:Incoming
574
void ManagerImpl::refuseCall(const std::string& id)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
575
{
576
    stopTone();
577

Rafaël Carré's avatar
Rafaël Carré committed
578
    if (getCallList().size() <= 1) {
579
        audioLayerMutexLock();
580
        audiodriver_->stopStream();
581
        audioLayerMutexUnlock();
582
    }
Emmanuel Milou's avatar
Emmanuel Milou committed
583

584
    /* Direct IP to IP call */
585

586
587
    if (getConfigFromCall(id) == Call::IPtoIP)
        SIPVoIPLink::instance()->refuse(id);
588
    else {
589
        /* Classic call, attached to an account */
590
591
        std::string accountid = getAccountFromCall(id);

Rafaël Carré's avatar
Rafaël Carré committed
592
        if (accountid.empty())
Rafaël Carré's avatar
Rafaël Carré committed
593
            return;
594

Rafaël Carré's avatar
Rafaël Carré committed
595
        getAccountLink(accountid)->refuse(id);
596

597
        removeCallAccount(id);
598
    }
599

600
    removeWaitingCall(id);
601
    dbus_.getCallManager()->callStateChanged(id, "HUNGUP");
602

603
    // Disconnect streams
604
    removeStream(id);
605

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

609
Conference*
610
ManagerImpl::createConference(const std::string& id1, const std::string& id2)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
611
{
612
    typedef std::pair<std::string, Conference*> ConferenceEntry;
613
    _debug("Manager: Create conference with call %s and %s", id1.c_str(), id2.c_str());
614

615
    Conference* conf = new Conference;
616

617
618
    conf->add(id1);
    conf->add(id2);
619

620
    // Add conference to map
621
    conferenceMap_.insert(ConferenceEntry(conf->getConfID(), conf));
Alexandre Savard's avatar
Alexandre Savard committed
622

623
    // broadcast a signal over dbus
624
    dbus_.getCallManager()->conferenceCreated(conf->getConfID());
625

626
    return conf;
627
628
}

629
void ManagerImpl::removeConference(const std::string& conference_id)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
630
{
631
    _debug("Manager: Remove conference %s", conference_id.c_str());
632

633
634
    _debug("Manager: number of participants: %u", conferenceMap_.size());
    ConferenceMap::iterator iter = conferenceMap_.find(conference_id);
635

636
    Conference* conf = 0;
637

638
    if (iter != conferenceMap_.end())
639
        conf = iter->second;
640

641
    if (conf == NULL) {
642
        _error("Manager: Error: Conference not found");
643
644
        return;
    }
645

646
    // broadcast a signal over dbus
647
    dbus_.getCallManager()->conferenceRemoved(conference_id);
648

649
    // We now need to bind the audio to the remain participant
650

651
    // Unbind main participant audio from conference
652
    getMainBuffer()->unBindAll(Call::DEFAULT_ID);
653

654
    ParticipantSet participants(conf->getParticipantList());
655

656
657
    // bind main participant audio to remaining conference call
    ParticipantSet::iterator iter_p = participants.begin();
658

659
    if (iter_p != participants.end())
660
        getMainBuffer()->bindCallID(*iter_p, Call::DEFAULT_ID);
661

662
    // Then remove the conference from the conference map
663
    if (conferenceMap_.erase(conference_id) == 1)