managerimpl.cpp 132 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: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
8
 *  Author: Guillaume Carmel-Archambault <guillaume.carmel-archambault@savoirfairelinux.com>
9
 *
jpbl's avatar
jpbl committed
10
11
 *  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
12
 *  the Free Software Foundation; either version 3 of the License, or
jpbl's avatar
jpbl committed
13
 *  (at your option) any later version.
14
 *
jpbl's avatar
jpbl committed
15
16
17
18
 *  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.
19
 *
jpbl's avatar
jpbl committed
20
21
22
23
24
 *  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.
 */

25
26
27
28
29
#include "managerimpl.h"

#include "account.h"
#include "dbus/callmanager.h"
#include "user_cfg.h"
30
#include "global.h"
31
#include "sip/sipaccount.h"
32

33
34
35
36
37
38
39
40
41
42
#include "audio/audiolayer.h"
#include "audio/alsa/alsalayer.h"
#include "audio/pulseaudio/pulselayer.h"
#include "audio/sound/tonelist.h"
#include "history/historymanager.h"
#include "accountcreator.h" // create new account
#include "sip/sipvoiplink.h"
#include "manager.h"
#include "dbus/configurationmanager.h"

43
44
#include "conference.h"

jpbl's avatar
jpbl committed
45
46
47
48
49
#include <errno.h>
#include <time.h>
#include <cstdlib>
#include <iostream>
#include <fstream>
50
#include <sstream>
jpbl's avatar
jpbl committed
51
#include <sys/types.h> // mkdir(2)
52
53
#include <sys/stat.h>  // mkdir(2)
#include <pwd.h>       // getpwuid
jpbl's avatar
jpbl committed
54

55
#define DIRECT_IP_CALL	"IP CALL"
jpbl's avatar
jpbl committed
56
57
58
59
60
61

#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)))

62
63
#define MD5_APPEND(pms,buf,len) pj_md5_update(pms, (const pj_uint8_t*)buf, len)

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

95
    // initialize random generator for call id
96
    srand (time (NULL));
yanmorin's avatar
   
yanmorin committed
97

98
    _cleaner = new NumberCleaner ();
99
    _history = new HistoryManager ();
100

yanmorin's avatar
   
yanmorin committed
101
#ifdef TEST
102
103
104
105
    testAccountMap();
    loadAccountMap();
    testCallAccountMap();
    unloadAccountMap();
yanmorin's avatar
   
yanmorin committed
106
107
#endif

108
109
    // should be call before initConfigFile
    // loadAccountMap();, called in init() now.
jpbl's avatar
jpbl committed
110
111
112
}

// never call if we use only the singleton...
113
ManagerImpl::~ManagerImpl (void)
jpbl's avatar
jpbl committed
114
{
115
    // terminate();
116
117
    delete _cleaner;
    _cleaner=0;
Julien Bonjean's avatar
Julien Bonjean committed
118
    _debug ("%s stop correctly.", PROGNAME);
jpbl's avatar
jpbl committed
119
120
}

121
void
122
ManagerImpl::init()
jpbl's avatar
jpbl committed
123
{
124

125
126
    // Load accounts, init map
    loadAccountMap();
127

128
    initVolume();
129

130
    if (_exist == 0) {
Julien Bonjean's avatar
Julien Bonjean committed
131
        _debug ("Cannot create config file in your home directory");
132
    }
133

134
    initAudioDriver();
135

136
    selectAudioDriver();
jpbl's avatar
jpbl committed
137

138
139
    // Initialize the list of supported audio codecs
    initAudioCodec();
140

141
    AudioLayer *audiolayer = getAudioDriver();
142

143
    if (audiolayer != 0) {
144
        unsigned int sampleRate = audiolayer->getSampleRate();
jpbl's avatar
jpbl committed
145

146
147
148
        _debugInit ("Load Telephone Tone");
        std::string country = getConfigString (PREFERENCES, ZONE_TONE);
        _telephoneTone = new TelephoneTone (country, sampleRate);
jpbl's avatar
jpbl committed
149

150
151
        _debugInit ("Loading DTMF key");
        _dtmfKey = new DTMF (sampleRate);
152
    }
153
154

    if (audiolayer == 0)
155
        audiolayer->stopStream();
156
157
158


    // Load the history
159
    _history->load_history (getConfigInt (PREFERENCES, CONFIG_HISTORY_LIMIT));
jpbl's avatar
jpbl committed
160
161
162
163
}

void ManagerImpl::terminate()
{
Julien Bonjean's avatar
Julien Bonjean committed
164
    _debug ("ManagerImpl::terminate ");
165
    saveConfig();
jpbl's avatar
jpbl committed
166

167
    unloadAccountMap();
168

Julien Bonjean's avatar
Julien Bonjean committed
169
    _debug ("Unload DTMF Key ");
170
    delete _dtmfKey;
jpbl's avatar
jpbl committed
171

Julien Bonjean's avatar
Julien Bonjean committed
172
    _debug ("Unload Audio Driver ");
173
174
    delete _audiodriver;
    _audiodriver = NULL;
jpbl's avatar
jpbl committed
175

Julien Bonjean's avatar
Julien Bonjean committed
176
    _debug ("Unload Telephone Tone ");
177
178
    delete _telephoneTone;
    _telephoneTone = NULL;
179

Julien Bonjean's avatar
Julien Bonjean committed
180
    _debug ("Unload Audio Codecs ");
181
    _codecDescriptorMap.deleteHandlePointer();
182

jpbl's avatar
jpbl committed
183
184
}

yanmorin's avatar
   
yanmorin committed
185
bool
186
187
188
ManagerImpl::isCurrentCall (const CallID& callId)
{
    return (_currentCallId2 == callId ? true : false);
jpbl's avatar
jpbl committed
189
190
}

yanmorin's avatar
   
yanmorin committed
191
bool
192
193
ManagerImpl::hasCurrentCall()
{
Julien Bonjean's avatar
Julien Bonjean committed
194
    // _debug ("ManagerImpl::hasCurrentCall current call ID = %s", _currentCallId2.c_str());
195
196
197
198
199
200

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

    return false;
jpbl's avatar
jpbl committed
201
202
}

203
const CallID&
204
205
206
ManagerImpl::getCurrentCallId()
{
    return _currentCallId2;
jpbl's avatar
jpbl committed
207
208
209
}

void
210
211
212
ManagerImpl::switchCall (const CallID& id)
{
    ost::MutexLock m (_currentCallMutex);
Julien Bonjean's avatar
Julien Bonjean committed
213
    _debug ("----- Switch current call id to %s -----", id.c_str());
214
    _currentCallId2 = id;
215

216
217
    /*
    AudioLayer *al = getAudioDriver();
218

219
    if (id != "") {
220

221
    if(isConference(id)) {
222

223
        Conference *conf;
224

225
226
227
        ConferenceMap::iterator iter = _conferencemap.find(id);
        if(iter != _conferencemap.end())
        {
Julien Bonjean's avatar
Julien Bonjean committed
228
    	_debug("    set call recordable in audio layer");
229
230
231
232
233
    	conf = iter->second;
    	al->setRecorderInstance((Recordable*)conf);
        }
    }
    else {
234

235
236
        // set the recordable instance in audiolayer
        AccountID account_id = getAccountFromCall(id);
237
238


239
240
241
        Call *call = NULL;
        call = getAccountLink (account_id)->getCall(id);

Julien Bonjean's avatar
Julien Bonjean committed
242
        _debug("    set call recordable in audio layer");
243
244
        al->setRecorderInstance((Recordable*)call);
    }
245
246
    }
    */
jpbl's avatar
jpbl committed
247
248
249
250
251
252
}


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

255
bool
256
ManagerImpl::outgoingCall (const std::string& account_id, const CallID& call_id, const std::string& to)
yanmorin's avatar
   
yanmorin committed
257
{
258
    std::string pattern, to_cleaned;
Emmanuel Milou's avatar
Emmanuel Milou committed
259
260
    Call::CallConfiguration callConfig;
    SIPVoIPLink *siplink;
261

Julien Bonjean's avatar
Julien Bonjean committed
262
    _debug ("ManagerImpl::outgoingCall(%s)", call_id.c_str());
263
264

    CallID current_call_id = getCurrentCallId();
265

266
267
    if (getConfigString (HOOKS, PHONE_NUMBER_HOOK_ENABLED) ==  "1")
        _cleaner->set_phone_number_prefix (getConfigString (HOOKS, PHONE_NUMBER_HOOK_ADD_PREFIX));
268
269
    else
        _cleaner->set_phone_number_prefix ("");
Emmanuel Milou's avatar
Emmanuel Milou committed
270

271
    to_cleaned = _cleaner->clean (to);
Emmanuel Milou's avatar
Emmanuel Milou committed
272
273

    /* Check what kind of call we are dealing with */
274
    check_call_configuration (call_id, to_cleaned, &callConfig);
275

276
    // in any cases we have to detach from current communication
277
    if (hasCurrentCall()) {
278

Julien Bonjean's avatar
Julien Bonjean committed
279
        _debug ("    outgoingCall: Has current call (%s) put it onhold", current_call_id.c_str());
280
281
282
283

        // if this is not a conferenceand this and is not a conference participant

        if (!isConference (current_call_id) && !participToConference (current_call_id)) {
Julien Bonjean's avatar
Julien Bonjean committed
284
            _debug ("    outgoingCall: Put the current call (%s) on hold", current_call_id.c_str());
285
286
            onHoldCall (current_call_id);
        } else if (isConference (current_call_id) && !participToConference (call_id)) {
Julien Bonjean's avatar
Julien Bonjean committed
287
            _debug ("    outgoingCall: detach main participant from conference");
288
289
            detachParticipant (default_id, current_call_id);
        }
290
291
    }

Emmanuel Milou's avatar
Emmanuel Milou committed
292
    if (callConfig == Call::IPtoIP) {
Julien Bonjean's avatar
Julien Bonjean committed
293
        _debug ("    outgoingCall: Start IP to IP call");
Emmanuel Milou's avatar
Emmanuel Milou committed
294
        /* We need to retrieve the sip voiplink instance */
295
296
        siplink = SIPVoIPLink::instance ("");

297
298
        if (siplink->new_ip_to_ip_call (call_id, to_cleaned)) {
            switchCall (call_id);
Emmanuel Milou's avatar
Emmanuel Milou committed
299
            return true;
300
        } else {
301
            callFailure (call_id);
Emmanuel Milou's avatar
Emmanuel Milou committed
302
        }
303

Emmanuel Milou's avatar
Emmanuel Milou committed
304
        return false;
305
    }
306

307
    if (!accountExists (account_id)) {
Julien Bonjean's avatar
Julien Bonjean committed
308
        _debug ("! Manager Error: Outgoing Call: account doesn't exist");
Emmanuel Milou's avatar
Emmanuel Milou committed
309
310
        return false;
    }
311

312
    if (getAccountFromCall (call_id) != AccountNULL) {
Julien Bonjean's avatar
Julien Bonjean committed
313
        _debug ("! Manager Error: Outgoing Call: call id already exists");
Emmanuel Milou's avatar
Emmanuel Milou committed
314
315
        return false;
    }
316
317


Julien Bonjean's avatar
Julien Bonjean committed
318
    _debug ("- Manager Action: Adding Outgoing Call %s on account %s", call_id.data(), account_id.data());
319

320
    associateCallToAccount (call_id, account_id);
321

322
323
    if (getAccountLink (account_id)->newOutgoingCall (call_id, to_cleaned)) {
        switchCall (call_id);
Emmanuel Milou's avatar
Emmanuel Milou committed
324
325
        return true;
    } else {
326
        callFailure (call_id);
Julien Bonjean's avatar
Julien Bonjean committed
327
        _debug ("! Manager Error: An error occur, the call was not created");
Emmanuel Milou's avatar
Emmanuel Milou committed
328
    }
329

Emmanuel Milou's avatar
Emmanuel Milou committed
330
    return false;
jpbl's avatar
jpbl committed
331
332
}

yanmorin's avatar
   
yanmorin committed
333
//THREAD=Main : for outgoing Call
334
bool
335
ManagerImpl::answerCall (const CallID& call_id)
jpbl's avatar
jpbl committed
336
{
337

Julien Bonjean's avatar
Julien Bonjean committed
338
    _debug ("ManagerImpl::answerCall(%s)", call_id.c_str());
339

340
    stopTone ();
341

342
343
344
345
    // store the current call id
    CallID current_call_id = getCurrentCallId();

    AccountID account_id = getAccountFromCall (call_id);
346
347

    if (account_id == AccountNULL) {
Julien Bonjean's avatar
Julien Bonjean committed
348
        _debug ("    answerCall: AccountId is null");
349
    }
350

351
    Call* call = NULL;
352

353
    call = getAccountLink (account_id)->getCall (call_id);
354

355
    if (call == NULL) {
Julien Bonjean's avatar
Julien Bonjean committed
356
        _debug ("    answerCall: Call is null");
357
    }
358
359

    // in any cases we have to detach from current communication
Alexandre Savard's avatar
Alexandre Savard committed
360
    if (hasCurrentCall()) {
361

Julien Bonjean's avatar
Julien Bonjean committed
362
        _debug ("    answerCall: Currently conversing with %s", current_call_id.c_str());
363
364
365
        // if it is not a conference and is not a conference participant

        if (!isConference (current_call_id) && !participToConference (current_call_id)) {
Julien Bonjean's avatar
Julien Bonjean committed
366
            _debug ("    answerCall: Put the current call (%s) on hold", current_call_id.c_str());
367
368
369
370
371
            onHoldCall (current_call_id);
        }

        // if we are talking to a conference and we are answering an incoming call
        else if (isConference (current_call_id) && !participToConference (call_id)) {
Julien Bonjean's avatar
Julien Bonjean committed
372
            _debug ("    answerCall: Detach main participant from conference");
373
374
            detachParticipant (default_id, current_call_id);
        }
375

Alexandre Savard's avatar
Alexandre Savard committed
376
    }
377

378

379
    if (!getAccountLink (account_id)->answer (call_id)) {
380
        // error when receiving...
381
        removeCallAccount (call_id);
382
383
        return false;
    }
Alexandre Savard's avatar
Alexandre Savard committed
384

385
    // if it was waiting, it's waiting no more
386
    if (_dbus) _dbus->getCallManager()->callStateChanged (call_id, "CURRENT");
Emmanuel Milou's avatar
Emmanuel Milou committed
387

388
389
    // std::string codecName = Manager::instance().getCurrentCodecName (call_id);
    // if (_dbus) _dbus->getCallManager()->currentSelectedCodec (call_id, codecName.c_str());
390

391
    removeWaitingCall (call_id);
392

393
    // if we dragged this call into a conference already
394
395
396
    if (participToConference (call_id)) {

        // AccountID currentAccountId;
397
398
        // Call* call = NULL;

399
400
401
402
403
404
        // currentAccountId = getAccountFromCall (call_id);
        // call = getAccountLink (currentAccountId)->getCall (call_id);

        switchCall (call->getConfId());
    } else {
        switchCall (call_id);
405
    }
406
407

    return true;
jpbl's avatar
jpbl committed
408
409
}

yanmorin's avatar
   
yanmorin committed
410
//THREAD=Main
411
bool
412
ManagerImpl::hangupCall (const CallID& call_id)
jpbl's avatar
jpbl committed
413
{
Julien Bonjean's avatar
Julien Bonjean committed
414
    _debug ("ManagerImpl::hangupCall(%s)", call_id.c_str());
415
    PulseLayer *pulselayer;
416
    AccountID account_id;
417
    bool returnValue = true;
Emmanuel Milou's avatar
Emmanuel Milou committed
418

419
    // store the current call id
420
421
    CallID current_call_id = getCurrentCallId();

422
    stopTone ();
yanmorin's avatar
   
yanmorin committed
423

424
    /* Broadcast a signal over DBus */
Julien Bonjean's avatar
Julien Bonjean committed
425
    _debug ("    hangupCall: Send DBUS call state change (HUNGUP) for id %s", call_id.c_str());
426

427
    if (_dbus) _dbus->getCallManager()->callStateChanged (call_id, "HUNGUP");
428

429
    if (participToConference (call_id)) {
430

431
        Conference *conf = getConferenceFromCallID (call_id);
432

433
434
435
436
437
438
        if (conf != NULL) {
            // remove this participant
            removeParticipant (call_id);

            processRemainingParticipant (current_call_id, conf);
        }
439

440
441
442
443
    } else {
        // we are not participating to a conference, current call switched to ""
        if (!isConference (current_call_id))
            switchCall ("");
444
    }
445

Emmanuel Milou's avatar
Emmanuel Milou committed
446
    /* Direct IP to IP call */
447
448
    if (getConfigFromCall (call_id) == Call::IPtoIP) {
        returnValue = SIPVoIPLink::instance (AccountNULL)->hangup (call_id);
449
    }
Emmanuel Milou's avatar
Emmanuel Milou committed
450
    /* Classic call, attached to an account */
451
    else {
452
        account_id = getAccountFromCall (call_id);
453

454
        if (account_id == AccountNULL) {
455

Julien Bonjean's avatar
Julien Bonjean committed
456
            _debug ("! Manager Hangup Call: Call doesn't exists");
457
            returnValue = false;
Emmanuel Milou's avatar
Emmanuel Milou committed
458
        }
459
	else {
460

461
462
463
	    returnValue = getAccountLink (account_id)->hangup (call_id);
	    removeCallAccount (call_id);
	}
Emmanuel Milou's avatar
Emmanuel Milou committed
464
    }
465

466
467
468
469
470
    int nbCalls = getCallList().size();

    AudioLayer *audiolayer = getAudioDriver();

    // stop streams
471
    if (audiolayer && (nbCalls <= 0)) {
472
473
474
475
        _debug ("    hangupCall: stop audio stream, ther is only %i call(s) remaining", nbCalls);
        audiolayer->stopStream();
    }

476
    if (_audiodriver->getLayerType() == PULSEAUDIO) {
477
478
        pulselayer = dynamic_cast<PulseLayer *> (getAudioDriver());
    }
479

480
    return returnValue;
jpbl's avatar
jpbl committed
481
482
}

Alexandre Savard's avatar
Alexandre Savard committed
483
484
485
486

bool
ManagerImpl::hangupConference (const ConfID& id)
{
Julien Bonjean's avatar
Julien Bonjean committed
487
    _debug ("ManagerImpl::hangupConference()");
Alexandre Savard's avatar
Alexandre Savard committed
488
489

    Conference *conf;
490
    ConferenceMap::iterator iter_conf = _conferencemap.find (id);
Alexandre Savard's avatar
Alexandre Savard committed
491
492
493

    AccountID currentAccountId;

494
    // Call* call = NULL;
Alexandre Savard's avatar
Alexandre Savard committed
495
496


497
498
    if (iter_conf != _conferencemap.end()) {
        conf = iter_conf->second;
Alexandre Savard's avatar
Alexandre Savard committed
499

500
501
        ParticipantSet participants = conf->getParticipantList();
        ParticipantSet::iterator iter_participant = participants.begin();
Alexandre Savard's avatar
Alexandre Savard committed
502

503
        while (iter_participant != participants.end()) {
Julien Bonjean's avatar
Julien Bonjean committed
504
            _debug ("ManagerImpl::hangupConference participant %s", (*iter_participant).c_str());
Alexandre Savard's avatar
Alexandre Savard committed
505

506
            hangupCall (*iter_participant);
Alexandre Savard's avatar
Alexandre Savard committed
507

508
509
510
            iter_participant++;

        }
Alexandre Savard's avatar
Alexandre Savard committed
511
512
513

    }

514
515
    switchCall ("");

Alexandre Savard's avatar
Alexandre Savard committed
516
517
518
519
    return true;
}


yanmorin's avatar
   
yanmorin committed
520
//THREAD=Main
521
bool
yanmorin's avatar
   
yanmorin committed
522
ManagerImpl::cancelCall (const CallID& id)
jpbl's avatar
jpbl committed
523
{
Emmanuel Milou's avatar
Emmanuel Milou committed
524
525
    AccountID accountid;
    bool returnValue;
yanmorin's avatar
   
yanmorin committed
526

527
    stopTone ();
528

Emmanuel Milou's avatar
Emmanuel Milou committed
529
    /* Direct IP to IP call */
530

Emmanuel Milou's avatar
Emmanuel Milou committed
531
    if (getConfigFromCall (id) == Call::IPtoIP) {
532
        returnValue = SIPVoIPLink::instance (AccountNULL)->cancel (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
533
534
535
    }

    /* Classic call, attached to an account */
536
    else {
537
538
        accountid = getAccountFromCall (id);

Emmanuel Milou's avatar
Emmanuel Milou committed
539
        if (accountid == AccountNULL) {
Julien Bonjean's avatar
Julien Bonjean committed
540
            _debug ("! Manager Cancel Call: Call doesn't exists");
Emmanuel Milou's avatar
Emmanuel Milou committed
541
542
            return false;
        }
543
544
545
546

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

        removeCallAccount (id);
Emmanuel Milou's avatar
Emmanuel Milou committed
547
    }
548

Emmanuel Milou's avatar
Emmanuel Milou committed
549
    // it could be a waiting call?
550
551
552
    removeWaitingCall (id);

    switchCall ("");
Emmanuel Milou's avatar
Emmanuel Milou committed
553
554

    return returnValue;
jpbl's avatar
jpbl committed
555
556
}

yanmorin's avatar
   
yanmorin committed
557
//THREAD=Main
558
bool
559
ManagerImpl::onHoldCall (const CallID& call_id)
jpbl's avatar
jpbl committed
560
{
561
    AccountID account_id;
Emmanuel Milou's avatar
Emmanuel Milou committed
562
    bool returnValue;
yanmorin's avatar
   
yanmorin committed
563

Julien Bonjean's avatar
Julien Bonjean committed
564
    _debug ("ManagerImpl::onHoldCall(%s)", call_id.c_str());
565

566
    stopTone ();
567

568
569
    CallID current_call_id = getCurrentCallId();

Julien Bonjean's avatar
Julien Bonjean committed
570
    _debug ("    onHoldCall: try to put call %s on hold", call_id.c_str());
571

572
    /* Direct IP to IP call */
573

574
    if (getConfigFromCall (call_id) == Call::IPtoIP) {
575
        returnValue = SIPVoIPLink::instance (AccountNULL)-> onhold (call_id);
Emmanuel Milou's avatar
Emmanuel Milou committed
576
    }
577

Emmanuel Milou's avatar
Emmanuel Milou committed
578
    /* Classic call, attached to an account */
579
    else {
580
        account_id = getAccountFromCall (call_id);
581

582
        if (account_id == AccountNULL) {
Julien Bonjean's avatar
Julien Bonjean committed
583
            _debug ("    onHoldCall: Account ID %s or callid %s doesn't exists", account_id.c_str(), call_id.c_str());
584
585
            return false;
        }
586

587
        returnValue = getAccountLink (account_id)->onhold (call_id);
Emmanuel Milou's avatar
Emmanuel Milou committed
588
    }
589

590
    removeWaitingCall (call_id);
591

592
    // keeps current call id if the action is not holding this call or a new outgoing call
593

594
595
596
    if (current_call_id == call_id) {

        switchCall ("");
597
    }
598

599
    if (_dbus) _dbus->getCallManager()->callStateChanged (call_id, "HOLD");
600

Emmanuel Milou's avatar
Emmanuel Milou committed
601
    return returnValue;
yanmorin's avatar
   
yanmorin committed
602
603
604
}

//THREAD=Main
605
bool
606
ManagerImpl::offHoldCall (const CallID& call_id)
yanmorin's avatar
   
yanmorin committed
607
{
608

609
    AccountID account_id;
610
    bool returnValue, is_rec;
Emmanuel Milou's avatar
Emmanuel Milou committed
611
    std::string codecName;
612

613
    is_rec = false;
614

Julien Bonjean's avatar
Julien Bonjean committed
615
    _debug ("ManagerImpl::offHoldCall(%s)", call_id.c_str());
616

617
    stopTone ();
618

619
    CallID current_call_id = getCurrentCallId();
620

621
    //Place current call on hold if it isn't
622
623
624
625

    if (hasCurrentCall()) {
        // if this is not a conferenceand this and is not a conference participant
        if (!isConference (current_call_id) && !participToConference (current_call_id)) {
Julien Bonjean's avatar
Julien Bonjean committed
626
            _debug ("    offHoldCall: put current call (%s) on hold", current_call_id.c_str());
627
628
            onHoldCall (current_call_id);
        } else if (isConference (current_call_id) && !participToConference (call_id)) {
Julien Bonjean's avatar
Julien Bonjean committed
629
            _debug ("    offHoldCall Put current conference (%s) on hold", current_call_id.c_str());
630
631
            detachParticipant (default_id, current_call_id);
        }
Emmanuel Milou's avatar
Emmanuel Milou committed
632
    }
633

634
    // switch current call id to id since sipvoip link need it to amke a call
635
    // switchCall(id);
636

Emmanuel Milou's avatar
Emmanuel Milou committed
637
    /* Direct IP to IP call */
638
    if (getConfigFromCall (call_id) == Call::IPtoIP) {
639
        // is_rec = SIPVoIPLink::instance (AccountNULL)-> isRecording (call_id);
640
        returnValue = SIPVoIPLink::instance (AccountNULL)-> offhold (call_id);
Emmanuel Milou's avatar
Emmanuel Milou committed
641
    }
alexandresavard's avatar
alexandresavard committed
642

Emmanuel Milou's avatar
Emmanuel Milou committed
643
    /* Classic call, attached to an account */
644
    else {
645
        account_id = getAccountFromCall (call_id);
646

647
        if (account_id == AccountNULL) {
Julien Bonjean's avatar
Julien Bonjean committed
648
            _debug ("Manager OffHold Call: Call doesn't exists");
Emmanuel Milou's avatar
Emmanuel Milou committed
649
650
            return false;
        }
651

Julien Bonjean's avatar
Julien Bonjean committed
652
        _debug ("Setting OFFHOLD, Account %s, callid %s", account_id.c_str(), call_id.c_str());
653

654
        is_rec = getAccountLink (account_id)->getCall (call_id)->isRecording();
655
        returnValue = getAccountLink (account_id)->offhold (call_id);
Emmanuel Milou's avatar
Emmanuel Milou committed
656
    }
alexandresavard's avatar
alexandresavard committed
657

658

659
    if (_dbus) {
660
        if (is_rec)
661
            _dbus->getCallManager()->callStateChanged (call_id, "UNHOLD_RECORD");
662
        else
663
            _dbus->getCallManager()->callStateChanged (call_id, "UNHOLD_CURRENT");
664

Emmanuel Milou's avatar
Emmanuel Milou committed
665
    }
666

667
668
669
    if (participToConference (call_id)) {

        AccountID currentAccountId;
670
671
        Call* call = NULL;

672
673
674
675
676
677
678
679
        currentAccountId = getAccountFromCall (call_id);
        call = getAccountLink (currentAccountId)->getCall (call_id);

        switchCall (call->getConfId());

    } else {
        switchCall (call_id);
        _audiodriver->flushMain();
680
    }
681

682

683
    // codecName = getCurrentCodecName (call_id);
Julien Bonjean's avatar
Julien Bonjean committed
684
    // _debug("ManagerImpl::hangupCall(): broadcast codec name %s ",codecName.c_str());
685

686
    // if (_dbus) _dbus->getCallManager()->currentSelectedCodec (call_id,codecName.c_str());
687
688


Emmanuel Milou's avatar
Emmanuel Milou committed
689
    return returnValue;
jpbl's avatar
jpbl committed
690
691
}

yanmorin's avatar
   
yanmorin committed
692
//THREAD=Main
693
bool
694
ManagerImpl::transferCall (const CallID& call_id, const std::string& to)
jpbl's avatar
jpbl committed
695
{
Emmanuel Milou's avatar
Emmanuel Milou committed
696
697
    AccountID accountid;
    bool returnValue;
698

699
    stopTone ();
700

701
702
    CallID current_call_id = getCurrentCallId();

703
704
705
    if (participToConference (call_id)) {

        _debug("Particip to a conference\n");
706

707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
        Conference *conf = getConferenceFromCallID (call_id);

        if (conf != NULL) {
            // remove this participant
            removeParticipant (call_id);

            processRemainingParticipant (current_call_id, conf);
        }
    } else {

        _debug("Do not Particip to a conference\n");

        // we are not participating to a conference, current call switched to ""
        if (!isConference (current_call_id))
            switchCall ("");
    }
723

724
    /* Direct IP to IP call */
725
726
    if (getConfigFromCall (call_id) == Call::IPtoIP) {
        returnValue = SIPVoIPLink::instance (AccountNULL)-> transfer (call_id, to);
Emmanuel Milou's avatar
Emmanuel Milou committed
727
728
    }
    /* Classic call, attached to an account */
729
    else {
730
        accountid = getAccountFromCall (call_id);
731

Emmanuel Milou's avatar