audiortp.cpp 15.6 KB
Newer Older
jpbl's avatar
jpbl committed
1
/*
2
 *  Copyright (C) 2004-2008 Savoir-Faire Linux inc.
3
 *  Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
4
 *  Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com>
jpbl's avatar
jpbl committed
5
6
7
8
9
 *  Author: Yan Morin <yan.morin@savoirfairelinux.com>
 *  Author: Laurielle Lea <laurielle.lea@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
10
 *  the Free Software Foundation; either version 3 of the License, or
jpbl's avatar
jpbl committed
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 *  (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.
 */

#include <cstdio>
#include <cstdlib>
#include <ccrtp/rtp.h>
#include <assert.h>
#include <string>
28
#include <cstring>
29
#include <math.h>
30
31
#include <dlfcn.h>
#include <iostream>
32
#include <sstream>
jpbl's avatar
jpbl committed
33
34
35
36
37
38
39
40
41
42
43
44
45

#include "../global.h"
#include "../manager.h"
#include "codecDescriptor.h"
#include "audiortp.h"
#include "audiolayer.h"
#include "ringbuffer.h"
#include "../user_cfg.h"
#include "../sipcall.h"

////////////////////////////////////////////////////////////////////////////////
// AudioRtp                                                          
////////////////////////////////////////////////////////////////////////////////
Yun Liu's avatar
Yun Liu committed
46
AudioRtp::AudioRtp() :_RTXThread(0), _symmetric(), _threadMutex()
jpbl's avatar
jpbl committed
47
48
49
50
{
}

AudioRtp::~AudioRtp (void) {
51
  delete _RTXThread; _RTXThread = 0;
jpbl's avatar
jpbl committed
52
53
54
}

int 
yanmorin's avatar
   
yanmorin committed
55
AudioRtp::createNewSession (SIPCall *ca) {
alexandresavard's avatar
alexandresavard committed
56
   
57
    ost::MutexLock m(_threadMutex);
58

59
60
61
62
63
64
65
    // something should stop the thread before...
    if ( _RTXThread != 0 ) { 
        _debug("**********************************************************\n");
        _debug("! ARTP Failure: Thread already exists..., stopping it\n");
        _debug("**********************************************************\n");
        delete _RTXThread; _RTXThread = 0;
    }
66
67
68
69
70
71

  // Start RTP Send/Receive threads
  _symmetric = Manager::instance().getConfigInt(SIGNALISATION,SYMMETRIC) ? true : false;
  _RTXThread = new AudioRtpRTX (ca, _symmetric);
  try {
    if (_RTXThread->start() != 0) {
Emmanuel Milou's avatar
Emmanuel Milou committed
72
     _debug("! ARTP Failure: unable to start RTX Thread\n");
73
74
75
76
77
78
      return -1;
    }
  } catch(...) {
    _debugException("! ARTP Failure: when trying to start a thread");
    throw;
  }
alexandresavard's avatar
alexandresavard committed
79

80
  return 0;
jpbl's avatar
jpbl committed
81
82
}

83

jpbl's avatar
jpbl committed
84
85
void
AudioRtp::closeRtpSession () {
86

87
  ost::MutexLock m(_threadMutex);
88
  // This will make RTP threads finish.
89
  _debug("Stopping AudioRTP\n");
90
  try {
alexandresavard's avatar
alexandresavard committed
91
    
92
93
94
95
96
    delete _RTXThread; _RTXThread = 0;
  } catch(...) {
    _debugException("! ARTP Exception: when stopping audiortp\n");
    throw;
  }
Emmanuel Milou's avatar
Emmanuel Milou committed
97
98
  AudioLayer* audiolayer = Manager::instance().getAudioDriver();
  audiolayer->stopStream();
jpbl's avatar
jpbl committed
99
100
}

alexandresavard's avatar
alexandresavard committed
101
102
103
104

void
AudioRtp::setRecording() {
  
105
  _debug("AudioRtp::setRecording\n");
106
  _RTXThread->_ca->setRecording();
107

alexandresavard's avatar
alexandresavard committed
108
109
110
111
}



jpbl's avatar
jpbl committed
112
113
114
////////////////////////////////////////////////////////////////////////////////
// AudioRtpRTX Class                                                          //
////////////////////////////////////////////////////////////////////////////////
Yun Liu's avatar
Yun Liu committed
115
116
117
AudioRtpRTX::AudioRtpRTX (SIPCall *sipcall, bool sym) : time(new ost::Time()), _ca(sipcall), _sessionSend(NULL), _sessionRecv(NULL), _session(NULL), _start(), 
		               _sym(sym), micData(NULL), micDataConverted(NULL), micDataEncoded(NULL), spkrDataDecoded(NULL), spkrDataConverted(NULL), 
		               converter(NULL), _layerSampleRate(),_codecSampleRate(), _layerFrameSize(), _audiocodec(NULL)
118
{
119
  setCancel(cancelDefault);
120
121
122
123
124
125
126
127
128
129
130
131
132
133
  // AudioRtpRTX should be close if we change sample rate
  // TODO: Change bind address according to user settings.
  // TODO: this should be the local ip not the external (router) IP
  std::string localipConfig = _ca->getLocalIp(); // _ca->getLocalIp();
  ost::InetHostAddress local_ip(localipConfig.c_str());
  if (!_sym) {
    _sessionRecv = new ost::RTPSession(local_ip, _ca->getLocalAudioPort());
    _sessionSend = new ost::RTPSession(local_ip, _ca->getLocalAudioPort());
    _session = NULL;
  } else {
    _session = new ost::SymmetricRTPSession (local_ip, _ca->getLocalAudioPort());
    _sessionRecv = NULL;
    _sessionSend = NULL;
  }
134
  
jpbl's avatar
jpbl committed
135
136
137
}

AudioRtpRTX::~AudioRtpRTX () {
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
  _start.wait();

  try {
    this->terminate();
  } catch(...) {
    _debugException("! ARTP: Thread destructor didn't terminate correctly");
    throw;
  }
  _ca = 0;
  if (!_sym) {
    delete _sessionRecv; _sessionRecv = NULL;
    delete _sessionSend; _sessionSend = NULL;
  } else {
    delete _session;     _session = NULL;
  }
alexandresavard's avatar
alexandresavard committed
153
 
154
155
156
  delete [] micData;  micData = NULL;
  delete [] micDataConverted;  micDataConverted = NULL;
  delete [] micDataEncoded;  micDataEncoded = NULL;
157

158
159
  delete [] spkrDataDecoded; spkrDataDecoded = NULL;
  delete [] spkrDataConverted; spkrDataConverted = NULL;
160
161

  delete time; time = NULL;
162
163

  delete converter; converter = NULL;
164
  
jpbl's avatar
jpbl committed
165
166
}

167
  void
168
AudioRtpRTX::initBuffers()
jpbl's avatar
jpbl committed
169
{
170
  converter = new SamplerateConverter( _layerSampleRate , _layerFrameSize );
171

172
  nbSamplesMax = (int) (_layerSampleRate * _layerFrameSize /1000);
173
174
175
176
177
178
179

  micData = new SFLDataFormat[nbSamplesMax];
  micDataConverted = new SFLDataFormat[nbSamplesMax];
  micDataEncoded = new unsigned char[nbSamplesMax];

  spkrDataConverted = new SFLDataFormat[nbSamplesMax];
  spkrDataDecoded = new SFLDataFormat[nbSamplesMax];
jpbl's avatar
jpbl committed
180
181
}

182
  void
183
184
AudioRtpRTX::initAudioRtpSession (void) 
{
185
  _debug("AudioRtpRTX::initAudioRtpSession: call %s \n",_ca->getCallId().c_str());
186
187
  try {
    if (_ca == 0) { return; }
188
    
189
    _audiocodec = Manager::instance().getCodecDescriptorMap().getCodec( _ca->getAudioCodec() );
190
191
    
    _codecSampleRate = _audiocodec->getClockRate();
192
193

    ost::InetHostAddress remote_ip(_ca->getRemoteIp().c_str());
194
    
195
196
197
198
    if (!remote_ip) {
      return;
    }

199

200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
    if (!_sym) {
      _sessionRecv->setSchedulingTimeout (10000);
      _sessionRecv->setExpireTimeout(1000000);

      _sessionSend->setSchedulingTimeout(10000);
      _sessionSend->setExpireTimeout(1000000);
    } else {
      _session->setSchedulingTimeout(10000);
      _session->setExpireTimeout(1000000);
    }

    if (!_sym) {
      if ( !_sessionRecv->addDestination(remote_ip, (unsigned short) _ca->getRemoteAudioPort()) ) {
	_debug("AudioRTP Thread Error: could not connect to port %d\n",  _ca->getRemoteAudioPort());
	return;
      }
      if (!_sessionSend->addDestination (remote_ip, (unsigned short) _ca->getRemoteAudioPort())) {
	_debug("! ARTP Thread Error: could not connect to port %d\n",  _ca->getRemoteAudioPort());
	return;
      }

      bool payloadIsSet = false;
      if (_audiocodec) {
	if (_audiocodec->hasDynamicPayload()) {
	  payloadIsSet = _sessionRecv->setPayloadFormat(ost::DynamicPayloadFormat((ost::PayloadType) _audiocodec->getPayload(), _audiocodec->getClockRate()));
	} else {
	  payloadIsSet= _sessionRecv->setPayloadFormat(ost::StaticPayloadFormat((ost::StaticPayloadType) _audiocodec->getPayload()));
	  payloadIsSet = _sessionSend->setPayloadFormat(ost::StaticPayloadFormat((ost::StaticPayloadType) _audiocodec->getPayload()));
228
	}
229
230
231
      }
      _sessionSend->setMark(true);
    } else {
232

233
      //_debug("AudioRTP Thread: Added session destination %s\n", remote_ip.getHostname() );
234

235
236
237
      if (!_session->addDestination (remote_ip, (unsigned short) _ca->getRemoteAudioPort())) {
	return;
      }
238

239
240
241
242
243
244
245
246
247
      bool payloadIsSet = false;
      if (_audiocodec) {
	if (_audiocodec->hasDynamicPayload()) {
	  payloadIsSet = _session->setPayloadFormat(ost::DynamicPayloadFormat((ost::PayloadType) _audiocodec->getPayload(), _audiocodec->getClockRate()));
	} else {
	  payloadIsSet = _session->setPayloadFormat(ost::StaticPayloadFormat((ost::StaticPayloadType) _audiocodec->getPayload()));
	}
      }
    }
248

249

250
251
252
253
  } catch(...) {
    _debugException("! ARTP Failure: initialisation failed");
    throw;
  }
254
  _debug("AudioRtpRTX::initAudioRtpSession: Init audio RTP sessionend of method\n");
Emmanuel Milou's avatar
Emmanuel Milou committed
255
256
}

257
  void
258
259
AudioRtpRTX::sendSessionFromMic(int timestamp)
{
260
261
262
263
264
  // STEP:
  //   1. get data from mic
  //   2. convert it to int16 - good sample, good rate
  //   3. encode it
  //   4. send it
Emmanuel Milou's avatar
Emmanuel Milou committed
265
  //try {
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281

    timestamp += time->getSecond();
    if (_ca==0) { _debug(" !ARTP: No call associated (mic)\n"); return; } // no call, so we do nothing
    AudioLayer* audiolayer = Manager::instance().getAudioDriver();
    if (!audiolayer) { _debug(" !ARTP: No audiolayer available for mic\n"); return; }

    if (!_audiocodec) { _debug(" !ARTP: No audiocodec available for mic\n"); return; }

    // we have to get 20ms of data from the mic *20/1000 = /50
    int maxBytesToGet = _layerSampleRate * _layerFrameSize * sizeof(SFLDataFormat) / 1000;
    // available bytes inside ringbuffer
    int availBytesFromMic = audiolayer->canGetMic();

    // take the lowest
    int bytesAvail = (availBytesFromMic < maxBytesToGet) ? availBytesFromMic : maxBytesToGet;
    // Get bytes from micRingBuffer to data_from_mic
282
283
    //_debug("get data from mic\n");
    int nbSample = audiolayer->getMic( micData , bytesAvail ) / sizeof(SFLDataFormat);
284
    int nb_sample_up = nbSample;
285
286
287
288
    
    // Store the length of the mic buffer in samples for recording
    _nSamplesMic = nbSample;

289
290
    int nbSamplesMax = _layerFrameSize * _audiocodec->getClockRate() / 1000;

Emmanuel Milou's avatar
Emmanuel Milou committed
291
    //_debug("resample data = %i\n", nb_sample_up);
292
293
294
295
    nbSample = reSampleData(_audiocodec->getClockRate(), nb_sample_up, DOWN_SAMPLING);	

    if ( nbSample < nbSamplesMax - 10 ) { // if only 10 is missing, it's ok
      // fill end with 0...
296
      memset( micDataConverted + nbSample, 0, (nbSamplesMax-nbSample)*sizeof(int16));
297
298
      nbSample = nbSamplesMax;
    }
299
    int compSize = _audiocodec->codecEncode( micDataEncoded , micDataConverted , nbSample*sizeof(int16));
300
301
302
303
    // encode divise by two
    // Send encoded audio sample over the network
    if (compSize > nbSamplesMax) { _debug("! ARTP: %d should be %d\n", compSize, nbSamplesMax);}
    if (!_sym) {
304
      _sessionSend->putData(timestamp, micDataEncoded, compSize);
305
    } else {
306
      _session->putData(timestamp, micDataEncoded, compSize);
307
    }
Emmanuel Milou's avatar
Emmanuel Milou committed
308
  /*} catch(...) {
309
310
    _debugException("! ARTP: sending failed");
    throw;
Emmanuel Milou's avatar
Emmanuel Milou committed
311
  }*/
jpbl's avatar
jpbl committed
312
313
}

314
  void
315
AudioRtpRTX::receiveSessionForSpkr (int& countTime)
jpbl's avatar
jpbl committed
316
{
317
318


319
  if (_ca == 0) { return; }
Emmanuel Milou's avatar
Emmanuel Milou committed
320
  //try {
321

322
323
324
325
326
327
    AudioLayer* audiolayer = Manager::instance().getAudioDriver();
    if (!audiolayer) { return; }

    const ost::AppDataUnit* adu = NULL;
    // Get audio data stream

328
329
    // printf("AudioRtpRTX::receiveSessionForSpkr() %i \n",_session->getFirstTimestamp());

330
331
332
333
334
335
336
337
338
339
    if (!_sym) {
      adu = _sessionRecv->getData(_sessionRecv->getFirstTimestamp());
    } else {
      adu = _session->getData(_session->getFirstTimestamp());
    }
    if (adu == NULL) {
      //_debug("No RTP audio stream\n");
      return;
    }

340
341
    

Emmanuel Milou's avatar
Emmanuel Milou committed
342
    //int payload = adu->getType(); // codec type
343
    unsigned char* spkrData  = (unsigned char*)adu->getData(); // data in char
344
345
    unsigned int size = adu->getSize(); // size in char

346
347
    // printf("AudioRtpRTX::receiveSessionForSpkr() Size of data from %i \n",size);

348
    // Decode data with relevant codec
Emmanuel Milou's avatar
Emmanuel Milou committed
349
    unsigned int max = (unsigned int)(_codecSampleRate * _layerFrameSize / 1000);
350
351

    if ( size > max ) {
Emmanuel Milou's avatar
Emmanuel Milou committed
352
      _debug("We have received from RTP a packet larger than expected: %d VS %d\n", size, max);
353
354
355
356
357
358
      _debug("The packet size has been cropped\n");
      size=max;
    }

    if (_audiocodec != NULL) {

359
      int expandedSize = _audiocodec->codecDecode( spkrDataDecoded , spkrData , size );
360
361
362
      //buffer _receiveDataDecoded ----> short int or int16, coded on 2 bytes
      int nbInt16 = expandedSize / sizeof(int16);
      //nbInt16 represents the number of samples we just decoded
Yun Liu's avatar
Yun Liu committed
363
      if ((unsigned int)nbInt16 > max) {
Emmanuel Milou's avatar
Emmanuel Milou committed
364
	_debug("We have decoded an RTP packet larger than expected: %d VS %d. Cropping.\n", nbInt16, max);
365
366
367
368
369
370
371
	nbInt16=max;
      }
      int nbSample = nbInt16;

      // Do sample rate conversion
      int nb_sample_down = nbSample;
      nbSample = reSampleData(_codecSampleRate , nb_sample_down, UP_SAMPLING);
372
373
374
#ifdef DATAFORMAT_IS_FLOAT
#else
#endif
375
376
377
    
      // Stor the number of samples for recording
      _nSamplesSpkr = nbSample;
378
        
379
380
    //audiolayer->playSamples( spkrDataConverted, nbSample * sizeof(SFLDataFormat), true);
    audiolayer->putMain (spkrDataConverted, nbSample * sizeof(SFLDataFormat));
Emmanuel Milou's avatar
Emmanuel Milou committed
381
      
382

383
384
385
386
387
388
      // Notify (with a beep) an incoming call when there is already a call 
      countTime += time->getSecond();
      if (Manager::instance().incomingCallWaiting() > 0) {
	countTime = countTime % 500; // more often...
	if (countTime == 0) {
	  Manager::instance().notificationIncomingCall();
389
	}
390
      }
391

392
393
394
395
    } else {
      countTime += time->getSecond();
    }
    delete adu; adu = NULL;
Emmanuel Milou's avatar
Emmanuel Milou committed
396
397
398
399
  //} catch(...) {
    //_debugException("! ARTP: receiving failed");
    //throw;
  //}
400

401
}
402

403
  int 
404
405
AudioRtpRTX::reSampleData(int sampleRate_codec, int nbSamples, int status)
{
406
  if(status==UP_SAMPLING){
407
    return converter->upsampleData( spkrDataDecoded , spkrDataConverted , sampleRate_codec , _layerSampleRate , nbSamples );
408
  }
409
  else if(status==DOWN_SAMPLING){
410
    return converter->downsampleData( micData , micDataConverted , sampleRate_codec , _layerSampleRate , nbSamples );
411
412
413
  }
  else
    return 0;
414
415
}

Alexandre Savard's avatar
Alexandre Savard committed
416
417


jpbl's avatar
jpbl committed
418
419
void
AudioRtpRTX::run () {
420
421
422
423
  //mic, we receive from soundcard in stereo, and we send encoded
  //encoding before sending
  AudioLayer *audiolayer = Manager::instance().getAudioDriver();
  _layerFrameSize = audiolayer->getFrameSize(); // en ms
424
  _layerSampleRate = audiolayer->getSampleRate();
425
426
427
  initBuffers();
  int step; 

428
429
  int sessionWaiting;

Emmanuel Milou's avatar
Emmanuel Milou committed
430
  //try {
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
    // Init the session
    initAudioRtpSession();
    step = (int) (_layerFrameSize * _codecSampleRate / 1000);
    // start running the packet queue scheduler.
    //_debug("AudioRTP Thread started\n");
    if (!_sym) {
      _sessionRecv->startRunning();
      _sessionSend->startRunning();
    } else {
      _session->startRunning();
      //_debug("Session is now: %d active\n", _session->isActive());
    }

    int timestamp = 0; // for mic
    int countTime = 0; // for receive
    TimerPort::setTimer(_layerFrameSize);

    audiolayer->startStream();
    _start.post();
450
    _debug("- ARTP Action: Start call %s\n",_ca->getCallId().c_str());
451
    while (!testCancel()) {
452
453
454
455
456
      
      // printf("AudioRtpRTX::run() _session->getFirstTimestamp() %i \n",_session->getFirstTimestamp());
    
      // printf("AudioRtpRTX::run() _session->isWaiting() %i \n",_session->isWaiting());
      /////////////////////
457
458
459
      ////////////////////////////
      // Send session
      ////////////////////////////
460
461
462

      sessionWaiting = _session->isWaiting();

463
      sendSessionFromMic(timestamp); 
464
      timestamp += step;
465
      
466
467
468
469
      ////////////////////////////
      // Recv session
      ////////////////////////////
      receiveSessionForSpkr(countTime);
470
      
471
      // Let's wait for the next transmit cycle
472

473
474
      
      if(sessionWaiting == 1){
Alexandre Savard's avatar
Alexandre Savard committed
475
        // _debug("Record TWO buffer \n");
476
        _ca->recAudio.recData(spkrDataConverted,micData,_nSamplesSpkr,_nSamplesMic);
477
478
      }
      else {
Alexandre Savard's avatar
Alexandre Savard committed
479
        // _debug("Record ONE buffer \n");
480
        _ca->recAudio.recData(micData,_nSamplesMic);
481
      }
482

483
      Thread::sleep(TimerPort::getTimer());
484
      TimerPort::incTimer(_layerFrameSize); // 'frameSize' ms
485
      
486
    }
487
    
alexandresavard's avatar
alexandresavard committed
488
    // _debug("stop stream for audiortp loop\n");
489
    audiolayer->stopStream();
490
    _debug("- ARTP Action: Stop call %s\n",_ca->getCallId().c_str());
Emmanuel Milou's avatar
Emmanuel Milou committed
491
492
493
494
495
496
497
498
499
  //} catch(std::exception &e) {
    //_start.post();
    //_debug("! ARTP: Stop %s\n", e.what());
    //throw;
  //} catch(...) {
    //_start.post();
    //_debugException("* ARTP Action: Stop");
    //throw;
  //}
alexandresavard's avatar
alexandresavard committed
500
    
jpbl's avatar
jpbl committed
501
502
503
504
}


// EOF