iaxvoiplink.cpp 24.9 KB
Newer Older
yanmorin's avatar
 
yanmorin committed
1
/*
2
3
 *  Copyright (C) 2006-2007 Savoir-Faire Linux inc.
 *  Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com>
yanmorin's avatar
 
yanmorin committed
4
5
6
7
 *  Author: Yan Morin <yan.morin@savoirfairelinux.com>
 *                                                                              
 *  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
10
11
12
13
14
15
16
17
18
19
 *  (at your option) any later version.
 *                                                                                
 *  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.
 *                                                                              
 *  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"
yanmorin's avatar
   
yanmorin committed
21
#include "global.h" // for _debug
22
23
#include "iaxcall.h"
#include "eventthread.h"
yanmorin's avatar
   
yanmorin committed
24

yanmorin's avatar
yanmorin committed
25
#include "manager.h"
26
#include "audio/audiolayer.h"
yanmorin's avatar
yanmorin committed
27

28
#include <samplerate.h>
29
#include <iax/iax-client.h>
30
#include <math.h>
31
#include <dlfcn.h>
32
33
34
35


#define IAX_BLOCKING    1
#define IAX_NONBLOCKING 0
36

yanmorin's avatar
   
yanmorin committed
37
38
#define IAX_SUCCESS  0
#define IAX_FAILURE -1
yanmorin's avatar
 
yanmorin committed
39

40
41
#define RANDOM_IAX_PORT   rand() % 64000 + 1024

42
43
44
#define MUSIC_ONHOLD true
#define NO_MUSIC_ONHOLD	false

45
46
// from IAXC : iaxclient.h

Alexandre Bourget's avatar
Alexandre Bourget committed
47
48
#define IAX__20S_8KHZ_MAX   320 //320 samples, IAX packets can have more than 20ms.
#define IAX__20S_48KHZ_MAX  1920 // 320*6 samples = 1920, 6 = 48000/8000 
49

50
51
52
53
54
#define CHK_VALID_CALL   if (call == NULL) { _debug("IAX: Call doesn't exists\n"); \
                                             return false; }



yanmorin's avatar
   
yanmorin committed
55
IAXVoIPLink::IAXVoIPLink(const AccountID& accountID)
56
  : VoIPLink(accountID)
yanmorin's avatar
 
yanmorin committed
57
{
58
  _evThread = new EventThread(this);
59
  _regSession = NULL;
60
  _nextRefreshStamp = 0;
61
62
63

  // to get random number for RANDOM_PORT
  srand (time(NULL));
64

65
  audiolayer = NULL;
66
67
68
69
70
71
72
73
74

  _receiveDataDecoded = new int16[IAX__20S_48KHZ_MAX];
  _sendDataEncoded   =  new unsigned char[IAX__20S_8KHZ_MAX];

  // we estimate that the number of format after a conversion 8000->48000 is expanded to 6 times
  _dataAudioLayer = new SFLDataFormat[IAX__20S_48KHZ_MAX];
  _floatBuffer8000  = new float32[IAX__20S_8KHZ_MAX];
  _floatBuffer48000 = new float32[IAX__20S_48KHZ_MAX];
  _intBuffer8000  = new int16[IAX__20S_8KHZ_MAX];
75
76
77
78
79

  // libsamplerate-related
  _src_state_mic  = src_new(SRC_SINC_BEST_QUALITY, 1, &_src_err);
  _src_state_spkr = src_new(SRC_SINC_BEST_QUALITY, 1, &_src_err);

yanmorin's avatar
   
yanmorin committed
80
}
yanmorin's avatar
 
yanmorin committed
81
82


yanmorin's avatar
   
yanmorin committed
83
84
IAXVoIPLink::~IAXVoIPLink()
{
85
86
  delete _evThread; _evThread = NULL;
  _regSession = NULL; // shall not delete it
87
  terminate();
88

89
90
91
92
93
  audiolayer = NULL;
  delete [] _intBuffer8000; _intBuffer8000 = NULL;
  delete [] _floatBuffer48000; _floatBuffer48000 = NULL;
  delete [] _floatBuffer8000; _floatBuffer8000 = NULL;
  delete [] _dataAudioLayer; _dataAudioLayer = NULL;
94

95
96
  delete [] _sendDataEncoded; _sendDataEncoded = NULL;
  delete [] _receiveDataDecoded; _receiveDataDecoded = NULL;
97
98
99
100

  // libsamplerate-related
  _src_state_mic  = src_delete(_src_state_mic);
  _src_state_spkr = src_delete(_src_state_spkr);
yanmorin's avatar
   
yanmorin committed
101
}
yanmorin's avatar
 
yanmorin committed
102

yanmorin's avatar
   
yanmorin committed
103
104
105
bool
IAXVoIPLink::init()
{
106
107
108
109
  // If it was done, don't do it again, until we call terminate()
  if (_initDone)
    return false;

yanmorin's avatar
   
yanmorin committed
110
111
112
  bool returnValue = false;
  //_localAddress = "127.0.0.1";
  // port 0 is default
yanmorin's avatar
   
yanmorin committed
113
  //  iax_enable_debug(); have to enable debug when compiling iax...
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
  int port = IAX_DEFAULT_PORTNO;
  int last_port = 0;
  int nbTry = 3;

  while (port != IAX_FAILURE && nbTry) {
    last_port = port;
    port = iax_init(port);
    if ( port < 0 ) {
      _debug("IAX Warning: already initialize on port %d\n", last_port);
      port = RANDOM_IAX_PORT;
    } else if (port == IAX_FAILURE) {
      _debug("IAX Fail to start on port %d", last_port);
      port = RANDOM_IAX_PORT;
    } else {
      _debug("IAX Info: listening on port %d\n", last_port);
      _localPort = last_port;
      returnValue = true;
      _evThread->start();
132
133

      audiolayer = Manager::instance().getAudioDriver();
134
135
136
      break;
    }
    nbTry--;
137
138

    _initDone = true;
139
140
141
  }
  if (port == IAX_FAILURE || nbTry==0) {
    _debug("Fail to initialize iax\n");
142
143
    
    _initDone = false;
yanmorin's avatar
   
yanmorin committed
144
  }
145
146
  

yanmorin's avatar
   
yanmorin committed
147
148
  return returnValue;
}
yanmorin's avatar
 
yanmorin committed
149

yanmorin's avatar
   
yanmorin committed
150
151
152
void
IAXVoIPLink::terminate()
{
153
154
155
156
157
158
159
160
161
162
  // If it was done, don't do it again, until we call init()
  if (!_initDone)
    return;

  // iaxc_shutdown();  

  // Hangup all calls
  terminateIAXCall();

  _initDone = false;
yanmorin's avatar
   
yanmorin committed
163
}
164

165
166
167
168
169
170
171
172
173
174
void
IAXVoIPLink::terminateIAXCall()
{
  ost::MutexLock m(_callMapMutex);
  CallMap::iterator iter = _callMap.begin();
  IAXCall *call;
  while( iter != _callMap.end() ) {
    call = dynamic_cast<IAXCall*>(iter->second);
    if (call) {
      _mutexIAX.enterMutex();
175
      iax_hangup(call->getSession(), "Dumped Call");
176
      _mutexIAX.leaveMutex();
177
178
      call->setSession(NULL);
      delete call; call = NULL;
179
180
181
182
183
184
    }
    iter++;
  }
  _callMap.clear();
}

185
186
187
void
IAXVoIPLink::getEvent() 
{
188
  IAXCall* call = NULL;
189

190
191
  // lock iax_ stuff..
  _mutexIAX.enterMutex();
192
  iax_event* event = NULL;
193
194
195
196
197
198
  while ( (event = iax_get_event(IAX_NONBLOCKING)) != NULL ) {
    // If we received an 'ACK', libiax2 tells apps to ignore them.
    if (event->etype == IAX_EVENT_NULL) {
      continue;
    }

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

201
    call = iaxFindCallBySession(event->session);
202
203

    if (call) {
204
      // We know that call, deal with it
205
      iaxHandleCallEvent(event, call);
Emmanuel Milou's avatar
Emmanuel Milou committed
206
      //_audiocodec = Manager::instance().getCodecDescriptorMap().getCodec( call -> getAudioCodec() ); 
207
208
209
    }
    else if (event->session && event->session == _regSession) {
      // This is a registration session, deal with it
210
      iaxHandleRegReply(event);
211
212
213
    }
    else {
      // We've got an event before it's associated with any call
214
      iaxHandlePrecallEvent(event);
215
    }
216
    
yanmorin's avatar
yanmorin committed
217
    iax_event_free(event);
218
  }
219
220
  _mutexIAX.leaveMutex();

221
222
223
224
225
226
227

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


  // Refresh registration.
  if (_nextRefreshStamp && _nextRefreshStamp - 2 < time(NULL)) {
228
    sendRegister();
229
230
  }

231
  // thread wait 3 millisecond
232
  _evThread->sleep(3);
233
234
}

235
236
237
void
IAXVoIPLink::sendAudioFromMic(void)
{
Emmanuel Milou's avatar
Emmanuel Milou committed
238
  IAXCall* currentCall = getIAXCall(Manager::instance().getCurrentCallId());
239

240
241
242
243
  if (!currentCall) {
    // Let's mind our own business.
    return;
  }
Emmanuel Milou's avatar
Emmanuel Milou committed
244
245
246
247
  
  if( currentCall -> getAudioCodec() < 0 )
    return;

248
249

  // Just make sure the currentCall is in state to receive audio right now.
250
251
252
253
254
255
  //_debug("Here we get: connectionState: %d   state: %d \n",
  // currentCall->getConnectionState(),
  // currentCall->getState());

  if (currentCall->getConnectionState() != Call::Connected ||
      currentCall->getState() != Call::Active) {
256
257
258
    return;
  }

Emmanuel Milou's avatar
Emmanuel Milou committed
259
260
  AudioCodec* ac = currentCall -> getCodecMap().getCodec( currentCall -> getAudioCodec() );
  if (!ac) {
261
262
263
    // Audio codec still not determined.
    if (audiolayer) {
      // To keep latency low..
264
      //audiolayer->flushMic();
265
266
267
    }
    return;
  }
Emmanuel Milou's avatar
Emmanuel Milou committed
268
  
269
  // Send sound here
270
  if (audiolayer) {
271
272
273
274

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

276
277
    // available bytes inside ringbuffer
    int availBytesFromMic = audiolayer->canGetMic();
278

279
280
281
282
283
    if (availBytesFromMic < maxBytesToGet) {
      // We need packets full!
      return;
    }

284
285
    // take the lowest
    int bytesAvail = (availBytesFromMic < maxBytesToGet) ? availBytesFromMic : maxBytesToGet;
Alexandre Bourget's avatar
Pouet    
Alexandre Bourget committed
286
    //_debug("available = %d, maxBytesToGet = %d\n", availBytesFromMic, maxBytesToGet);
287
288
289
    
    // Get bytes from micRingBuffer to data_from_mic
    int nbSample = audiolayer->getMic(_dataAudioLayer, bytesAvail) / sizeof(SFLDataFormat);
290
291

    // Audio ici est PARFAIT
292
    int16* toIAX = NULL;
293
    //if (audiolayer->getSampleRate() != audiocodec->getClockRate() && nbSample) {
Emmanuel Milou's avatar
Emmanuel Milou committed
294
    if (audiolayer->getSampleRate() != ac ->getClockRate() && nbSample) {
295
296
297
298
299
300
301
302
      SRC_DATA src_data;
#ifdef DATAFORMAT_IS_FLOAT   
      src_data.data_in = _dataAudioLayer;
#else
      src_short_to_float_array(_dataAudioLayer, _floatBuffer48000, nbSample);
      src_data.data_in = _floatBuffer48000; 
#endif
      
303
      // Audio parfait à ce point.
Emmanuel Milou's avatar
Emmanuel Milou committed
304
      double factord = (double) ac->getClockRate() / audiolayer->getSampleRate();
305
306
307
308
309
      
      src_data.src_ratio = factord;
      src_data.input_frames = nbSample;
      src_data.output_frames = (int) floor(factord * nbSample);
      src_data.data_out = _floatBuffer8000;
310
      src_data.end_of_input = 0; 
311
312
313
314
      
      src_process(_src_state_mic, &src_data);
      
      nbSample = src_data.output_frames_gen;
315
316

      // Bon, l'audio en float 8000 est laid mais yé consistant.
317
318
      src_float_to_short_array (_floatBuffer8000, _intBuffer8000, nbSample);
      toIAX = _intBuffer8000;
319
320

      // Audio bon ici aussi..
321
322
323
324
325
326
327
328
329
330
331
332
    } else {
#ifdef DATAFORMAT_IS_FLOAT
      // convert _receiveDataDecoded to float inside _receiveData
      src_float_to_short_array(_dataAudioLayer, _intBuffer8000, nbSample);
      toIAX = _intBuffer8000;
      //if (nbSample > IAX__20S_8KHZ_MAX) { _debug("Alert from mic, nbSample %d is bigger than expected %d\n", nbSample, IAX__20S_8KHZ_MAX); }
#else
      toIAX = _dataAudioLayer; // int to int
#endif
    }

    // for the mono: range = 0 to IAX_FRAME2SEND * sizeof(int16)
Emmanuel Milou's avatar
Emmanuel Milou committed
333
    int compSize = ac->codecEncode(_sendDataEncoded, toIAX, nbSample*sizeof(int16));
334

335
336
337
    // Send it out!
    _mutexIAX.enterMutex();
    // Make sure the session and the call still exists.
338
339
    if (currentCall->getSession()) {
      if ( iax_send_voice(currentCall->getSession(), currentCall->getFormat(), (unsigned char*)_sendDataEncoded, compSize, nbSample) == -1) {
340
341
342
343
	_debug("IAX: Error sending voice data.\n");
      }
    }
    _mutexIAX.leaveMutex();
yanmorin's avatar
yanmorin committed
344
  }
345
346
}

347
348
349
350
351
352
353
354

IAXCall* 
IAXVoIPLink::getIAXCall(const CallID& id) 
{
  Call* call = getCall(id);
  if (call) {
    return dynamic_cast<IAXCall*>(call);
  }
355
  return NULL;
356
357
358
359
}



360
bool
361
IAXVoIPLink::sendRegister() 
362
{
yanmorin's avatar
yanmorin committed
363
  bool result = false;
yanmorin's avatar
yanmorin committed
364

365
366
367
368
369
370
371
372
  if (_host.empty()) {
    Manager::instance().displayConfigError("Fill host field for IAX Account");
    return false;
  }
  if (_user.empty()) {
    Manager::instance().displayConfigError("Fill user field for IAX Account");
    return false;
  }
yanmorin's avatar
yanmorin committed
373

374
375
  // lock
  _mutexIAX.enterMutex();
yanmorin's avatar
yanmorin committed
376

377
378
379
  // Always use a brand new session
  if (_regSession) {
    iax_destroy(_regSession);
yanmorin's avatar
yanmorin committed
380
  }
381
382
383

  _regSession = iax_session_new();

384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
  if (!_regSession) {
    _debug("Error when generating new session for register");
  } else {
    // refresh
    // last reg
    char host[_host.length()+1]; 
    strcpy(host, _host.c_str());
    char user[_user.length()+1];
    strcpy(user, _user.c_str());
    char pass[_pass.length()+1]; 
    strcpy(pass, _pass.c_str());
    // iax_register doesn't use const char*

    _debug("IAX Sending registration to %s with user %s\n", host, user);
    int val = iax_register(_regSession, host, user, pass, 120);
    _debug ("Return value: %d\n", val);
    // set the time-out to 15 seconds, after that, resend a registration request.
    // until we unregister.
    _nextRefreshStamp = time(NULL) + 10;
    result = true;
404
405

    setRegistrationState(Trying);
406
407
408
409
410
  }

  // unlock
  _mutexIAX.leaveMutex();

yanmorin's avatar
yanmorin committed
411
  return result;
412
413
}

414
415
416



417
bool
418
IAXVoIPLink::sendUnregister()
419
{
420
  _mutexIAX.enterMutex();
421
  if (_regSession) {
422
    /** @todo Should send a REGREL in sendUnregister()... */
423
424

    //iax_send_regrel(); doesn't exist yet :)
425
    iax_destroy(_regSession);
426
427

    _regSession = NULL;
428
  }
429
430
  _mutexIAX.leaveMutex();

431
  _nextRefreshStamp = 0;
432
433
434

  setRegistrationState(Unregistered);

435
436
437
  return false;
}

438
439
440
441
Call* 
IAXVoIPLink::newOutgoingCall(const CallID& id, const std::string& toUrl)
{
  IAXCall* call = new IAXCall(id, Call::Outgoing);
442
443
  call->setCodecMap(Manager::instance().getCodecDescriptorMap());

444

445
446
  if (call) {
    call->setPeerNumber(toUrl);
447

448
449
450
451
452
    if ( iaxOutgoingInvite(call) ) {
      call->setConnectionState(Call::Progressing);
      call->setState(Call::Active);
      addCall(call);
    } else {
453
      delete call; call = NULL;
454
455
456
457
458
    }
  }
  return call;
}

459

460
bool 
461
IAXVoIPLink::answer(const CallID& id)
462
463
{
  IAXCall* call = getIAXCall(id);
Emmanuel Milou's avatar
Emmanuel Milou committed
464
  call->setCodecMap(Manager::instance().getCodecDescriptorMap());
465
466
467
  
  CHK_VALID_CALL;

468
469
470
  _mutexIAX.enterMutex();
  iax_answer(call->getSession());
  _mutexIAX.leaveMutex();
471

472
473
  call->setState(Call::Active);
  call->setConnectionState(Call::Connected);
474
475
  // Start audio
  audiolayer->startStream();
476
  //audiolayer->flushMic();
477

478
479
480
  return true;
}

yanmorin's avatar
yanmorin committed
481
482
483
bool 
IAXVoIPLink::hangup(const CallID& id)
{
484
485
486
487
488
489
490
491
492
493
494
495
496
  IAXCall* call = getIAXCall(id);

  CHK_VALID_CALL;

  _mutexIAX.enterMutex();
  iax_hangup(call->getSession(), "Dumped Call");
  _mutexIAX.leaveMutex();
  call->setSession(NULL);
  if (Manager::instance().isCurrentCall(id)) {
    // stop audio
  }
  removeCall(id);
  return true;	
yanmorin's avatar
yanmorin committed
497
}
498
499
500
501
502

bool 
IAXVoIPLink::onhold(const CallID& id) 
{
  IAXCall* call = getIAXCall(id);
503
504
505

  CHK_VALID_CALL;

506
  //if (call->getState() == Call::Hold) { _debug("Call is already on hold\n"); return false; }
507
  
508
  _mutexIAX.enterMutex();
509
  iax_quelch_moh(call->getSession() , MUSIC_ONHOLD);
510
  _mutexIAX.leaveMutex();
511

512
513
514
515
516
517
518
519
  call->setState(Call::Hold);
  return true;
}

bool 
IAXVoIPLink::offhold(const CallID& id)
{
  IAXCall* call = getIAXCall(id);
520
521
522

  CHK_VALID_CALL;

523
524
525
526
  //if (call->getState() == Call::Active) { _debug("Call is already active\n"); return false; }
  _mutexIAX.enterMutex();
  iax_unquelch(call->getSession());
  _mutexIAX.leaveMutex();
527
  audiolayer->startStream();
528
529
530
531
  call->setState(Call::Active);
  return true;
}

532
533
534
535
bool 
IAXVoIPLink::transfer(const CallID& id, const std::string& to)
{
  IAXCall* call = getIAXCall(id);
536
537

  CHK_VALID_CALL;
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553

  char callto[to.length()+1];
  strcpy(callto, to.c_str());
  
  _mutexIAX.enterMutex();
  iax_transfer(call->getSession(), callto); 
  _mutexIAX.leaveMutex();

  // should we remove it?
  // removeCall(id);
}

bool 
IAXVoIPLink::refuse(const CallID& id)
{
  IAXCall* call = getIAXCall(id);
554
555
556

  CHK_VALID_CALL;

557
558
559
560
561
562
563
564
565
566
  _mutexIAX.enterMutex();
  iax_reject(call->getSession(), "Call rejected manually.");
  _mutexIAX.leaveMutex();
  removeCall(id);
}

bool
IAXVoIPLink::carryingDTMFdigits(const CallID& id, char code)
{
  IAXCall* call = getIAXCall(id);
567
568
569

  CHK_VALID_CALL;

570
571
572
573
574
  _mutexIAX.enterMutex();
  iax_send_dtmf(call->getSession(), code);
  _mutexIAX.leaveMutex();
}

575
576


577
578
579
580
bool
IAXVoIPLink::iaxOutgoingInvite(IAXCall* call) 
{
  struct iax_session *newsession;
581
582
  ost::MutexLock m(_mutexIAX);

583
584
585
586
587
588
589
590
  newsession = iax_session_new();
  if (!newsession) {
     _debug("IAX Error: Can't make new session for a new call\n");
     return false;
  }
  call->setSession(newsession);
  /* reset activity and ping "timers" */
  // iaxc_note_activity(callNo);
yanmorin's avatar
yanmorin committed
591
  
592
  std::string strNum = _user + ":" + _pass + "@" + _host + "/" + call->getPeerNumber();  
yanmorin's avatar
yanmorin committed
593
594
595
596
597
598

  char user[_user.length()+1];
  strcpy(user, _user.c_str());
  
  char num[strNum.length()+1];
  strcpy(num, strNum.c_str());
599
600
601

  char* lang = NULL;
  int wait = 0;
602
603
604
  /** @todo Make preference dynamic, and configurable */
  int audio_format_preferred =  call->getFirstMatchingFormat(call->getSupportedFormat());
  int audio_format_capability = call->getSupportedFormat();
605

606
  _debug("IAX New call: %s\n", num);
yanmorin's avatar
yanmorin committed
607
  iax_call(newsession, user, user, num, lang, wait, audio_format_preferred, audio_format_capability);
608
609
610
611
612

  return true;
}


613
614
615
616
617
618
IAXCall* 
IAXVoIPLink::iaxFindCallBySession(struct iax_session* session) 
{
  // access to callMap shoud use that
  // the code below is like findSIPCallWithCid() 
  ost::MutexLock m(_callMapMutex);	
619
  IAXCall* call = NULL;
620
621
622
623
624
625
626
627
  CallMap::iterator iter = _callMap.begin();
  while(iter != _callMap.end()) {
    call = dynamic_cast<IAXCall*>(iter->second);
    if (call && call->getSession() == session) {
      return call;
    }
    iter++;
  }
628
  return NULL; // not found
629
630
631
632
633
}

void
IAXVoIPLink::iaxHandleCallEvent(iax_event* event, IAXCall* call) 
{
yanmorin's avatar
yanmorin committed
634
635
636
  // call should not be 0
  // note activity?
  //
yanmorin's avatar
yanmorin committed
637
  CallID id = call->getCallId();
638
  int16* output = 0; // for audio output
639
  
yanmorin's avatar
yanmorin committed
640
  switch(event->etype) {
641
642
643
644
645
646
647
648
649
650
  case IAX_EVENT_HANGUP:
    Manager::instance().peerHungupCall(id); 
    if (Manager::instance().isCurrentCall(id)) {
      audiolayer->stopStream();
      // stop audio
    }
    removeCall(id);
    break;
    
  case IAX_EVENT_REJECT:
651
    //Manager::instance().peerHungupCall(id); 
652
653
654
655
    if (Manager::instance().isCurrentCall(id)) {
      // stop audio
      audiolayer->stopStream();
    }
656
657
658
659
    call->setConnectionState(Call::Connected);
    call->setState(Call::Error);
    Manager::instance().displayErrorText(id, "Failure");
    Manager::instance().callFailure(id);
660
    removeCall(id);
yanmorin's avatar
yanmorin committed
661
662
    break;

663
  case IAX_EVENT_ACCEPT:
664
    // Call accepted over there by the computer, not the user yet.
665
    if (event->ies.format) {
666
      call->setFormat(event->ies.format);
667
    }
yanmorin's avatar
yanmorin committed
668
669
    break;
    
670
671
  case IAX_EVENT_ANSWER:
    if (call->getConnectionState() != Call::Connected){
yanmorin's avatar
yanmorin committed
672
      call->setConnectionState(Call::Connected);
673
674
675
676
677
678
679
680
      call->setState(Call::Active);

      if (event->ies.format) {
	// Should not get here, should have been set in EVENT_ACCEPT
	call->setFormat(event->ies.format);
      }
      
      Manager::instance().peerAnsweredCall(id);
681
      //audiolayer->flushMic();
682
683
684
      audiolayer->startStream();
      // start audio here?
    } else {
685
      // deja connecté ?
686
687
688
689
690
691
692
693
694
    }
    break;
    
  case IAX_EVENT_BUSY:
    call->setConnectionState(Call::Connected);
    call->setState(Call::Busy);
    Manager::instance().displayErrorText(id, "Busy");
    Manager::instance().callBusy(id);
    removeCall(id);
yanmorin's avatar
yanmorin committed
695
696
    break;
    
697
  case IAX_EVENT_VOICE:
698
699
700
    //_debug("Should have a decent value!!!!!! = %i\n" , call -> getAudioCodec());
    if( !audiolayer -> isCaptureActive())
      audiolayer->startStream();
701
702
703
704
705
706
707
    iaxHandleVoiceEvent(event, call);
    break;
    
  case IAX_EVENT_TEXT:
    break;
    
  case IAX_EVENT_RINGA:
708
709
    call->setConnectionState(Call::Ringing);
    Manager::instance().peerRingingCall(call->getCallId());
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
    break;
    
  case IAX_EVENT_PONG:
    break;
    
  case IAX_EVENT_URL:
    break;
    
    //    case IAX_EVENT_CNG: ??
    //    break;
    
  case IAX_EVENT_TIMEOUT:
    break;
    
  case IAX_EVENT_TRANSFER:
    break;
    
  default:
728
    _debug("Unknown event type (in call event): %d\n", event->etype);
729
730
731
732
733
734
735
736
    
  }
}


/* Handle audio event, VOICE packet received */
void
IAXVoIPLink::iaxHandleVoiceEvent(iax_event* event, IAXCall* call)
737
{ 
738
739
740
741
742
743
744
    // If we receive datalen == 0, some things of the jitter buffer in libiax2/iax.c
    // were triggered
    if (!event->datalen) {
      // Skip this empty packet.
      //_debug("IAX: Skipping empty jitter-buffer interpolated packet\n");
      return;
    }
745

746
    if (audiolayer) {
Emmanuel Milou's avatar
Emmanuel Milou committed
747
748
749
  //    _debug("codec = %i\n" , call->getFormat());
   //   _debug("codec = %i\n" , _audiocodec->getPayload());
      //_debug("codec = %s\n" , _audiocodec->getCodecName().c_str());
750
751
752
753
754
      // 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()) {
	call->setFormat(event->subclass);
755
      }
756
      //_debug("Receive: len=%d, format=%d, _receiveDataDecoded=%p\n", event->datalen, call->getFormat(), _receiveDataDecoded);
Emmanuel Milou's avatar
Emmanuel Milou committed
757
758
      AudioCodec* ac = call->getCodecMap().getCodec( call -> getAudioCodec() );

759
760
761
762
763
764
765
766
      unsigned char* data = (unsigned char*)event->data;
      unsigned int size   = event->datalen;

      if (size > IAX__20S_8KHZ_MAX) {
	_debug("The size %d is bigger than expected %d. Packet cropped. Ouch!\n", size, IAX__20S_8KHZ_MAX);
	size = IAX__20S_8KHZ_MAX;
      }

Emmanuel Milou's avatar
Emmanuel Milou committed
767
      int expandedSize = ac->codecDecode(_receiveDataDecoded, data, size);
768
769
770
      int nbInt16      = expandedSize/sizeof(int16);

      if (nbInt16 > IAX__20S_8KHZ_MAX) {
771
	_debug("We have decoded an IAX VOICE packet larger than expected: %s VS %s. Cropping.\n", nbInt16, IAX__20S_8KHZ_MAX);
772
773
774
775
776
777
778
	nbInt16 = IAX__20S_8KHZ_MAX;
      }
      
      SFLDataFormat* toAudioLayer;
      int nbSample = nbInt16;
      int nbSampleMaxRate = nbInt16 * 6;
      
Emmanuel Milou's avatar
Emmanuel Milou committed
779
      if ( audiolayer->getSampleRate() != ac->getClockRate() && nbSample ) {
780
	// Do sample rate conversion
Emmanuel Milou's avatar
Emmanuel Milou committed
781
	double factord = (double) audiolayer->getSampleRate() / ac->getClockRate();
782
783
784
785
786
787
788
	// SRC_DATA from samplerate.h
	SRC_DATA src_data;
	src_data.data_in = _floatBuffer8000;
	src_data.data_out = _floatBuffer48000;
	src_data.input_frames = nbSample;
	src_data.output_frames = (int) floor(factord * nbSample);
	src_data.src_ratio = factord;
789
	src_data.end_of_input = 0;
790
791
792
793
794
795
796
797
798
799
800
801
	src_short_to_float_array(_receiveDataDecoded, _floatBuffer8000, nbSample);

	// samplerate convert, go!
	src_process(_src_state_spkr, &src_data);
	
	nbSample = ( src_data.output_frames_gen > IAX__20S_48KHZ_MAX) ? IAX__20S_48KHZ_MAX : src_data.output_frames_gen;
#ifdef DATAFORMAT_IS_FLOAT
	toAudioLayer = _floatBuffer48000;
#else
	src_float_to_short_array(_floatBuffer48000, _dataAudioLayer, nbSample);
	toAudioLayer = _dataAudioLayer;
#endif
802
  	
803
804
805
806
807
808
809
810
811
      } else {
	nbSample = nbInt16;
#ifdef DATAFORMAT_IS_FLOAT
	// convert _receiveDataDecoded to float inside _receiveData
	src_short_to_float_array(_receiveDataDecoded, _floatBuffer8000, nbSample);
	toAudioLayer = _floatBuffer8000;
#else
	toAudioLayer = _receiveDataDecoded; // int to int
#endif
812
      }
Emmanuel Milou's avatar
Emmanuel Milou committed
813
      audiolayer->playSamples(toAudioLayer, nbSample * sizeof(SFLDataFormat), true);
814
815
816
    } else {
      _debug("IAX: incoming audio, but no sound card open");
    }
817

yanmorin's avatar
yanmorin committed
818
819
}

820

821
822
823
/**
 * Handle the registration process
 */
yanmorin's avatar
yanmorin committed
824
825
826
void
IAXVoIPLink::iaxHandleRegReply(iax_event* event) 
{
827
  if (event->etype == IAX_EVENT_REGREJ) {
828
    /* Authentication failed! */
829
    _mutexIAX.enterMutex();
830
    iax_destroy(_regSession);
831
    _mutexIAX.leaveMutex();
832
    _regSession = NULL;
833

834
835
836
    setRegistrationState(Error, "Registration failed");
    //Manager::instance().registrationFailed(getAccountID());

837
838
839
  }
  else if (event->etype == IAX_EVENT_REGACK) {
    /* Authentication succeeded */
840
841
842
843
844
845
846
847
848
    _mutexIAX.enterMutex();
    iax_destroy(_regSession);
    _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.
    _nextRefreshStamp = time(NULL) + (event->ies.refresh ? event->ies.refresh : 60);

849
850
    setRegistrationState(Registered);
    //Manager::instance().registrationSucceed(getAccountID());
851
  }
852
}
yanmorin's avatar
yanmorin committed
853

854
855
856
857


void
IAXVoIPLink::iaxHandlePrecallEvent(iax_event* event)
yanmorin's avatar
yanmorin committed
858
{
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
  IAXCall* call = NULL;
  CallID   id;

  switch(event->etype) {
  case IAX_EVENT_REGACK:
  case IAX_EVENT_REGREJ:
    _debug("IAX Registration Event in a pre-call setup\n");
    break;
    
  case IAX_EVENT_REGREQ:
    // Received when someone wants to register to us!?!
    // Asterisk receives and answers to that, not us, we're a phone.
    _debug("Registration by a peer, don't allow it\n");
    break;
    
  case IAX_EVENT_CONNECT:
    // We've got an incoming call! Yikes!
    _debug("> IAX_EVENT_CONNECT (receive)\n");

    id = Manager::instance().getNewCallID();

Emmanuel Milou's avatar
Emmanuel Milou committed
880

881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
    call = new IAXCall(id, Call::Incoming);

    if (!call) {
      _debug("! IAX Failure: unable to create an incoming call");
      return;
    }

    // Setup the new IAXCall
    // Associate the call to the session.
    call->setSession(event->session);

    // setCallAudioLocal(call);
    call->setCodecMap(Manager::instance().getCodecDescriptorMap());
    call->setConnectionState(Call::Progressing);

896

897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
    if (event->ies.calling_number)
      call->setPeerNumber(std::string(event->ies.calling_number));
    if (event->ies.calling_name)
      call->setPeerName(std::string(event->ies.calling_name));

    if (Manager::instance().incomingCall(call, getAccountID())) {
      /** @todo Faudra considérer éventuellement le champ CODEC PREFS pour
       * l'établissement du codec de transmission */

      // Remote lists its capabilities
      int format = call->getFirstMatchingFormat(event->ies.capability);
      // Remote asks for preferred codec voiceformat
      int pref_format = call->getFirstMatchingFormat(event->ies.format);

      // Priority to remote's suggestion. In case it's a forwarding, no transcoding
      // will be needed from the server, thus less latency.
      if (pref_format)
	format = pref_format;

      iax_accept(event->session, format);
      iax_ring_announce(event->session);

      addCall(call);
    } else {
      // reject call, unable to add it
      iax_reject(event->session, "Error ringing user.");

      delete call; call = NULL;
    }

    break;
    
  case IAX_EVENT_HANGUP:
    // Remote peer hung up
    call = iaxFindCallBySession(event->session);
    id = call->getCallId();

    Manager::instance().peerHungupCall(id);
    removeCall(id);
    break;
    
  case IAX_EVENT_TIMEOUT: // timeout for an unknown session
    
    break;
    
  default:
943
    _debug("Unknown event type (in precall): %d\n", event->etype);
yanmorin's avatar
yanmorin committed
944
  }
945
  
yanmorin's avatar
yanmorin committed
946
}
947

948
949
950
951
952
953
954
955
956
int 
IAXVoIPLink::iaxCodecMapToFormat(IAXCall* call)
{
  CodecOrder map = call->getCodecMap().getActiveCodecs();
  printf("taytciatcia = %i\n", map.size());
  return 0;
}