callmanager.cpp 12.8 KB
Newer Older
1
/*
2
 *  Copyright (C) 2004-2012 Savoir-Faire Linux Inc.
3
 *  Author: Pierre-Luc Beaudoin <pierre-luc.beaudoin@savoirfairelinux.com>
4
 *  Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com>
5
 *
6
7
 *  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
8
 *  the Free Software Foundation; either version 3 of the License, or
9
 *  (at your option) any later version.
10
 *
11
12
13
14
 *  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.
15
 *
16
17
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
18
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
19
20
21
22
23
24
25
26
27
28
29
 *
 *  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.
30
 */
31
32
#include <vector>

33
34
35
#include "global.h"
#include "callmanager.h"

Rafaël Carré's avatar
Rafaël Carré committed
36
#include "sip/sipcall.h"
37
#include "sip/sipvoiplink.h"
38
39
#include "sip/sipaccount.h"
#include "sip/sippresence.h"
40
#include "audio/audiolayer.h"
41
#include "audio/audiortp/audio_rtp_factory.h"
42
#if HAVE_ZRTP
43
#include "audio/audiortp/audio_zrtp_session.h"
44
#endif
45

46
#include "logger.h"
47
#include "manager.h"
48

49
CallManager::CallManager(DBus::Connection& connection)
50
    : DBus::ObjectAdaptor(connection, "/org/sflphone/SFLphone/CallManager")
51
{}
52

53
bool CallManager::placeCall(const std::string& accountID,
54
55
                            const std::string& callID,
                            const std::string& to)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
56
{
57
    // Check if a destination number is available
58
    if (to.empty()) {
59
        DEBUG("No number entered - Call stopped");
60
61
62
63
        return false;
    } else {
        return Manager::instance().outgoingCall(accountID, callID, to);
    }
64
65
}

66
bool
67
CallManager::refuse(const std::string& callID)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
68
{
69
    return Manager::instance().refuseCall(callID);
70
71
}

72
bool
73
CallManager::accept(const std::string& callID)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
74
{
75
    return Manager::instance().answerCall(callID);
76
77
}

78
bool
79
CallManager::hangUp(const std::string& callID)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
80
{
81
    return Manager::instance().hangupCall(callID);
82
83
}

84
bool
85
CallManager::hangUpConference(const std::string& confID)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
86
{
87
    return Manager::instance().hangupConference(confID);
Alexandre Savard's avatar
Alexandre Savard committed
88
89
}

90
bool
91
CallManager::hold(const std::string& callID)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
92
{
93
    return Manager::instance().onHoldCall(callID);
94
95
}

96
bool
97
CallManager::unhold(const std::string& callID)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
98
{
99
    return Manager::instance().offHoldCall(callID);
100
101
}

102
bool
103
CallManager::transfer(const std::string& callID, const std::string& to)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
104
{
105
    return Manager::instance().transferCall(callID, to);
106
107
}

108
109
bool
CallManager::attendedTransfer(const std::string& transferID, const std::string& targetID)
110
{
111
    return Manager::instance().attendedTransfer(transferID, targetID);
112
}
113

114
void CallManager::setVolume(const std::string& device, const double& value)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
115
{
116
117
118
    AudioLayer *audiolayer = Manager::instance().getAudioDriver();

    if(!audiolayer) {
Tristan Matthews's avatar
Tristan Matthews committed
119
        ERROR("Audio layer not valid while updating volume");
120
121
122
123
124
        return;
    }

    DEBUG("DBUS set volume for %s: %f", device.c_str(), value);

125
126
127
128
129
    if (device == "speaker") {
        audiolayer->setPlaybackGain((int)(value * 100.0));
    } else if (device == "mic") {
        audiolayer->setCaptureGain((int)(value * 100.0));
    }
130

131
    volumeChanged(device, value);
132
133
}

134
double
135
CallManager::getVolume(const std::string& device)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
136
{
137
138
    AudioLayer *audiolayer = Manager::instance().getAudioDriver();

139
    if(!audiolayer) {
Tristan Matthews's avatar
Tristan Matthews committed
140
        ERROR("Audio layer not valid while updating volume");
141
142
143
        return 0.0;
    }

144
    if (device == "speaker")
145
        return audiolayer->getPlaybackGain() / 100.0;
146
    else if (device == "mic")
147
        return audiolayer->getCaptureGain() / 100.0;
148

149
150
151
    return 0;
}

152
153
154
bool
CallManager::joinParticipant(const std::string& sel_callID,
                             const std::string& drag_callID)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
155
{
156
    return Manager::instance().joinParticipant(sel_callID, drag_callID);
157
158
}

159
void
160
CallManager::createConfFromParticipantList(const std::vector<std::string>& participants)
161
{
162
    Manager::instance().createConfFromParticipantList(participants);
163
164
}

165
166
167
168
169
170
171
172
173
174
175
176
bool
CallManager::isConferenceParticipant(const std::string& callID)
{
    return  Manager::instance().isConferenceParticipant(callID);
}

void
CallManager::removeConference(const std::string& conference_id)
{
    Manager::instance().removeConference(conference_id);
}

177
bool
178
CallManager::addParticipant(const std::string& callID, const std::string& confID)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
179
{
180
    return  Manager::instance().addParticipant(callID, confID);
181
182
}

183
bool
184
CallManager::addMainParticipant(const std::string& confID)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
185
{
186
    return Manager::instance().addMainParticipant(confID);
187
188
}

189
bool
190
CallManager::detachParticipant(const std::string& callID)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
191
{
192
    return Manager::instance().detachParticipant(callID);
193
194
}

195
bool
196
CallManager::joinConference(const std::string& sel_confID, const std::string& drag_confID)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
197
{
198
    return Manager::instance().joinConference(sel_confID, drag_confID);
199
200
}

201
bool
202
CallManager::holdConference(const std::string& confID)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
203
{
204
    return Manager::instance().holdConference(confID);
205
206
}

207
bool
208
CallManager::unholdConference(const std::string& confID)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
209
{
210
    return Manager::instance().unHoldConference(confID);
211
212
}

213
std::map<std::string, std::string>
214
CallManager::getConferenceDetails(const std::string& callID)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
215
{
216
    return Manager::instance().getConferenceDetails(callID);
217
}
218

219
std::vector<std::string>
220
CallManager::getConferenceList()
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
221
{
222
223
    return Manager::instance().getConferenceList();
}
224

225
std::vector<std::string>
226
CallManager::getParticipantList(const std::string& confID)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
227
{
228
    return Manager::instance().getParticipantList(confID);
229
230
}

231
232
233
234
235
236
std::string
CallManager::getConferenceId(const std::string& callID)
{
    return Manager::instance().getConferenceId(callID);
}

237
bool
238
239
CallManager::startRecordedFilePlayback(const std::string& filepath)
{
240
    return Manager::instance().startRecordedFilePlayback(filepath);
241
242
243
244
245
246
247
248
}

void
CallManager::stopRecordedFilePlayback(const std::string& filepath)
{
    Manager::instance().stopRecordedFilePlayback(filepath);
}

249
250
251
252
253
254
bool
CallManager::toggleRecording(const std::string& callID)
{
    return Manager::instance().toggleRecordingCall(callID);
}

alexandresavard's avatar
alexandresavard committed
255
void
256
CallManager::setRecording(const std::string& callID)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
257
{
258
    toggleRecording(callID);
alexandresavard's avatar
alexandresavard committed
259
260
}

261
262
263
264
265
266
void
CallManager::recordPlaybackSeek(const double& value)
{
    Manager::instance().recordingPlaybackSeek(value);
}

267
bool
268
CallManager::getIsRecording(const std::string& callID)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
269
{
270
    return Manager::instance().isRecording(callID);
271
272
}

273
std::string CallManager::getCurrentAudioCodecName(const std::string& callID)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
274
{
275
    return Manager::instance().getCurrentAudioCodecName(callID);
Alexandre Savard's avatar
Alexandre Savard committed
276
277
}

278
std::map<std::string, std::string>
279
CallManager::getCallDetails(const std::string& callID)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
280
{
281
    return Manager::instance().getCallDetails(callID);
282
283
}

284
285
std::vector<std::string>
CallManager::getCallList()
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
286
{
287
288
    return Manager::instance().getCallList();
}
289
290

void
291
CallManager::playDTMF(const std::string& key)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
292
{
293
    Manager::instance().sendDtmf(Manager::instance().getCurrentCallId(), key.data()[0]);
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
294
295
}

296
void
297
CallManager::startTone(const int32_t& start , const int32_t& type)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
298
{
299
    if (start) {
300
301
302
303
304
        if (type == 0)
            Manager::instance().playTone();
        else
            Manager::instance().playToneWithMessage();
    } else
305
        Manager::instance().stopTone();
306
}
307

308
309
// TODO: this will have to be adapted
// for conferencing in order to get
310
// the right pointer for the given
311
// callID.
312
#if HAVE_ZRTP
313
314
sfl::AudioZrtpSession *
CallManager::getAudioZrtpSession(const std::string& callID)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
315
{
316
    // IP2IP profile is associated with IP2IP profile anyway
317
    SIPVoIPLink * link = static_cast<SIPVoIPLink *>(Manager::instance().getAccountLink(SIPAccount::IP2IP_PROFILE));
318

319
    if (!link)
320
        throw CallManagerException("Failed to get sip link");
321

322
323
    SIPCall *call = link->getSipCall(callID);
    if (!call)
324
        throw CallManagerException("Call id " + callID + " is not valid");
325

326
    sfl::AudioZrtpSession * zSession = call->getAudioRtp().getAudioZrtpSession();
327

Rafaël Carré's avatar
Rafaël Carré committed
328
    if (!zSession)
329
        throw CallManagerException("Failed to get AudioZrtpSession");
330

331
332
    return zSession;
}
333
#endif
334
335

void
336
CallManager::setSASVerified(const std::string& callID)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
337
{
338
#if HAVE_ZRTP
339
340
    try {
        sfl::AudioZrtpSession * zSession;
341
        zSession = getAudioZrtpSession(callID);
342
        zSession->SASVerified();
343
344
    } catch (...) {
    }
345
346
347
#else
    ERROR("No zrtp support for %s, please recompile SFLphone with zrtp", callID.c_str());
#endif
348
349
350
}

void
351
CallManager::resetSASVerified(const std::string& callID)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
352
{
353
#if HAVE_ZRTP
354
    try {
355
356
        sfl::AudioZrtpSession * zSession;
        zSession = getAudioZrtpSession(callID);
357
        zSession->resetSASVerified();
358
359
    } catch (...) {
    }
360
361
362
#else
    ERROR("No zrtp support for %s, please recompile SFLphone with zrtp", callID.c_str());
#endif
363
364
365
}

void
366
CallManager::setConfirmGoClear(const std::string& callID)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
367
{
368
#if HAVE_ZRTP
369
    try {
370
371
        sfl::AudioZrtpSession * zSession;
        zSession = getAudioZrtpSession(callID);
372
        zSession->goClearOk();
373
374
    } catch (...) {
    }
375
376
377
#else
    ERROR("No zrtp support for %s, please recompile SFLphone with zrtp", callID.c_str());
#endif
378
379
}

380
381
void
CallManager::requestGoClear(const std::string& callID)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
382
{
383
#if HAVE_ZRTP
384
    try {
385
386
        sfl::AudioZrtpSession * zSession;
        zSession = getAudioZrtpSession(callID);
387
        zSession->requestGoClear();
388
389
    } catch (...) {
    }
390
391
392
#else
    ERROR("No zrtp support for %s, please recompile SFLphone with zrtp", callID.c_str());
#endif
393
394
}

395
void
396
CallManager::acceptEnrollment(const std::string& callID, const bool& accepted)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
397
{
398
#if HAVE_ZRTP
399
    try {
400
401
        sfl::AudioZrtpSession * zSession;
        zSession = getAudioZrtpSession(callID);
402
        zSession->acceptEnrollment(accepted);
403
404
    } catch (...) {
    }
405
406
407
#else
    ERROR("No zrtp support for %s, please recompile SFLphone with zrtp", callID.c_str());
#endif
408
409
}

410
411
412
413
414
415
void CallManager::sendTextMessage(const std::string& callID, const std::string& message, const std::string& from)
{
#if HAVE_INSTANT_MESSAGING
    Manager::instance().sendTextMessage(callID, message, from);
#endif
}
416

Emmanuel Milou's avatar
Emmanuel Milou committed
417
void
418
CallManager::sendTextMessage(const std::string& callID, const std::string& message)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
419
{
420
#if HAVE_INSTANT_MESSAGING
421
    if (!Manager::instance().sendTextMessage(callID, message, "Me"))
422
        throw CallManagerException();
423
424
425
#else
    ERROR("Could not send \"%s\" text message to %s since SFLphone daemon does not support it, please recompile with instant messaging support", message.c_str(), callID.c_str());
#endif
426
}
427

428
429
430
431

/**
 * Un/subscribe to buddySipUri for an accountID
 */
432
void
433
CallManager::subscribePresSubClient(const std::string& accountID, const std::string& uri, const bool& flag)
434
{
435
436
437
438
439
440
441
442

    SIPAccount *sipaccount = Manager::instance().getSipAccount(accountID);
    if (!sipaccount)
        ERROR("Could not find account %s",accountID.c_str());
    else{
        DEBUG("%subscribePresence (acc:%s, buddy:%s)",flag? "S":"Uns", accountID.c_str(), uri.c_str());
        sipaccount->getPresence()->subscribePresSubClient(uri,flag);
    }
443
}
444

445
446
447
/**
 *  Enable the presence module (PUBLISH/SUBSCRIBE)
 */
448
void
449
450
451
452
453
454
455
456
CallManager::enablePresence(const std::string& accountID, const bool& flag){
    SIPAccount *sipaccount = Manager::instance().getSipAccount(accountID);
    if (!sipaccount)
        ERROR("Could not find account %s",accountID.c_str());
    else{
        DEBUG("Enable Presence (acc:%s : %s)",accountID.c_str(), flag? "yes":"no");
        sipaccount->getPresence()->enable(flag);
    }
457
458
}

459
460
461
462
/**
 * push a presence for a account
 * Notify for IP2IP account and publish for PBX account
 */
Eloi Bail's avatar
Eloi Bail committed
463
void
464
CallManager::sendPresence(const std::string& accountID, const std::string& status, const std::string& note)
Eloi Bail's avatar
Eloi Bail committed
465
{
466
467
468
469
470
471
472
    SIPAccount *sipaccount = Manager::instance().getSipAccount(accountID);
    if (!sipaccount)
        ERROR("Could not find account %s",accountID.c_str());
    else{
        DEBUG("Send Presence (acc:%s)",accountID.c_str());
        sipaccount->getPresence()->sendPresence(status,note);
    }
Eloi Bail's avatar
Eloi Bail committed
473
}
474

475
476
477
/**
 * Accept or not a PresSubServer request for IP2IP account
 */
478
void
479
480
481
482
483
484
485
486
487
CallManager::approvePresSubServer(const bool& flag, const std::string& buddySipUri)
{
    SIPAccount *sipaccount = Manager::instance().getIP2IPAccount();
    if (!sipaccount)
        ERROR("Could not find account IP2IP");
    else{
        DEBUG("Approve presence (acc:IP2IP, buddy:%s)", buddySipUri.c_str());
        sipaccount->getPresence()->approvePresSubServer(flag, buddySipUri);
    }
488
}