Commit fa57bac5 authored by Emmanuel Milou's avatar Emmanuel Milou
Browse files

use sampling frequency and frame size from the user config

Sampling rate values are no more hardcoded. The sampling rate of the audio layer
 and the frame size can be set in the user config file. The clock rate of the codec we use
in the rtp session is set with his actual value, but can be changed by modifying
the available codec in the user config file (only G711 for now)
parent 9c76e463
...@@ -2,10 +2,11 @@ ...@@ -2,10 +2,11 @@
* Copyright (C) 2005 Savoir-Faire Linux inc. * Copyright (C) 2005 Savoir-Faire Linux inc.
* Author: Yan Morin <yan.morin@savoirfairelinux.com> * Author: Yan Morin <yan.morin@savoirfairelinux.com>
* Author: Jerome Oufella <jerome.oufella@savoirfairelinux.com> * Author: Jerome Oufella <jerome.oufella@savoirfairelinux.com>
* Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
...@@ -108,13 +109,15 @@ AudioLayer::hasStream(void) { ...@@ -108,13 +109,15 @@ AudioLayer::hasStream(void) {
void void
AudioLayer::openDevice (int indexIn, int indexOut, int sampleRate) AudioLayer::openDevice (int indexIn, int indexOut, int sampleRate, int frameSize)
{ {
closeStream(); closeStream();
_sampleRate = sampleRate; _sampleRate = sampleRate;
_frameSize = frameSize;
int portaudioFramePerBuffer = FRAME_PER_BUFFER; //=FRAME_PER_BUFFER; //= paFramesPerBufferUnspecified; int portaudioFramePerBuffer = FRAME_PER_BUFFER; //=FRAME_PER_BUFFER; //= paFramesPerBufferUnspecified;
//int portaudioFramePerBuffer = (int) (8000 * frameSize / 1000);
//= paFramesPerBufferUnspecified;
int nbDevice = getDeviceCount(); int nbDevice = getDeviceCount();
if (nbDevice == 0) { if (nbDevice == 0) {
......
...@@ -2,10 +2,11 @@ ...@@ -2,10 +2,11 @@
* Copyright (C) 2004-2005 Savoir-Faire Linux inc. * Copyright (C) 2004-2005 Savoir-Faire Linux inc.
* Author: Yan Morin <yan.morin@savoirfairelinux.com> * Author: Yan Morin <yan.morin@savoirfairelinux.com>
* Author: Jerome Oufella <jerome.oufella@savoirfairelinux.com> * Author: Jerome Oufella <jerome.oufella@savoirfairelinux.com>
* Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
...@@ -35,96 +36,103 @@ class RingBuffer; ...@@ -35,96 +36,103 @@ class RingBuffer;
class ManagerImpl; class ManagerImpl;
class AudioLayer { class AudioLayer {
public: public:
AudioLayer(ManagerImpl* manager); AudioLayer(ManagerImpl* manager);
~AudioLayer(void); ~AudioLayer(void);
/* /*
* @param indexIn * @param indexIn
* @param indexOut * @param indexOut
* @param sampleRate * @param sampleRate
*/ * @param frameSize
void openDevice(int, int, int); */
void startStream(void); void openDevice(int, int, int, int);
void stopStream(void); void startStream(void);
void sleep(int); void stopStream(void);
bool hasStream(void); void sleep(int);
bool isStreamActive(void); bool hasStream(void);
bool isStreamStopped(void); bool isStreamActive(void);
bool isStreamStopped(void);
void flushMain();
int putMain(void* buffer, int toCopy); void flushMain();
int putUrgent(void* buffer, int toCopy); int putMain(void* buffer, int toCopy);
int canGetMic(); int putUrgent(void* buffer, int toCopy);
int getMic(void *, int); int canGetMic();
void flushMic(); int getMic(void *, int);
void flushMic();
int audioCallback (const void *, void *, unsigned long,
const PaStreamCallbackTimeInfo*, PaStreamCallbackFlags); int audioCallback (const void *, void *, unsigned long,
int miniAudioCallback (const void *, void *, unsigned long, const PaStreamCallbackTimeInfo*, PaStreamCallbackFlags);
const PaStreamCallbackTimeInfo*, PaStreamCallbackFlags); int miniAudioCallback (const void *, void *, unsigned long,
const PaStreamCallbackTimeInfo*, PaStreamCallbackFlags);
void setErrorMessage(const std::string& error) { _errorMessage = error; }
std::string getErrorMessage() { return _errorMessage; } void setErrorMessage(const std::string& error) { _errorMessage = error; }
std::string getErrorMessage() { return _errorMessage; }
/**
* Get the sample rate of audiolayer /**
* accessor only * Get the sample rate of audiolayer
*/ * accessor only
unsigned int getSampleRate() { return _sampleRate; } */
unsigned int getSampleRate() { return _sampleRate; }
int getDeviceCount(); unsigned int getFrameSize() { return _frameSize; }
AudioDevice* getAudioDeviceInfo(int index, int ioDeviceMask); int getDeviceCount();
AudioDevice* getAudioDeviceInfo(int index, int ioDeviceMask);
enum IODEVICE {InputDevice=0x01, OutputDevice=0x02 };
enum IODEVICE {InputDevice=0x01, OutputDevice=0x02 };
/**
* Toggle echo testing on/off /**
*/ * Toggle echo testing on/off
void toggleEchoTesting(); */
void toggleEchoTesting();
private:
void closeStream (void); private:
RingBuffer _urgentRingBuffer; void closeStream (void);
RingBuffer _mainSndRingBuffer; RingBuffer _urgentRingBuffer;
RingBuffer _micRingBuffer; RingBuffer _mainSndRingBuffer;
ManagerImpl* _manager; // augment coupling, reduce indirect access RingBuffer _micRingBuffer;
// a audiolayer can't live without manager ManagerImpl* _manager; // augment coupling, reduce indirect access
// a audiolayer can't live without manager
portaudio::MemFunCallbackStream<AudioLayer> *_stream;
portaudio::MemFunCallbackStream<AudioLayer> *_stream;
/**
* Sample Rate of SFLphone : should be 8000 for 8khz /**
* Added because we could change it in the futur * Sample Rate SFLphone should send sound data to the sound card
*/ * The value can be set in the user config file- now: 44100HZ
unsigned int _sampleRate; */
unsigned int _sampleRate;
/**
* Input channel (mic) should be 1 mono /**
*/ * Length of the sound frame we capture or read in ms
unsigned int _inChannel; // mic * The value can be set in the user config file - now: 20ms
*/
/** unsigned int _frameSize;
* Output channel (stereo) should be 1 mono
*/ /**
unsigned int _outChannel; // speaker * Input channel (mic) should be 1 mono
*/
/** unsigned int _inChannel; // mic
* Default volume for incoming RTP and Urgent sounds.
*/ /**
unsigned short _defaultVolume; // 100 * Output channel (stereo) should be 1 mono
*/
/** unsigned int _outChannel; // speaker
* Echo testing or not
*/ /**
bool _echoTesting; * Default volume for incoming RTP and Urgent sounds.
*/
std::string _errorMessage; unsigned short _defaultVolume; // 100
ost::Mutex _mutex;
/**
float *table_; * Echo testing or not
int tableSize_; */
int leftPhase_; bool _echoTesting;
std::string _errorMessage;
ost::Mutex _mutex;
float *table_;
int tableSize_;
int leftPhase_;
}; };
#endif // _AUDIO_LAYER_H_ #endif // _AUDIO_LAYER_H_
......
/* /*
* Copyright (C) 2004-2007 Savoir-Faire Linux inc. * Copyright (C) 2004-2007 Savoir-Faire Linux inc.
* Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
* Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com> * Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com>
* Author: Yan Morin <yan.morin@savoirfairelinux.com> * Author: Yan Morin <yan.morin@savoirfairelinux.com>
* Author: Laurielle Lea <laurielle.lea@savoirfairelinux.com> * Author: Laurielle Lea <laurielle.lea@savoirfairelinux.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
...@@ -44,476 +45,478 @@ ...@@ -44,476 +45,478 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
AudioRtp::AudioRtp () AudioRtp::AudioRtp ()
{ {
_RTXThread = 0; _RTXThread = 0;
} }
AudioRtp::~AudioRtp (void) { AudioRtp::~AudioRtp (void) {
delete _RTXThread; _RTXThread = 0; delete _RTXThread; _RTXThread = 0;
} }
int int
AudioRtp::createNewSession (SIPCall *ca) { AudioRtp::createNewSession (SIPCall *ca) {
ost::MutexLock m(_threadMutex); ost::MutexLock m(_threadMutex);
// something should stop the thread before... // something should stop the thread before...
if ( _RTXThread != 0 ) { if ( _RTXThread != 0 ) {
_debug("! ARTP Failure: Thread already exists..., stopping it\n"); _debug("! ARTP Failure: Thread already exists..., stopping it\n");
delete _RTXThread; _RTXThread = 0; delete _RTXThread; _RTXThread = 0;
//return -1; //return -1;
} }
// Start RTP Send/Receive threads // Start RTP Send/Receive threads
_symmetric = Manager::instance().getConfigInt(SIGNALISATION,SYMMETRIC) ? true : false; _symmetric = Manager::instance().getConfigInt(SIGNALISATION,SYMMETRIC) ? true : false;
_RTXThread = new AudioRtpRTX (ca, _symmetric); _RTXThread = new AudioRtpRTX (ca, _symmetric);
try { try {
if (_RTXThread->start() != 0) { if (_RTXThread->start() != 0) {
_debug("! ARTP Failure: unable to start RTX Thread\n"); _debug("! ARTP Failure: unable to start RTX Thread\n");
return -1; return -1;
} }
} catch(...) { } catch(...) {
_debugException("! ARTP Failure: when trying to start a thread"); _debugException("! ARTP Failure: when trying to start a thread");
throw; throw;
} }
return 0; return 0;
} }
void void
AudioRtp::closeRtpSession () { AudioRtp::closeRtpSession () {
ost::MutexLock m(_threadMutex); ost::MutexLock m(_threadMutex);
// This will make RTP threads finish. // This will make RTP threads finish.
// _debug("Stopping AudioRTP\n"); // _debug("Stopping AudioRTP\n");
try { try {
delete _RTXThread; _RTXThread = 0; delete _RTXThread; _RTXThread = 0;
} catch(...) { } catch(...) {
_debugException("! ARTP Exception: when stopping audiortp\n"); _debugException("! ARTP Exception: when stopping audiortp\n");
throw; throw;
} }
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// AudioRtpRTX Class // // AudioRtpRTX Class //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
AudioRtpRTX::AudioRtpRTX (SIPCall *sipcall, bool sym) AudioRtpRTX::AudioRtpRTX (SIPCall *sipcall, bool sym)
// : _fstream("/tmp/audio.dat", std::ofstream::binary) // : _fstream("/tmp/audio.dat", std::ofstream::binary)
{ {
setCancel(cancelDeferred); setCancel(cancelDeferred);
time = new ost::Time(); time = new ost::Time();
_ca = sipcall; _ca = sipcall;
_sym = sym; _sym = sym;
// AudioRtpRTX should be close if we change sample rate // AudioRtpRTX should be close if we change sample rate
_receiveDataDecoded = new int16[RTP_20S_48KHZ_MAX]; _codecSampleRate = _ca->getAudioCodec()->getClockRate();
_sendDataEncoded = new unsigned char[RTP_20S_8KHZ_MAX];
// TODO: Change bind address according to user settings.
// we estimate that the number of format after a conversion 8000->48000 is expanded to 6 times // TODO: this should be the local ip not the external (router) IP
_dataAudioLayer = new SFLDataFormat[RTP_20S_48KHZ_MAX]; std::string localipConfig = _ca->getLocalIp(); // _ca->getLocalIp();
_floatBuffer8000 = new float32[RTP_20S_8KHZ_MAX]; ost::InetHostAddress local_ip(localipConfig.c_str());
_floatBuffer48000 = new float32[RTP_20S_48KHZ_MAX];
_intBuffer8000 = new int16[RTP_20S_8KHZ_MAX]; if (!_sym) {
_sessionRecv = new ost::RTPSession(local_ip, _ca->getLocalAudioPort());
// TODO: Change bind address according to user settings. _sessionSend = new ost::RTPSession(local_ip, _ca->getLocalAudioPort());
// TODO: this should be the local ip not the external (router) IP _session = NULL;
std::string localipConfig = _ca->getLocalIp(); // _ca->getLocalIp(); } else {
ost::InetHostAddress local_ip(localipConfig.c_str()); _session = new ost::SymmetricRTPSession (local_ip, _ca->getLocalAudioPort());
_sessionRecv = NULL;
if (!_sym) { _sessionSend = NULL;
_sessionRecv = new ost::RTPSession(local_ip, _ca->getLocalAudioPort()); }
_sessionSend = new ost::RTPSession(local_ip, _ca->getLocalAudioPort());
_session = NULL; // libsamplerate-related
} else { // Set the converter type for the upsampling and the downsampling
_session = new ost::SymmetricRTPSession (local_ip, _ca->getLocalAudioPort()); // interpolator SRC_SINC_BEST_QUALITY
_sessionRecv = NULL; _src_state_mic = src_new(SRC_SINC_BEST_QUALITY, 1, &_src_err);
_sessionSend = NULL; _src_state_spkr = src_new(SRC_SINC_BEST_QUALITY, 1, &_src_err);
}
// 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);
} }
AudioRtpRTX::~AudioRtpRTX () { AudioRtpRTX::~AudioRtpRTX () {
_start.wait(); _start.wait();
try { try {
this->terminate(); this->terminate();
} catch(...) { } catch(...) {
_debugException("! ARTP: Thread destructor didn't terminate correctly"); _debugException("! ARTP: Thread destructor didn't terminate correctly");
throw; throw;
} }
//_debug("terminate audiortprtx ended...\n"); //_debug("terminate audiortprtx ended...\n");
_ca = 0; _ca = 0;
if (!_sym) { if (!_sym) {
delete _sessionRecv; _sessionRecv = NULL; delete _sessionRecv; _sessionRecv = NULL;
delete _sessionSend; _sessionSend = NULL; delete _sessionSend; _sessionSend = NULL;
} else { } else {
delete _session; _session = NULL; delete _session; _session = NULL;
} }
delete [] _intBuffer8000; _intBuffer8000 = NULL; delete [] _intBufferDown; _intBufferDown = NULL;
delete [] _floatBuffer48000; _floatBuffer48000 = NULL; delete [] _floatBufferUp; _floatBufferUp = NULL;
delete [] _floatBuffer8000; _floatBuffer8000 = NULL; delete [] _floatBufferDown; _floatBufferDown = NULL;
delete [] _dataAudioLayer; _dataAudioLayer = NULL; delete [] _dataAudioLayer; _dataAudioLayer = NULL;
delete [] _sendDataEncoded; _sendDataEncoded = NULL; delete [] _sendDataEncoded; _sendDataEncoded = NULL;
delete [] _receiveDataDecoded; _receiveDataDecoded = NULL; delete [] _receiveDataDecoded; _receiveDataDecoded = NULL;
delete time; time = NULL; delete time; time = NULL;
// libsamplerate-related // libsamplerate-related
_src_state_mic = src_delete(_src_state_mic); _src_state_mic = src_delete(_src_state_mic);
_src_state_spkr = src_delete(_src_state_spkr); _src_state_spkr = src_delete(_src_state_spkr);
} }
void void
AudioRtpRTX::initAudioRtpSession (void) AudioRtpRTX::initBuffers()
{ {
try { int nbSamplesMax = (int) (_layerSampleRate * _layerFrameSize /1000);
if (_ca == 0) { return; } _dataAudioLayer = new SFLDataFormat[nbSamplesMax];
_receiveDataDecoded = new int16[nbSamplesMax];
//_debug("Init audio RTP session\n"); _floatBufferDown = new float32[nbSamplesMax];
ost::InetHostAddress remote_ip(_ca->getRemoteIp().c_str()); _floatBufferUp = new float32[nbSamplesMax];
if (!remote_ip) { _sendDataEncoded = new unsigned char[nbSamplesMax];
_debug("! ARTP Thread Error: Target IP address [%s] is not correct!\n", _ca->getRemoteIp().data()); _intBufferDown = new int16[nbSamplesMax];
return;
}
// Initialization
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;
}
AudioCodec* audiocodec = _ca->getAudioCodec();
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()));
}
}
_sessionSend->setMark(true);
} else {
//_debug("AudioRTP Thread: Added session destination %s:%d\n", remote_ip.getHostname(), (unsigned short) _ca->getRemoteSdpAudioPort());
if (!_session->addDestination (remote_ip, (unsigned short) _ca->getRemoteAudioPort())) {
return;
}
AudioCodec* audiocodec = _ca->getAudioCodec();
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()));
}
}
}
} catch(...) {
_debugException("! ARTP Failure: initialisation failed");
throw;
}
} }
void
AudioRtpRTX::initAudioRtpSession (void)
{
try {
if (_ca == 0) { return; }
//_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;
}
// Initialization
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;
}
AudioCodec* audiocodec = _ca->getAudioCodec();
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()));
}