iaxvoiplink.cpp 20 KB
Newer Older
yanmorin's avatar
 
yanmorin committed
1
/*
2
 *  Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
3
 *  Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com>
yanmorin's avatar
 
yanmorin committed
4
 *  Author: Yan Morin <yan.morin@savoirfairelinux.com>
5
 *
yanmorin's avatar
 
yanmorin committed
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
yanmorin's avatar
 
yanmorin committed
9
 *  (at your option) any later version.
10
 *
yanmorin's avatar
 
yanmorin committed
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
 *
yanmorin's avatar
 
yanmorin committed
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.
yanmorin's avatar
 
yanmorin committed
30
 */
yanmorin's avatar
 
yanmorin committed
31
#include "iaxvoiplink.h"
Tristan Matthews's avatar
Tristan Matthews committed
32 33 34 35
#include <unistd.h>
#include <cmath>
#include <algorithm>

36 37
#include "iaxcall.h"
#include "eventthread.h"
38
#include "im/instant_messaging.h"
Emmanuel Milou's avatar
Emmanuel Milou committed
39
#include "iaxaccount.h"
40
#include "logger.h"
yanmorin's avatar
yanmorin committed
41
#include "manager.h"
42
#include "hooks/urlhook.h"
43
#include "audio/audiolayer.h"
44
#include "audio/samplerateconverter.h"
45
#include "array_size.h"
46
#include "map_utils.h"
yanmorin's avatar
yanmorin committed
47

48 49
AccountMap IAXVoIPLink::iaxAccountMap_;
IAXCallMap IAXVoIPLink::iaxCallMap_;
50
std::mutex IAXVoIPLink::iaxCallMapMutex_;
51

52
IAXVoIPLink::IAXVoIPLink(const std::string& accountID) :
53
    regSession_(NULL)
54
    , nextRefreshStamp_(0)
55
    , mutexIAX_()
Adrien Béraud's avatar
Adrien Béraud committed
56
    , decData_(DEC_BUFFER_SIZE)
57
    , resampledData_(DEC_BUFFER_SIZE * 4)
58
    , encodedData_()
Rafaël Carré's avatar
Rafaël Carré committed
59
    , converter_(44100)
60
    , initDone_(false)
61
    , accountID_(accountID)
62
    , evThread_(this)
yanmorin's avatar
 
yanmorin committed
63
{
Rafaël Carré's avatar
Rafaël Carré committed
64
    srand(time(NULL));    // to get random number for RANDOM_PORT
yanmorin's avatar
 
yanmorin committed
65
}
yanmorin's avatar
 
yanmorin committed
66 67


yanmorin's avatar
 
yanmorin committed
68 69
IAXVoIPLink::~IAXVoIPLink()
{
70
    handlingEvents_ = false;
Rafaël Carré's avatar
Rafaël Carré committed
71
    regSession_ = NULL; // shall not delete it // XXX: but why?
Emmanuel Milou's avatar
Emmanuel Milou committed
72
    terminate();
73 74 75 76

    // This is our last account
    if (iaxAccountMap_.size() == 1)
        clearIaxCallMap();
yanmorin's avatar
 
yanmorin committed
77
}
yanmorin's avatar
 
yanmorin committed
78

79
void
yanmorin's avatar
 
yanmorin committed
80 81
IAXVoIPLink::init()
{
82
    if (initDone_)
83
        return;
84

Rafaël Carré's avatar
Rafaël Carré committed
85 86
    for (int port = IAX_DEFAULT_PORTNO, nbTry = 0; nbTry < 3 ; port = rand() % 64000 + 1024, nbTry++) {
        if (iax_init(port) >= 0) {
87 88
            handlingEvents_ = true;
            evThread_.start();
89 90
            initDone_ = true;
            break;
Emmanuel Milou's avatar
Emmanuel Milou committed
91 92
        }
    }
yanmorin's avatar
 
yanmorin committed
93
}
yanmorin's avatar
 
yanmorin committed
94

Emmanuel Milou's avatar
Emmanuel Milou committed
95
void
yanmorin's avatar
 
yanmorin committed
96 97
IAXVoIPLink::terminate()
{
98
    if (!initDone_)
Emmanuel Milou's avatar
Emmanuel Milou committed
99
        return;
100

101
    std::lock_guard<std::mutex> lock(iaxCallMapMutex_);
102

103
    for (auto & item : iaxCallMap_) {
104
        IAXCall *call = static_cast<IAXCall*>(item.second);
105

Emmanuel Milou's avatar
Emmanuel Milou committed
106
        if (call) {
107
            std::lock_guard<std::mutex> lock(mutexIAX_);
108
            iax_hangup(call->session, const_cast<char*>("Dumped Call"));
Emmanuel Milou's avatar
Emmanuel Milou committed
109 110 111 112
            delete call;
        }
    }

113
    iaxCallMap_.clear();
Rafaël Carré's avatar
Rafaël Carré committed
114 115

    initDone_ = false;
116 117
}

118
bool
119
IAXVoIPLink::getEvent()
120
{
121 122
    iax_event *event = NULL;

123
    {
124
        std::lock_guard<std::mutex> lock(mutexIAX_);
125 126
        event = iax_get_event(0);
    }
127

128
    while (event != NULL) {
129

130 131
        // If we received an 'ACK', libiax2 tells apps to ignore them.
        if (event->etype == IAX_EVENT_NULL) {
132
            std::lock_guard<std::mutex> lock(mutexIAX_);
133 134 135 136
            iax_event_free(event);
            event = iax_get_event(0);
            continue;
        }
137

138
        IAXCall *call = iaxFindCallBySession(event->session);
139

140 141 142 143 144 145 146 147 148
        if (call) {
            iaxHandleCallEvent(event, call);
        } else if (event->session && event->session == regSession_) {
            // This is a registration session, deal with it
            iaxHandleRegReply(event);
        } else {
            // We've got an event before it's associated with any call
            iaxHandlePrecallEvent(event);
        }
149

150
        {
151
            std::lock_guard<std::mutex> lock(mutexIAX_);
152
            iax_event_free(event);
153
            event = iax_get_event(0);
154
        }
155 156 157
    }

    if (nextRefreshStamp_ && nextRefreshStamp_ < time(NULL))
158
        sendRegister(Manager::instance().getIaxAccount(accountID_));
159

Emmanuel Milou's avatar
Emmanuel Milou committed
160
    sendAudioFromMic();
161

Emmanuel Milou's avatar
Emmanuel Milou committed
162
    // thread wait 3 millisecond
Tristan Matthews's avatar
Tristan Matthews committed
163
    usleep(3000);
164
    return handlingEvents_;
165 166
}

167 168 169 170
std::vector<std::string>
IAXVoIPLink::getCallIDs()
{
    std::vector<std::string> v;
171
    std::lock_guard<std::mutex> lock(iaxCallMapMutex_);
172 173 174 175 176

    map_utils::vectorFromMapKeys(iaxCallMap_, v);
    return v;
}

Emmanuel Milou's avatar
Emmanuel Milou committed
177
void
178
IAXVoIPLink::sendAudioFromMic()
179
{
180
    for (const auto & item : iaxCallMap_) {
181
        IAXCall *currentCall = static_cast<IAXCall*>(item.second);
182

183
        if (!currentCall or currentCall->getState() != Call::ACTIVE)
184
            continue;
185

186 187
        int codecType = currentCall->getAudioCodec();
        sfl::AudioCodec *audioCodec = static_cast<sfl::AudioCodec *>(Manager::instance().audioCodecFactory.getCodec(codecType));
188

189 190
        if (!audioCodec)
            continue;
191

192
        Manager::instance().getMainBuffer().setInternalSamplingRate(audioCodec->getClockRate());
193

194
        unsigned int mainBufferSampleRate = Manager::instance().getMainBuffer().getInternalSamplingRate();
195

196 197
        // we have to get 20ms of data from the mic *20/1000 = /50
        // rate/50 shall be lower than IAX__20S_48KHZ_MAX
Adrien Béraud's avatar
Adrien Béraud committed
198
        size_t samples = mainBufferSampleRate * 20 / 1000;
199

Adrien Béraud's avatar
Adrien Béraud committed
200
        if (Manager::instance().getMainBuffer().availableForGet(currentCall->getCallId()) < samples)
201
            continue;
202

203
        // Get bytes from micRingBuffer to data_from_mic
Adrien Béraud's avatar
Adrien Béraud committed
204
        decData_.resize(samples);
205
        samples = Manager::instance().getMainBuffer().getData(decData_, currentCall->getCallId());
206

207 208 209
        int compSize;
        unsigned int audioRate = audioCodec->getClockRate();
        int outSamples;
Adrien Béraud's avatar
Adrien Béraud committed
210
        AudioBuffer *in;
211 212

        if (audioRate != mainBufferSampleRate) {
Adrien Béraud's avatar
Adrien Béraud committed
213 214
            decData_.setSampleRate(audioRate);
            resampledData_.setSampleRate(mainBufferSampleRate);
215
            converter_.resample(decData_, resampledData_);
Adrien Béraud's avatar
Adrien Béraud committed
216
            in = &resampledData_;
217
            outSamples = 0;
218 219
        } else {
            outSamples = samples;
Adrien Béraud's avatar
Adrien Béraud committed
220
            in = &decData_;
221 222
        }

223
        compSize = audioCodec->encode(encodedData_, in->getData(), DEC_BUFFER_SIZE);
224

Adrien Béraud's avatar
Adrien Béraud committed
225
        if (currentCall->session and samples > 0) {
226
            std::lock_guard<std::mutex> lock(mutexIAX_);
227

228
            if (iax_send_voice(currentCall->session, currentCall->format, encodedData_, compSize, outSamples) == -1)
229
                ERROR("IAX: Error sending voice data.");
230
        }
231
    }
232 233
}

234

Emmanuel Milou's avatar
Emmanuel Milou committed
235
IAXCall*
236
IAXVoIPLink::getIAXCall(const std::string& id)
237
{
238
    return getIaxCall(id);
239 240
}

241
void
242
IAXVoIPLink::sendRegister(Account *a)
243
{
244
    IAXAccount *account = static_cast<IAXAccount*>(a);
245

246
    if (account->getHostname().empty())
247
        throw VoipLinkException("Account hostname is empty");
yanmorin's avatar
yanmorin committed
248

249
    if (account->getUsername().empty())
250
        throw VoipLinkException("Account username is empty");
251

252
    std::lock_guard<std::mutex> lock(mutexIAX_);
253

254 255
    if (regSession_)
        iax_destroy(regSession_);
256

257
    regSession_ = iax_session_new();
Emmanuel Milou's avatar
Emmanuel Milou committed
258

259
    if (regSession_) {
260 261
        iax_register(regSession_, account->getHostname().data(), account->getUsername().data(), account->getPassword().data(), 120);
        nextRefreshStamp_ = time(NULL) + 10;
262
        account->setRegistrationState(TRYING);
Emmanuel Milou's avatar
Emmanuel Milou committed
263
    }
264 265
}

266
void
267
IAXVoIPLink::sendUnregister(Account *a)
268
{
269
    if (regSession_) {
270
        std::lock_guard<std::mutex> lock(mutexIAX_);
271 272 273
        iax_destroy(regSession_);
        regSession_ = NULL;
    }
274

275
    nextRefreshStamp_ = 0;
276

277
    static_cast<IAXAccount*>(a)->setRegistrationState(UNREGISTERED);
278 279
}

Emmanuel Milou's avatar
Emmanuel Milou committed
280
Call*
281
IAXVoIPLink::newOutgoingCall(const std::string& id, const std::string& toUrl, const std::string &account_id)
282
{
283
    IAXCall* call = new IAXCall(id, Call::OUTGOING, account_id);
Emmanuel Milou's avatar
Emmanuel Milou committed
284

285
    call->setPeerNumber(toUrl);
286
    call->initRecFilename(toUrl);
Emmanuel Milou's avatar
Emmanuel Milou committed
287

288
    iaxOutgoingInvite(call);
289 290
    call->setConnectionState(Call::PROGRESSING);
    call->setState(Call::ACTIVE);
291
    addIaxCall(call);
Emmanuel Milou's avatar
Emmanuel Milou committed
292 293

    return call;
294 295
}

296

297
void
298
IAXVoIPLink::answer(Call *call)
299
{
300
    Manager::instance().addStream(call->getCallId());
301

302
    {
303
        std::lock_guard<std::mutex> lock(mutexIAX_);
304 305
        call->answer();
    }
306

307 308
    call->setState(Call::ACTIVE);
    call->setConnectionState(Call::CONNECTED);
309

310
    Manager::instance().getMainBuffer().flushAllBuffers();
311 312
}

313
void
314
IAXVoIPLink::hangup(const std::string& id, int reason UNUSED)
yanmorin's avatar
yanmorin committed
315
{
316
    IAXCall* call = getIAXCall(id);
317

318
    if (call == NULL)
319
        throw VoipLinkException("Could not find call");
320

321
    Manager::instance().getMainBuffer().unBindAll(call->getCallId());
322

323
    {
324
        std::lock_guard<std::mutex> lock(mutexIAX_);
325 326
        iax_hangup(call->session, (char*) "Dumped Call");
    }
327

Rafaël Carré's avatar
Rafaël Carré committed
328
    call->session = NULL;
329

330
    removeIaxCall(id);
331 332 333
}


334
void
335
IAXVoIPLink::peerHungup(const std::string& id)
336
{
337
    IAXCall* call = getIAXCall(id);
338

339
    if (call == NULL)
340
        throw VoipLinkException("Could not find call");
341

342
    Manager::instance().getMainBuffer().unBindAll(call->getCallId());
343

Rafaël Carré's avatar
Rafaël Carré committed
344
    call->session = NULL;
345

346
    removeIaxCall(id);
yanmorin's avatar
yanmorin committed
347
}
348

349 350


351
void
352
IAXVoIPLink::onhold(const std::string& id)
353
{
354 355
    IAXCall* call = getIAXCall(id);

356
    if (call == NULL)
357
        throw VoipLinkException("Call does not exist");
358

359
    Manager::instance().getMainBuffer().unBindAll(call->getCallId());
360

361
    {
362
        std::lock_guard<std::mutex> lock(mutexIAX_);
363 364
        iax_quelch_moh(call->session, true);
    }
365

366
    call->setState(Call::HOLD);
367 368
}

369
void
370
IAXVoIPLink::offhold(const std::string& id)
371
{
372 373
    IAXCall* call = getIAXCall(id);

374
    if (call == NULL)
375
        throw VoipLinkException("Call does not exist");
376

377
    Manager::instance().addStream(call->getCallId());
378

379
    {
380
        std::lock_guard<std::mutex> lock(mutexIAX_);
381 382 383
        iax_unquelch(call->session);
    }

384
    Manager::instance().startAudioDriverStream();
385
    call->setState(Call::ACTIVE);
386 387
}

388
void
389
IAXVoIPLink::transfer(const std::string& id, const std::string& to)
390
{
391 392
    IAXCall* call = getIAXCall(id);

393
    if (!call)
394
        return;
395

396
    char callto[to.length() + 1];
397
    strcpy(callto, to.c_str());
398

399
    {
400
        std::lock_guard<std::mutex> lock(mutexIAX_);
401 402
        iax_transfer(call->session, callto);
    }
403 404
}

405
bool
406
IAXVoIPLink::attendedTransfer(const std::string& /*transferID*/, const std::string& /*targetID*/)
407
{
408
    return false; // TODO
409 410
}

Rafaël Carré's avatar
Rafaël Carré committed
411
void
412
IAXVoIPLink::refuse(const std::string& id)
413
{
414 415
    IAXCall* call = getIAXCall(id);

Rafaël Carré's avatar
Rafaël Carré committed
416
    if (call) {
417
        {
418
            std::lock_guard<std::mutex> lock(mutexIAX_);
419 420
            iax_reject(call->session, (char*) "Call rejected manually.");
        }
421

422
        removeIaxCall(id);
Rafaël Carré's avatar
Rafaël Carré committed
423
    }
424 425
}

alexandresavard's avatar
alexandresavard committed
426

Rafaël Carré's avatar
Rafaël Carré committed
427
void
428
IAXVoIPLink::carryingDTMFdigits(const std::string& id, char code)
429
{
430 431
    IAXCall* call = getIAXCall(id);

Rafaël Carré's avatar
Rafaël Carré committed
432
    if (call) {
433
        std::lock_guard<std::mutex> lock(mutexIAX_);
434
        iax_send_dtmf(call->session, code);
Rafaël Carré's avatar
Rafaël Carré committed
435
    }
436 437
}

438
#if HAVE_INSTANT_MESSAGING
Rafaël Carré's avatar
Rafaël Carré committed
439
void
440
IAXVoIPLink::sendTextMessage(const std::string& callID,
441
                             const std::string& message,
442
                             const std::string& /*from*/)
443
{
444 445
    IAXCall* call = getIAXCall(callID);

Rafaël Carré's avatar
Rafaël Carré committed
446
    if (call) {
447
        std::lock_guard<std::mutex> lock(mutexIAX_);
448
        sfl::InstantMessaging::send_iax_message(call->session, callID, message.c_str());
Rafaël Carré's avatar
Rafaël Carré committed
449
    }
450
}
451
#endif
452

453
void
454
IAXVoIPLink::clearIaxCallMap()
455
{
456
    std::lock_guard<std::mutex> lock(iaxCallMapMutex_);
457

458 459

    for (const auto & item : iaxCallMap_)
460
        delete item.second;
461 462 463 464 465 466

    iaxCallMap_.clear();

}

void
467
IAXVoIPLink::addIaxCall(IAXCall* call)
468
{
469
    if (call and getIaxCall(call->getCallId()) == NULL) {
470
        std::lock_guard<std::mutex> lock(iaxCallMapMutex_);
471 472 473 474 475
        iaxCallMap_[call->getCallId()] = call;
    }
}

void
476
IAXVoIPLink::removeIaxCall(const std::string& id)
477
{
478
    std::lock_guard<std::mutex> lock(iaxCallMapMutex_);
479 480 481 482 483 484 485

    DEBUG("Removing call %s from list", id.c_str());

    delete iaxCallMap_[id];
    iaxCallMap_.erase(id);
}

486 487
IAXCall*
IAXVoIPLink::getIaxCall(const std::string& id)
488
{
489
    IAXCallMap::iterator iter = iaxCallMap_.find(id);
490 491 492 493 494 495 496 497

    if (iter != iaxCallMap_.end())

        return iter->second;
    else
        return NULL;
}

498
std::string
499
IAXVoIPLink::getCurrentVideoCodecName(Call * /*call*/) const
500
{
501
    // FIXME: Video not supported for IAX yet
502 503
    return "";
}
504

Emmanuel Milou's avatar
Emmanuel Milou committed
505
std::string
506
IAXVoIPLink::getCurrentAudioCodecNames(Call *c) const
Alexandre Savard's avatar
Alexandre Savard committed
507
{
508
    IAXCall *call = static_cast<IAXCall*>(c);
509
    sfl::AudioCodec *audioCodec = Manager::instance().audioCodecFactory.getCodec(call->getAudioCodec());
Rafaël Carré's avatar
Rafaël Carré committed
510
    return audioCodec ? audioCodec->getMimeSubtype() : "";
Alexandre Savard's avatar
Alexandre Savard committed
511 512
}

Rafaël Carré's avatar
Rafaël Carré committed
513
void
514
IAXVoIPLink::iaxOutgoingInvite(IAXCall* call)
515
{
516
    std::lock_guard<std::mutex> lock(mutexIAX_);
517

Rafaël Carré's avatar
Rafaël Carré committed
518
    call->session = iax_session_new();
519

520
    IAXAccount *account = Manager::instance().getIaxAccount(accountID_);
521 522
    std::string username(account->getUsername());
    std::string strNum(username + ":" + account->getPassword() + "@" + account->getHostname() + "/" + call->getPeerNumber());
523

Emmanuel Milou's avatar
Emmanuel Milou committed
524
    /** @todo Make preference dynamic, and configurable */
525 526
    int audio_format_preferred = call->getFirstMatchingFormat(call->getSupportedFormat(accountID_), accountID_);
    int audio_format_capability = call->getSupportedFormat(accountID_);
527

Rafaël Carré's avatar
Rafaël Carré committed
528
    iax_call(call->session, username.c_str(), username.c_str(), strNum.c_str(),
529
             NULL, 0, audio_format_preferred, audio_format_capability);
530 531 532
}


Emmanuel Milou's avatar
Emmanuel Milou committed
533
IAXCall*
534
IAXVoIPLink::iaxFindCallBySession(iax_session* session)
535
{
536
    std::lock_guard<std::mutex> lock(iaxCallMapMutex_);
537

538
    for (const auto & item : iaxCallMap_) {
539
        IAXCall* call = static_cast<IAXCall*>(item.second);
540

Rafaël Carré's avatar
Rafaël Carré committed
541
        if (call and call->session == session)
Emmanuel Milou's avatar
Emmanuel Milou committed
542 543
            return call;
    }
544

Rafaël Carré's avatar
Rafaël Carré committed
545
    return NULL;
546 547
}

Emmanuel Milou's avatar
Emmanuel Milou committed
548
void
549
IAXVoIPLink::iaxHandleCallEvent(iax_event* event, IAXCall* call)
550
{
551
    std::string id = call->getCallId();
Emmanuel Milou's avatar
Emmanuel Milou committed
552 553 554

    switch (event->etype) {
        case IAX_EVENT_HANGUP:
555
            Manager::instance().peerHungupCall(id);
Emmanuel Milou's avatar
Emmanuel Milou committed
556

557
            removeIaxCall(id);
Emmanuel Milou's avatar
Emmanuel Milou committed
558 559 560
            break;

        case IAX_EVENT_REJECT:
561 562
            call->setConnectionState(Call::CONNECTED);
            call->setState(Call::ERROR);
563
            Manager::instance().callFailure(id);
564
            removeIaxCall(id);
Emmanuel Milou's avatar
Emmanuel Milou committed
565
            break;
566

Emmanuel Milou's avatar
Emmanuel Milou committed
567
        case IAX_EVENT_ACCEPT:
568

569
            if (event->ies.format)
Rafaël Carré's avatar
Rafaël Carré committed
570
                call->format = event->ies.format;
571

Emmanuel Milou's avatar
Emmanuel Milou committed
572
            break;
573

Emmanuel Milou's avatar
Emmanuel Milou committed
574
        case IAX_EVENT_ANSWER:
575
        case IAX_EVENT_TRANSFER:
576

577
            if (call->getConnectionState() == Call::CONNECTED)
578
                break;
579

580 581
            Manager::instance().addStream(call->getCallId());

582 583
            call->setConnectionState(Call::CONNECTED);
            call->setState(Call::ACTIVE);
584

585
            if (event->ies.format)
Rafaël Carré's avatar
Rafaël Carré committed
586
                call->format = event->ies.format;
587

588
            Manager::instance().peerAnsweredCall(id);
589

590
            Manager::instance().startAudioDriverStream();
591
            Manager::instance().getMainBuffer().flushAllBuffers();
592

Emmanuel Milou's avatar
Emmanuel Milou committed
593
            break;
594

Emmanuel Milou's avatar
Emmanuel Milou committed
595
        case IAX_EVENT_BUSY:
596 597
            call->setConnectionState(Call::CONNECTED);
            call->setState(Call::BUSY);
598
            Manager::instance().callBusy(id);
599
            removeIaxCall(id);
Emmanuel Milou's avatar
Emmanuel Milou committed
600
            break;
601

Emmanuel Milou's avatar
Emmanuel Milou committed
602
        case IAX_EVENT_VOICE:
603
            iaxHandleVoiceEvent(event, call);
Emmanuel Milou's avatar
Emmanuel Milou committed
604
            break;
605

Emmanuel Milou's avatar
Emmanuel Milou committed
606
        case IAX_EVENT_TEXT:
607
#if HAVE_INSTANT_MESSAGING
608
            Manager::instance().incomingMessage(call->getCallId(), call->getPeerNumber(), std::string((const char*) event->data));
609
#endif
Emmanuel Milou's avatar
Emmanuel Milou committed
610
            break;
611