audiortp.cpp 15.8 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) {
Emmanuel Milou's avatar
Emmanuel Milou committed
56
  //ost::MutexLock m(_threadMutex);
57
58
59
60
61
62
63
64
65
66
67
68
69

  // something should stop the thread before...
  if ( _RTXThread != 0 ) { 
    _debug("! ARTP Failure: Thread already exists..., stopping it\n");
    delete _RTXThread; _RTXThread = 0;
    //return -1; 
  }

  // 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
70
     _debug("! ARTP Failure: unable to start RTX Thread\n");
71
72
73
74
75
76
      return -1;
    }
  } catch(...) {
    _debugException("! ARTP Failure: when trying to start a thread");
    throw;
  }
alexandresavard's avatar
alexandresavard committed
77

78
  return 0;
jpbl's avatar
jpbl committed
79
80
}

81

jpbl's avatar
jpbl committed
82
83
void
AudioRtp::closeRtpSession () {
84

Emmanuel Milou's avatar
Emmanuel Milou committed
85
  //ost::MutexLock m(_threadMutex);
86
87
88
89
90
91
92
93
  // This will make RTP threads finish.
  // _debug("Stopping AudioRTP\n");
  try {
    delete _RTXThread; _RTXThread = 0;
  } catch(...) {
    _debugException("! ARTP Exception: when stopping audiortp\n");
    throw;
  }
94

Yun Liu's avatar
Yun Liu committed
95
96
  AudioLayer* audiolayer = Manager::instance().getAudioDriver();
  audiolayer->stopStream();
jpbl's avatar
jpbl committed
97
98
}

alexandresavard's avatar
alexandresavard committed
99
100
101
102
103

void
AudioRtp::setRecording() {
  
  _debug("AudioRtp::setRecording");
104
105
  // _RTXThread->recAudio.setRecording();
  _RTXThread->_ca->setRecording();
alexandresavard's avatar
alexandresavard committed
106
107
108
109
110
  
}



jpbl's avatar
jpbl committed
111
112
113
////////////////////////////////////////////////////////////////////////////////
// AudioRtpRTX Class                                                          //
////////////////////////////////////////////////////////////////////////////////
Yun Liu's avatar
Yun Liu committed
114
115
116
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)
117
{
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
  setCancel(cancelDeferred);
  // 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;
  }
jpbl's avatar
jpbl committed
133
134
135
}

AudioRtpRTX::~AudioRtpRTX () {
136
137
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;
  }
  //_debug("terminate audiortprtx ended...\n");
  _ca = 0;
  if (!_sym) {
    delete _sessionRecv; _sessionRecv = NULL;
    delete _sessionSend; _sessionSend = NULL;
  } else {
    delete _session;     _session = NULL;
  }

153
154
155
  delete [] micData;  micData = NULL;
  delete [] micDataConverted;  micDataConverted = NULL;
  delete [] micDataEncoded;  micDataEncoded = NULL;
156

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

  delete time; time = NULL;
161
162

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

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

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

  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
178
179
}

180
  void
181
182
AudioRtpRTX::initAudioRtpSession (void) 
{
183
184
185
186
187
188
189
190
191
192
193
194
  try {
    if (_ca == 0) { return; }
    _audiocodec = Manager::instance().getCodecDescriptorMap().getCodec( _ca->getAudioCodec() );
    _codecSampleRate = _audiocodec->getClockRate();	

    _debug("Init audio RTP session\n");
    ost::InetHostAddress remote_ip(_ca->getRemoteIp().c_str());
    if (!remote_ip) {
      _debug("! ARTP Thread Error: Target IP address [%s] is not correct!\n", _ca->getRemoteIp().data());
      return;
    }

195
196
197
198
199
200
201
202
203
204
205
206
    // Initialization   
    printf("AudioRTPX::initAudioRtpSession: CallID to be used: %s \n",_ca->getCallId().c_str());           
 
    printf("AudioRTPX::initAudioRtpSession: Account %s \n",Manager::instance().getAccountFromCall(_ca->getCallId()).c_str());
    
    printf("AudioRTPX::initAudioSRtpSession: FileName from call class: %s \n", _ca->getFileName().c_str());
    
 
    _debug("Opening the wave file\n");
    FILE_TYPE ft = FILE_WAV;
    SOUND_FORMAT sf = INT16;
    recAudio.setSndSamplingRate(44100);
207
208
209
210
211
    recAudio.openFile(_ca->getFileName(),ft,sf);
    
    //_debug("Opening the wave file in call nstance\n");
    //_ca->recAudio.setSndSamplingRate(44100);
    //_ca->recAudio.openFile("testRecFromCall",ft,sf,_ca->getCallId());
212
213


214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
    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()));
242
	}
243
244
245
      }
      _sessionSend->setMark(true);
    } else {
246

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

249
250
251
      if (!_session->addDestination (remote_ip, (unsigned short) _ca->getRemoteAudioPort())) {
	return;
      }
252

253
254
255
256
257
258
259
260
261
      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()));
	}
      }
    }
262

263

264
265
266
267
  } catch(...) {
    _debugException("! ARTP Failure: initialisation failed");
    throw;
  }
Emmanuel Milou's avatar
Emmanuel Milou committed
268
269
}

270
  void
271
272
AudioRtpRTX::sendSessionFromMic(int timestamp)
{
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
  // STEP:
  //   1. get data from mic
  //   2. convert it to int16 - good sample, good rate
  //   3. encode it
  //   4. send it
  try {

    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
295
296
    //_debug("get data from mic\n");
    int nbSample = audiolayer->getMic( micData , bytesAvail ) / sizeof(SFLDataFormat);
297
    int nb_sample_up = nbSample;
298
299
300
301
    
    // Store the length of the mic buffer in samples for recording
    _nSamplesMic = nbSample;

302
303
    int nbSamplesMax = _layerFrameSize * _audiocodec->getClockRate() / 1000;

304
    //_debug("resample data\n");
305
306
307
308
    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...
309
      memset( micDataConverted + nbSample, 0, (nbSamplesMax-nbSample)*sizeof(int16));
310
311
      nbSample = nbSamplesMax;
    }
312
    int compSize = _audiocodec->codecEncode( micDataEncoded , micDataConverted , nbSample*sizeof(int16));
313
314
315
316
    // 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) {
317
      _sessionSend->putData(timestamp, micDataEncoded, compSize);
318
    } else {
319
      _session->putData(timestamp, micDataEncoded, compSize);
320
321
322
323
324
    }
  } catch(...) {
    _debugException("! ARTP: sending failed");
    throw;
  }
jpbl's avatar
jpbl committed
325
326
}

327
  void
328
AudioRtpRTX::receiveSessionForSpkr (int& countTime)
jpbl's avatar
jpbl committed
329
{
330
331


332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
  if (_ca == 0) { return; }
  try {
    AudioLayer* audiolayer = Manager::instance().getAudioDriver();
    if (!audiolayer) { return; }

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

    if (!_sym) {
      adu = _sessionRecv->getData(_sessionRecv->getFirstTimestamp());
    } else {
      adu = _session->getData(_session->getFirstTimestamp());
    }
    if (adu == NULL) {
      //_debug("No RTP audio stream\n");
      return;
    }

Emmanuel Milou's avatar
Emmanuel Milou committed
350
    //int payload = adu->getType(); // codec type
351
    unsigned char* spkrData  = (unsigned char*)adu->getData(); // data in char
352
353
354
    unsigned int size = adu->getSize(); // size in char

    // Decode data with relevant codec
Emmanuel Milou's avatar
Emmanuel Milou committed
355
    unsigned int max = (unsigned int)(_codecSampleRate * _layerFrameSize / 1000);
356
357

    if ( size > max ) {
Emmanuel Milou's avatar
Emmanuel Milou committed
358
      _debug("We have received from RTP a packet larger than expected: %d VS %d\n", size, max);
359
360
361
362
363
      _debug("The packet size has been cropped\n");
      size=max;
    }

    if (_audiocodec != NULL) {
364
  
365

366
      int expandedSize = _audiocodec->codecDecode( spkrDataDecoded , spkrData , size );
367
368
369
      //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
370
      if ((unsigned int)nbInt16 > max) {
Emmanuel Milou's avatar
Emmanuel Milou committed
371
	_debug("We have decoded an RTP packet larger than expected: %d VS %d. Cropping.\n", nbInt16, max);
372
373
374
375
376
377
378
	nbInt16=max;
      }
      int nbSample = nbInt16;

      // Do sample rate conversion
      int nb_sample_down = nbSample;
      nbSample = reSampleData(_codecSampleRate , nb_sample_down, UP_SAMPLING);
379
380
381
#ifdef DATAFORMAT_IS_FLOAT
#else
#endif
382
383
384
    
      // Stor the number of samples for recording
      _nSamplesSpkr = nbSample;
385
        
Emmanuel Milou's avatar
Emmanuel Milou committed
386
      audiolayer->playSamples( spkrDataConverted, nbSample * sizeof(SFLDataFormat), true);
387

Emmanuel Milou's avatar
Emmanuel Milou committed
388
      
389
390
391
392
393
394
      // 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();
395
	}
396
      }
397

398
399
400
401
402
403
404
405
    } else {
      countTime += time->getSecond();
    }
    delete adu; adu = NULL;
  } catch(...) {
    _debugException("! ARTP: receiving failed");
    throw;
  }
Emmanuel Milou's avatar
Emmanuel Milou committed
406

407

408
}
409

410
  int 
411
412
AudioRtpRTX::reSampleData(int sampleRate_codec, int nbSamples, int status)
{
413
  if(status==UP_SAMPLING){
414
    return converter->upsampleData( spkrDataDecoded , spkrDataConverted , sampleRate_codec , _layerSampleRate , nbSamples );
415
  }
416
  else if(status==DOWN_SAMPLING){
417
    return converter->downsampleData( micData , micDataConverted , sampleRate_codec , _layerSampleRate , nbSamples );
418
419
420
  }
  else
    return 0;
421
422
}

jpbl's avatar
jpbl committed
423
424
void
AudioRtpRTX::run () {
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
  //mic, we receive from soundcard in stereo, and we send encoded
  //encoding before sending
  AudioLayer *audiolayer = Manager::instance().getAudioDriver();
  _layerFrameSize = audiolayer->getFrameSize(); // en ms
  _layerSampleRate = audiolayer->getSampleRate();	
  initBuffers();
  int step; 

  try {
    // 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();
    _debug("- ARTP Action: Start\n");
    while (!testCancel()) {
      ////////////////////////////
      // Send session
      ////////////////////////////
      sendSessionFromMic(timestamp);
      timestamp += step;
      ////////////////////////////
      // Recv session
      ////////////////////////////
      receiveSessionForSpkr(countTime);
      // Let's wait for the next transmit cycle
465

466
      recAudio.recData(spkrDataConverted,micData,_nSamplesSpkr,_nSamplesMic);
467
468
      _ca->recAudio.recData(spkrDataConverted,micData,_nSamplesSpkr,_nSamplesMic);

469
      Thread::sleep(TimerPort::getTimer()); 
470
471
      TimerPort::incTimer(_layerFrameSize); // 'frameSize' ms
    }
472
473
474

    _debug("Close wave file\n");
    recAudio.closeFile();
475
476
477
   
    //_debug("Close wave file in call instance\n");
    //_ca->recAudio.closeFile();
478

alexandresavard's avatar
alexandresavard committed
479
    // _debug("stop stream for audiortp loop\n");
480
481
482
483
    audiolayer->stopStream();
  } catch(std::exception &e) {
    _start.post();
    _debug("! ARTP: Stop %s\n", e.what());
alexandresavard's avatar
alexandresavard committed
484
    
485
486
    _debug("! Close wave file\n");
    recAudio.closeFile();
487
488
489
   
    //_debug("Close wave file in call instance\n");
    //_ca->recAudio.closeFile();
490
 
491
492
493
494
    throw;
  } catch(...) {
    _start.post();
    _debugException("* ARTP Action: Stop");
495
496
    _debug("* Close wave file\n");
    recAudio.closeFile(); 
497
498
499
   
    //_debug("Close wave file in call instance\n");
    //_ca->recAudio.closeFile();
500

501
502
    throw;
  }
jpbl's avatar
jpbl committed
503
504
505
506
}


// EOF