iaxvoiplink.cpp 28.6 KB
Newer Older
1
/*
2 3
 *  Copyright (C) 2006-2007 Savoir-Faire Linux inc.
 *  Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com>
4
 *  Author: Yan Morin <yan.morin@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 18 19
 *  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.
 */
yanmorin's avatar
yanmorin committed
20
#include "iaxvoiplink.h"
21 22
#include "iaxcall.h"
#include "eventthread.h"
23
#include "iaxaccount.h"
yanmorin's avatar
yanmorin committed
24
#include "manager.h"
25
#include "audio/audiolayer.h"
yanmorin's avatar
yanmorin committed
26

27
#include <math.h>
28
#include <dlfcn.h>
29 30 31

#define IAX_BLOCKING    1
#define IAX_NONBLOCKING 0
32

yanmorin's avatar
yanmorin committed
33 34
#define IAX_SUCCESS  0
#define IAX_FAILURE -1
35

36 37
#define RANDOM_IAX_PORT   rand() % 64000 + 1024

38
#define MUSIC_ONHOLD true
39

40
#define CHK_VALID_CALL   if (call == NULL) { _debug("IAX: Call doesn't exists\n"); \
41
    return false; }
42

43 44
IAXVoIPLink::IAXVoIPLink (const AccountID& accountID)
        : VoIPLink (accountID)
45
{
46
    // _debug("IAXVoIPLink::IAXVoIPLink : creating eventhread \n ");
47
    _evThread = new EventThread (this);
48 49
    _regSession = NULL;
    _nextRefreshStamp = 0;
50

51
    // to get random number for RANDOM_PORT
52
    srand (time (NULL));
53

54
    audiolayer = NULL;
55

56
    converter = new SamplerateConverter();
57

58
    int nbSamplesMax = (int) (converter->getFrequence() * converter->getFramesize() / 1000);
59

60 61 62
    micData = new SFLDataFormat[nbSamplesMax];
    micDataConverted = new SFLDataFormat[nbSamplesMax];
    micDataEncoded = new unsigned char[nbSamplesMax];
63

64 65
    spkrDataConverted = new SFLDataFormat[nbSamplesMax];
    spkrDataDecoded = new SFLDataFormat[nbSamplesMax];
66 67

    urlhook = new UrlHook ();
yanmorin's avatar
yanmorin committed
68
}
69 70


yanmorin's avatar
yanmorin committed
71 72
IAXVoIPLink::~IAXVoIPLink()
{
73 74
    delete _evThread;
    _evThread = NULL;
75 76
    _regSession = NULL; // shall not delete it
    terminate();
77

78
    audiolayer = NULL;
79

80 81
    delete converter;

82 83 84 85 86 87 88 89 90 91 92
    delete [] micData;
    micData = NULL;
    delete [] micDataConverted;
    micDataConverted = NULL;
    delete [] micDataEncoded;
    micDataEncoded = NULL;

    delete [] spkrDataDecoded;
    spkrDataDecoded = NULL;
    delete [] spkrDataConverted;
    spkrDataConverted = NULL;
yanmorin's avatar
yanmorin committed
93
}
94

95
bool
yanmorin's avatar
yanmorin committed
96 97
IAXVoIPLink::init()
{
98 99 100
    // If it was done, don't do it again, until we call terminate()
    if (initDone())
        return false;
101

102
    bool returnValue = false;
103

104
    // _localAddress = "127.0.0.1";
105 106 107
    // port 0 is default
    //  iax_enable_debug(); have to enable debug when compiling iax...
    int port = IAX_DEFAULT_PORTNO;
108

109
    int last_port = 0;
110

111 112 113 114
    int nbTry = 3;

    while (port != IAX_FAILURE && nbTry) {
        last_port = port;
115 116 117 118
        port = iax_init (port);

        if (port < 0) {
            _debug ("IAX Warning: already initialize on port %d\n", last_port);
119 120
            port = RANDOM_IAX_PORT;
        } else if (port == IAX_FAILURE) {
121
            _debug ("IAX Fail to start on port %d", last_port);
122 123
            port = RANDOM_IAX_PORT;
        } else {
124
            _debug ("IAX Info: listening on port %d\n", last_port);
125 126 127 128 129 130 131
            _localPort = last_port;
            returnValue = true;
            _evThread->start();

            audiolayer = Manager::instance().getAudioDriver();
            break;
        }
132

133 134
        nbTry--;

135
        initDone (true);
136
    }
137

138
    if (port == IAX_FAILURE || nbTry==0) {
139
        _debug ("Fail to initialize iax\n");
140

141
        initDone (false);
142
    }
143

144
    return returnValue;
yanmorin's avatar
yanmorin committed
145
}
146

147
void
yanmorin's avatar
yanmorin committed
148 149
IAXVoIPLink::terminate()
{
150 151 152
    // If it was done, don't do it again, until we call init()
    if (!initDone())
        return;
153

154
    // iaxc_shutdown();
155

156 157
    // Hangup all calls
    terminateIAXCall();
158

159
    initDone (false);
yanmorin's avatar
yanmorin committed
160
}
161

162
void
163 164
IAXVoIPLink::terminateIAXCall()
{
165
    std::string reason = "Dumped Call";
166
    ost::MutexLock m (_callMapMutex);
167 168
    CallMap::iterator iter = _callMap.begin();
    IAXCall *call;
169 170 171 172

    while (iter != _callMap.end()) {
        call = dynamic_cast<IAXCall*> (iter->second);

173 174
        if (call) {
            _mutexIAX.enterMutex();
175
            iax_hangup (call->getSession(), (char*) reason.c_str());
176
            _mutexIAX.leaveMutex();
177 178 179
            call->setSession (NULL);
            delete call;
            call = NULL;
180
        }
181

182
        iter++;
183
    }
184

185
    _callMap.clear();
186 187
}

188
void IAXVoIPLink::terminateOneCall (const CallID& id)
189
{
190 191 192 193 194 195
    IAXCall* call = getIAXCall (id);

    if (call) {
        _debug ("IAXVoIPLink::terminateOneCall()::the call is deleted, should close recording file \n");
        delete call;
        call = 0;
196 197 198 199 200
    }
}



201 202
void
IAXVoIPLink::getEvent()
203
{
204
    IAXCall* call = NULL;
Emmanuel Milou's avatar
Emmanuel Milou committed
205

206 207 208 209
    // lock iax_ stuff..
    _mutexIAX.enterMutex();
    iax_event* event = NULL;

210
    while ( (event = iax_get_event (IAX_NONBLOCKING)) != NULL) {
211 212 213 214 215 216 217
        // If we received an 'ACK', libiax2 tells apps to ignore them.
        if (event->etype == IAX_EVENT_NULL) {
            continue;
        }

        //_debug ("Receive IAX Event: %d (0x%x)\n", event->etype, event->etype);

218
        call = iaxFindCallBySession (event->session);
219 220 221

        if (call) {
            // We know that call, deal with it
222 223 224
            iaxHandleCallEvent (event, call);
            //_audiocodec = Manager::instance().getCodecDescriptorMap().getCodec( call -> getAudioCodec() );
        } else if (event->session && event->session == _regSession) {
225
            // This is a registration session, deal with it
226 227
            iaxHandleRegReply (event);
        } else {
228
            // We've got an event before it's associated with any call
229
            iaxHandlePrecallEvent (event);
230 231
        }

232 233
        // _debug("IAXVoIPLink::getEvent() : timestamp %i \n",event->ts);

234
        iax_event_free (event);
235
    }
236

237
    _mutexIAX.leaveMutex();
238

239 240 241

    if (call) {
        call->recAudio.recData (spkrDataConverted,micData,nbSampleForRec_,nbSampleForRec_);
Alexandre Savard's avatar
Alexandre Savard committed
242 243
    }

244 245
    // Do the doodle-moodle to send audio from the microphone to the IAX channel.
    sendAudioFromMic();
246

247
    // Refresh registration.
248 249
    if (_nextRefreshStamp && _nextRefreshStamp - 2 < time (NULL)) {
        sendRegister ("");
250
    }
251

252 253 254
    // reinitialize speaker buffer for recording (when recording a voice mail)
    for (int i = 0; i < nbSampleForRec_; i++)
        spkrDataConverted[i] = 0;
255

256

257
    // thread wait 3 millisecond
258 259 260
    _evThread->sleep (3);

    free (event);
261 262
}

263 264
void
IAXVoIPLink::sendAudioFromMic (void)
265
{
Alexandre Savard's avatar
Alexandre Savard committed
266 267
    // _debug("IAXVoIPLink::sendAudioFromMic");

268
    int maxBytesToGet, availBytesFromMic, bytesAvail, compSize;
269
    AudioCodec *ac;
270
    IAXCall *currentCall;
271

Emmanuel Milou's avatar
Emmanuel Milou committed
272 273 274 275
    // We have to update the audio layer type in case we switched
    // TODO Find out a better way to do it
    updateAudiolayer();

276
    currentCall = getIAXCall (Manager::instance().getCurrentCallId());
277

278 279 280 281
    if (!currentCall) {
        // Let's mind our own business.
        return;
    }
Emmanuel Milou's avatar
Emmanuel Milou committed
282

283
    if (currentCall -> getAudioCodec() < 0)
284
        return;
285

286 287 288 289
    // Just make sure the currentCall is in state to receive audio right now.
    //_debug("Here we get: connectionState: %d   state: %d \n",
    //currentCall->getConnectionState(),
    //currentCall->getState());
290

291 292 293 294
    if (currentCall->getConnectionState() != Call::Connected ||
            currentCall->getState() != Call::Active) {
        return;
    }
295

296 297
    ac = currentCall->getCodecMap().getCodec (currentCall -> getAudioCodec());

298 299 300 301
    if (!ac) {
        // Audio codec still not determined.
        if (audiolayer) {
            // To keep latency low..
Emmanuel Milou's avatar
Emmanuel Milou committed
302
            audiolayer->flushMic();
303
        }
304

305
        return;
306
    }
307

308 309
    // Send sound here
    if (audiolayer) {
310

311 312
        // we have to get 20ms of data from the mic *20/1000 = /50
        // rate/50 shall be lower than IAX__20S_48KHZ_MAX
313
        maxBytesToGet = audiolayer->getSampleRate() * audiolayer->getFrameSize() / 1000 * sizeof (SFLDataFormat);
314

315 316
        // available bytes inside ringbuffer
        availBytesFromMic = audiolayer->canGetMic();
317

318 319 320 321
        if (availBytesFromMic < maxBytesToGet) {
            // We need packets full!
            return;
        }
322

323 324
        // take the lowest
        bytesAvail = (availBytesFromMic < maxBytesToGet) ? availBytesFromMic : maxBytesToGet;
325

326
        //_debug("available = %d, maxBytesToGet = %d\n", availBytesFromMic, maxBytesToGet);
327

328
        // Get bytes from micRingBuffer to data_from_mic
329 330
        nbSample_ = audiolayer->getMic (micData, bytesAvail) / sizeof (SFLDataFormat);

alexandresavard's avatar
alexandresavard committed
331
        // Store the number of samples for recording
332 333 334
        nbSampleForRec_ = nbSample_;

        // _debug("IAXVoIPLink::sendAudioFromMic : %i \n",nbSampleForRec_);
335

336
        // resample
337
        nbSample_ = converter->downsampleData (micData , micDataConverted , (int) ac ->getClockRate() , (int) audiolayer->getSampleRate() , nbSample_);
338

339
        // for the mono: range = 0 to IAX_FRAME2SEND * sizeof(int16)
340
        compSize = ac->codecEncode (micDataEncoded, micDataConverted , nbSample_*sizeof (int16));
341 342 343

        // Send it out!
        _mutexIAX.enterMutex();
344

345
        // Make sure the session and the call still exists.
346
        if (currentCall->getSession() && micDataEncoded != NULL) {
347 348
            if (iax_send_voice (currentCall->getSession(), currentCall->getFormat(), micDataEncoded, compSize, nbSample_) == -1) {
                _debug ("IAX: Error sending voice data.\n");
349 350
            }
        }
351

352
        _mutexIAX.leaveMutex();
353
    }
354 355
}

356

357 358
IAXCall*
IAXVoIPLink::getIAXCall (const CallID& id)
359
{
360 361
    Call* call = getCall (id);

362
    if (call) {
363
        return dynamic_cast<IAXCall*> (call);
364
    }
365

366
    return NULL;
367 368 369
}


370 371
int
IAXVoIPLink::sendRegister (AccountID id)
372
{
373 374
    IAXAccount *account;
    bool result;
yanmorin's avatar
yanmorin committed
375

376
    result = false;
377
    account = dynamic_cast<IAXAccount *> (getAccountPtr());
378

379
    if (account->getHostname().empty()) {
380 381
        return false;
    }
382

383
    if (account->getUsername().empty()) {
384 385
        return false;
    }
yanmorin's avatar
yanmorin committed
386

387 388
    // lock
    _mutexIAX.enterMutex();
389

390 391
    // Always use a brand new session
    if (_regSession) {
392
        iax_destroy (_regSession);
393
    }
394

395
    _regSession = iax_session_new();
396

397
    if (!_regSession) {
398
        _debug ("Error when generating new session for register");
399
    } else {
400 401
        _debug ("IAX Sending registration to %s with user %s\n", account->getHostname().c_str() , account->getUsername().c_str());
        int val = iax_register (_regSession, account->getHostname().data(), account->getUsername().data(), account->getPassword().data(), 120);
402 403 404
        _debug ("Return value: %d\n", val);
        // set the time-out to 15 seconds, after that, resend a registration request.
        // until we unregister.
405
        _nextRefreshStamp = time (NULL) + 10;
406 407
        result = true;

408
        account->setRegistrationState (Trying);
409
    }
410

411 412
    // unlock
    _mutexIAX.leaveMutex();
413

414
    return result;
415 416
}

417 418
int
IAXVoIPLink::sendUnregister (AccountID id)
419
{
420
    IAXAccount *account;
421

422 423 424
    account = dynamic_cast<IAXAccount*> (getAccountPtr());

    if (!account)
425
        return 1;
426

427
    _mutexIAX.enterMutex();
428

429 430 431
    if (_regSession) {
        /** @todo Should send a REGREL in sendUnregister()... */
        //iax_send_regrel(); doesn't exist yet :)
432
        iax_destroy (_regSession);
433 434
        _regSession = NULL;
    }
435

436
    _mutexIAX.leaveMutex();
437

438
    _nextRefreshStamp = 0;
439

440 441
    _debug ("IAX2 send unregister\n");
    account->setRegistrationState (Unregistered);
442

443
    return SUCCESS;
444 445
}

446 447
Call*
IAXVoIPLink::newOutgoingCall (const CallID& id, const std::string& toUrl)
448
{
449 450
    IAXCall* call = new IAXCall (id, Call::Outgoing);
    call->setCodecMap (Manager::instance().getCodecDescriptorMap());
451

452
    if (call) {
453
        call->setPeerNumber (toUrl);
454
        call->initRecFileName();
455 456 457 458 459

        if (iaxOutgoingInvite (call)) {
            call->setConnectionState (Call::Progressing);
            call->setState (Call::Active);
            addCall (call);
460
        } else {
461 462
            delete call;
            call = NULL;
463
        }
464
    }
465

466
    return call;
467 468
}

469

470 471
bool
IAXVoIPLink::answer (const CallID& id)
472
{
473 474
    IAXCall* call = getIAXCall (id);
    call->setCodecMap (Manager::instance().getCodecDescriptorMap());
475

476
    CHK_VALID_CALL;
477

478
    _mutexIAX.enterMutex();
479
    iax_answer (call->getSession());
480
    _mutexIAX.leaveMutex();
481

482 483
    call->setState (Call::Active);
    call->setConnectionState (Call::Connected);
484 485
    // Start audio
    audiolayer->startStream();
486

487
    return true;
488 489
}

490 491
bool
IAXVoIPLink::hangup (const CallID& id)
yanmorin's avatar
yanmorin committed
492
{
493 494
    _debug ("IAXVoIPLink::hangup() : function called once hangup \n");
    IAXCall* call = getIAXCall (id);
495 496 497
    std::string reason = "Dumped Call";
    CHK_VALID_CALL;
    _mutexIAX.enterMutex();
498 499

    iax_hangup (call->getSession(), (char*) reason.c_str());
500
    _mutexIAX.leaveMutex();
501 502 503
    call->setSession (NULL);

    if (Manager::instance().isCurrentCall (id)) {
504 505 506
        // stop audio
        audiolayer->stopStream();
    }
507 508 509 510 511

    terminateOneCall (id);

    removeCall (id);
    return true;
512 513 514
}


515 516
bool
IAXVoIPLink::peerHungup (const CallID& id)
517
{
518 519
    _debug ("IAXVoIPLink::peerHangup() : function called once hangup \n");
    IAXCall* call = getIAXCall (id);
520 521 522
    std::string reason = "Dumped Call";
    CHK_VALID_CALL;
    _mutexIAX.enterMutex();
523

524
    _mutexIAX.leaveMutex();
525 526 527
    call->setSession (NULL);

    if (Manager::instance().isCurrentCall (id)) {
528 529 530
        // stop audio
        audiolayer->stopStream();
    }
531 532 533 534 535

    terminateOneCall (id);

    removeCall (id);
    return true;
yanmorin's avatar
yanmorin committed
536
}
537

538 539


540 541
bool
IAXVoIPLink::onhold (const CallID& id)
542
{
543
    IAXCall* call = getIAXCall (id);
544

545
    CHK_VALID_CALL;
546

547
    //if (call->getState() == Call::Hold) { _debug("Call is already on hold\n"); return false; }
548

549
    _mutexIAX.enterMutex();
550
    iax_quelch_moh (call->getSession() , MUSIC_ONHOLD);
551
    _mutexIAX.leaveMutex();
552

553
    call->setState (Call::Hold);
554
    return true;
555 556
}

557 558
bool
IAXVoIPLink::offhold (const CallID& id)
559
{
560
    IAXCall* call = getIAXCall (id);
561

562
    CHK_VALID_CALL;
563

564 565
    //if (call->getState() == Call::Active) { _debug("Call is already active\n"); return false; }
    _mutexIAX.enterMutex();
566
    iax_unquelch (call->getSession());
567 568
    _mutexIAX.leaveMutex();
    audiolayer->startStream();
569
    call->setState (Call::Active);
570
    return true;
571 572
}

573 574
bool
IAXVoIPLink::transfer (const CallID& id, const std::string& to)
575
{
576
    IAXCall* call = getIAXCall (id);
577

578
    CHK_VALID_CALL;
579

580 581
    char callto[to.length() +1];
    strcpy (callto, to.c_str());
582

583
    _mutexIAX.enterMutex();
584
    iax_transfer (call->getSession(), callto);
585
    _mutexIAX.leaveMutex();
586

587
    return true;
588

589 590
    // should we remove it?
    // removeCall(id);
591 592
}

593 594
bool
IAXVoIPLink::refuse (const CallID& id)
595
{
596
    IAXCall* call = getIAXCall (id);
597
    std::string reason = "Call rejected manually.";
598

599
    CHK_VALID_CALL;
600

601
    _mutexIAX.enterMutex();
602
    iax_reject (call->getSession(), (char*) reason.c_str());
603
    _mutexIAX.leaveMutex();
604

605 606

    // terminateOneCall(id);
607
    removeCall (id);
608

609
    return true;
610 611
}

612

613 614
void
IAXVoIPLink::setRecording (const CallID& id)
615
{
616
    _debug ("IAXVoIPLink::setRecording()!");
617

618
    IAXCall* call = getIAXCall (id);
619

620
    call->setRecording();
621 622
}

623 624
bool
IAXVoIPLink::isRecording (const CallID& id)
625
{
626
    _debug ("IAXVoIPLink::setRecording()!");
627

628
    IAXCall* call = getIAXCall (id);
629

630
    return call->isRecording();
631 632 633
}


634 635


636 637
bool
IAXVoIPLink::carryingDTMFdigits (const CallID& id, char code)
638
{
639
    IAXCall* call = getIAXCall (id);
640

641
    CHK_VALID_CALL;
642

643
    _mutexIAX.enterMutex();
644
    iax_send_dtmf (call->getSession(), code);
645
    _mutexIAX.leaveMutex();
646

647
    return true;
648 649
}

650

651
std::string
Alexandre Savard's avatar
Alexandre Savard committed
652 653
IAXVoIPLink::getCurrentCodecName()
{
654 655 656 657
    IAXCall *call = getIAXCall (Manager::instance().getCurrentCallId());

    AudioCodec *ac = call->getCodecMap().getCodec (call->getAudioCodec());

Alexandre Savard's avatar
Alexandre Savard committed
658 659 660
    return ac->getCodecName();
}

661

662 663
bool
IAXVoIPLink::iaxOutgoingInvite (IAXCall* call)
664
{
665

666
    struct iax_session *newsession;
667
    ost::MutexLock m (_mutexIAX);
668 669 670 671
    std::string username, strNum;
    char *lang=NULL;
    int wait, audio_format_preferred, audio_format_capability;
    IAXAccount *account;
yanmorin's avatar
yanmorin committed
672

673
    newsession = iax_session_new();
674

675
    if (!newsession) {
676
        _debug ("IAX Error: Can't make new session for a new call\n");
677 678
        return false;
    }
679 680

    call->setSession (newsession);
681

682 683
    account = dynamic_cast<IAXAccount*> (getAccountPtr());
    username = account->getUsername();
684
    strNum = username + ":" + account->getPassword() + "@" + account->getHostname() + "/" + call->getPeerNumber();
685

686 687
    wait = 0;
    /** @todo Make preference dynamic, and configurable */
688
    audio_format_preferred =  call->getFirstMatchingFormat (call->getSupportedFormat());
689
    audio_format_capability = call->getSupportedFormat();
690

691 692
    _debug ("IAX New call: %s\n", strNum.c_str());
    iax_call (newsession, username.c_str(), username.c_str(), strNum.c_str(), lang, wait, audio_format_preferred, audio_format_capability);
693

694
    return true;
695 696 697
}


698 699
IAXCall*
IAXVoIPLink::iaxFindCallBySession (struct iax_session* session)
700
{
701
    // access to callMap shoud use that
702 703
    // the code below is like findSIPCallWithCid()
    ost::MutexLock m (_callMapMutex);
704 705
    IAXCall* call = NULL;
    CallMap::iterator iter = _callMap.begin();
706 707 708 709

    while (iter != _callMap.end()) {
        call = dynamic_cast<IAXCall*> (iter->second);

710 711 712
        if (call && call->getSession() == session) {
            return call;
        }
713

714
        iter++;
715
    }
716

717
    return NULL; // not found
718 719
}

720 721
void
IAXVoIPLink::iaxHandleCallEvent (iax_event* event, IAXCall* call)
722
{
723 724 725 726 727
    // call should not be 0
    // note activity?
    //
    CallID id = call->getCallId();

728 729
    switch (event->etype) {

730
        case IAX_EVENT_HANGUP:
731 732

            if (Manager::instance().isCurrentCall (id)) {
733 734 735
                // stop audio
                audiolayer->stopStream();
            }
736 737 738

            Manager::instance().peerHungupCall (id);

739
            /*
740
            _debug("IAXVoIPLink::iaxHandleCallEvent, peer hangup have been called");
741 742 743 744 745 746 747
            std::string reason = "Dumped Call";
            _mutexIAX.enterMutex();
            iax_hangup(call->getSession(), (char*)reason.c_str());
            _mutexIAX.leaveMutex();
            call->setSession(NULL);
            audiolayer->stopStream();
            terminateOneCall(id);
748 749
            */
            removeCall (id);
750 751 752
            break;

        case IAX_EVENT_REJECT:
753 754 755
            //Manager::instance().peerHungupCall(id);

            if (Manager::instance().isCurrentCall (id)) {
756 757 758
                // stop audio
                audiolayer->stopStream();
            }
759 760 761 762 763

            call->setConnectionState (Call::Connected);

            call->setState (Call::Error);
            Manager::instance().callFailure (id);
764
            // terminateOneCall(id);
765
            removeCall (id);
766 767 768 769
            break;

        case IAX_EVENT_ACCEPT:
            // Call accepted over there by the computer, not the user yet.
770

771
            if (event->ies.format) {
772
                call->setFormat (event->ies.format);
773
            }
774

775 776 777
            break;

        case IAX_EVENT_ANSWER:
778 779 780 781

            if (call->getConnectionState() != Call::Connected) {
                call->setConnectionState (Call::Connected);
                call->setState (Call::Active);
782
                audiolayer->startStream();
783 784 785

                if (event->ies.format) {
                    // Should not get here, should have been set in EVENT_ACCEPT
786
                    call->setFormat (event->ies.format);
787 788
                }

789 790
                Manager::instance().peerAnsweredCall (id);

791 792 793 794
                // start audio here?
            } else {
                // deja connecté ?
            }
795

796 797 798
            break;

        case IAX_EVENT_BUSY:
799 800 801
            call->setConnectionState (Call::Connected);
            call->setState (Call::Busy);
            Manager::instance().callBusy (id);
802
            // terminateOneCall(id);
803
            removeCall (id);
804 805 806
            break;

        case IAX_EVENT_VOICE:
Emmanuel Milou's avatar
Emmanuel Milou committed
807
            //if (!audiolayer->isCaptureActive ())
808
            //  audiolayer->startStream ();
Alexandre Savard's avatar
Alexandre Savard committed
809
            // _debug("IAX_EVENT_VOICE: \n");
810
            iaxHandleVoiceEvent (event, call);
811 812 813 814 815 816
            break;

        case IAX_EVENT_TEXT:
            break;

        case IAX_EVENT_RINGA:
817 818
            call->setConnectionState (Call::Ringing);
            Manager::instance().peerRingingCall (call->getCallId());
819 820
            break;

821
        case IAX_IE_MSGCOUNT:
822
            break;
823

824 825 826 827
        case IAX_EVENT_PONG:
            break;

        case IAX_EVENT_URL:
828

829
            if (Manager::instance().getConfigString (HOOKS, URLHOOK_IAX2_ENABLED) == "1") {
830
                if (strcmp ( (char*) event->data, "") != 0) {
831
                    _debug ("> IAX_EVENT_URL received: %s\n", event->data);
832
                    urlhook->addAction ( (char*) event->data, Manager::instance().getConfigString (HOOKS, URLHOOK_COMMAND));
833 834
                }
            }
835

836 837 838 839 840 841 842 843 844
            break;

        case IAX_EVENT_TIMEOUT:
            break;

        case IAX_EVENT_TRANSFER:
            break;

        default:
845
            _debug ("Unknown event type (in call event): %d\n", event->etype);
846 847

    }
848 849 850 851
}


/* Handle audio event, VOICE packet received */
852 853 854
void
IAXVoIPLink::iaxHandleVoiceEvent (iax_event* event, IAXCall* call)
{
855 856 857

    unsigned char *data;
    unsigned int size, max, nbInt16;
858
    int expandedSize, nbSample_;
859 860
    AudioCodec *ac;

861 862
    // If we receive datalen == 0, some things of the jitter buffer in libiax2/iax.c
    // were triggered
863

864 865 866 867
    if (!event->datalen) {
        // Skip this empty packet.
        //_debug("IAX: Skipping empty jitter-buffer interpolated packet\n");
        return;
868
    }
869

870 871 872 873 874
    if (audiolayer) {
        // On-the-fly codec changing (normally, when we receive a full packet)
        // as per http://tools.ietf.org/id/draft-guy-iax-03.txt
        // - subclass holds the voiceformat property.
        if (event->subclass && event->subclass != call->getFormat()) {
875
            call->setFormat (event->subclass);
876
        }
877

878
        //_debug("Receive: len=%d, format=%d, _receiveDataDecoded=%p\n", event->datalen, call->getFormat(), _receiveDataDecoded);
879 880 881
        ac = call->getCodecMap().getCodec (call -> getAudioCodec());

        data = (unsigned char*) event->data;
Emmanuel Milou's avatar
Emmanuel Milou committed
882

883
        size   = event->datalen;
884

885
        // Decode data with relevant codec
886
        max = (int) (ac->getClockRate() * audiolayer->getFrameSize() / 1000);
887

888
        if (size > max) {
889
            _debug ("The size %d is bigger than expected %d. Packet cropped. Ouch!\n", size, max);
890 891
            size = max;
        }
892

893 894 895
        expandedSize = ac->codecDecode (spkrDataDecoded , data , size);

        nbInt16      = expandedSize/sizeof (int16);
896

897
        if (nbInt16 > max) {
898
            _debug ("We have decoded an IAX VOICE packet larger than expected: %i VS %i. Cropping.\n", nbInt16, max);
899 900
            nbInt16 = max;
        }
901

902
        nbSample_ = nbInt16;
903

904
        // resample
905
        nbInt16 = converter->upsampleData (spkrDataDecoded , spkrDataConverted , ac->getClockRate() , audiolayer->getSampleRate() , nbSample_);
906

907
        /* Write the data to the mic ring buffer */
908
        audiolayer->putMain (spkrDataConverted , nbInt16 * sizeof (SFLDataFormat));
909 910

    } else {
911
        _debug ("IAX: incoming audio, but no sound card open");
912
    }
913

yanmorin's avatar
yanmorin committed
914 915
}

916 917 918
/**
 * Handle the registration process
 */
919 920
void
IAXVoIPLink::iaxHandleRegReply (iax_event* event)
yanmorin's avatar
yanmorin committed
921
{
922

923
    std::string account_id;
924
    IAXAccount *account;
925

926
    account_id = getAccountID();
927
    account = dynamic_cast<IAXAccount *> (Manager::instance().getAccount (account_id));
928

929 930 931
    if (event->etype == IAX_EVENT_REGREJ) {
        /* Authentication failed! */
        _mutexIAX.enterMutex();
932
        iax_destroy (_regSession);
933 934
        _mutexIAX.leaveMutex();
        _regSession = NULL;
935
        // Update the account registration state
936
        account->setRegistrationState (ErrorAuth);
937
    }
938

939 940 941 942 943
    else if (event->etype == IAX_EVENT_REGACK) {
        /* Authentication succeeded */
        _mutexIAX.enterMutex();

        // Looking for the voicemail information
944
        //if( event->ies != 0 )
945 946
        //new_voicemails = processIAXMsgCount(event->ies.msgcount);
        //_debug("iax voicemail number notification: %i\n", new_voicemails);
947
        // Notify the client if new voicemail waiting for the current account
948 949
        //account_id = getAccountID();
        //Manager::instance().startVoiceMessageNotification(account_id.c_str(), new_voicemails);
950

951
        iax_destroy (_regSession);
952 953 954 955 956
        _mutexIAX.leaveMutex();
        _regSession = NULL;

        // I mean, save the timestamp, so that we re-register again in the REFRESH time.
        // Defaults to 60, as per draft-guy-iax-03.
957 958
        _nextRefreshStamp = time (NULL) + (event->ies.refresh ? event->ies.refresh : 60);
        account->setRegistrationState (Registered);
959
    }
960
}
yanmorin's avatar
yanmorin committed
961

962
int IAXVoIPLink::processIAXMsgCount (int msgcount)
963
{
964

965 966 967 968 969 970 971 972 973 974
    // IAX sends the message count under a specific format:
    //                       1
    //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
    //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //  |      0x18     |      0x02     |
    //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //  |  Old messages |  New messages |
    //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

    // For now we just need the new messages informations.
975
    // Thus: