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 @@
* Copyright (C) 2005 Savoir-Faire Linux inc.
* Author: Yan Morin <yan.morin@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
* 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.
*
* This program is distributed in the hope that it will be useful,
......@@ -108,13 +109,15 @@ AudioLayer::hasStream(void) {
void
AudioLayer::openDevice (int indexIn, int indexOut, int sampleRate)
AudioLayer::openDevice (int indexIn, int indexOut, int sampleRate, int frameSize)
{
closeStream();
_sampleRate = sampleRate;
_frameSize = frameSize;
int portaudioFramePerBuffer = FRAME_PER_BUFFER; //=FRAME_PER_BUFFER; //= paFramesPerBufferUnspecified;
//int portaudioFramePerBuffer = (int) (8000 * frameSize / 1000);
//= paFramesPerBufferUnspecified;
int nbDevice = getDeviceCount();
if (nbDevice == 0) {
......
......@@ -2,10 +2,11 @@
* Copyright (C) 2004-2005 Savoir-Faire Linux inc.
* Author: Yan Morin <yan.morin@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
* 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.
*
* This program is distributed in the hope that it will be useful,
......@@ -35,96 +36,103 @@ class RingBuffer;
class ManagerImpl;
class AudioLayer {
public:
AudioLayer(ManagerImpl* manager);
~AudioLayer(void);
/*
* @param indexIn
* @param indexOut
* @param sampleRate
*/
void openDevice(int, int, int);
void startStream(void);
void stopStream(void);
void sleep(int);
bool hasStream(void);
bool isStreamActive(void);
bool isStreamStopped(void);
void flushMain();
int putMain(void* buffer, int toCopy);
int putUrgent(void* buffer, int toCopy);
int canGetMic();
int getMic(void *, int);
void flushMic();
int audioCallback (const void *, void *, unsigned long,
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; }
/**
* Get the sample rate of audiolayer
* accessor only
*/
unsigned int getSampleRate() { return _sampleRate; }
int getDeviceCount();
AudioDevice* getAudioDeviceInfo(int index, int ioDeviceMask);
enum IODEVICE {InputDevice=0x01, OutputDevice=0x02 };
/**
* Toggle echo testing on/off
*/
void toggleEchoTesting();
private:
void closeStream (void);
RingBuffer _urgentRingBuffer;
RingBuffer _mainSndRingBuffer;
RingBuffer _micRingBuffer;
ManagerImpl* _manager; // augment coupling, reduce indirect access
// a audiolayer can't live without manager
portaudio::MemFunCallbackStream<AudioLayer> *_stream;
/**
* Sample Rate of SFLphone : should be 8000 for 8khz
* Added because we could change it in the futur
*/
unsigned int _sampleRate;
/**
* Input channel (mic) should be 1 mono
*/
unsigned int _inChannel; // mic
/**
* Output channel (stereo) should be 1 mono
*/
unsigned int _outChannel; // speaker
/**
* Default volume for incoming RTP and Urgent sounds.
*/
unsigned short _defaultVolume; // 100
/**
* Echo testing or not
*/
bool _echoTesting;
std::string _errorMessage;
ost::Mutex _mutex;
float *table_;
int tableSize_;
int leftPhase_;
public:
AudioLayer(ManagerImpl* manager);
~AudioLayer(void);
/*
* @param indexIn
* @param indexOut
* @param sampleRate
* @param frameSize
*/
void openDevice(int, int, int, int);
void startStream(void);
void stopStream(void);
void sleep(int);
bool hasStream(void);
bool isStreamActive(void);
bool isStreamStopped(void);
void flushMain();
int putMain(void* buffer, int toCopy);
int putUrgent(void* buffer, int toCopy);
int canGetMic();
int getMic(void *, int);
void flushMic();
int audioCallback (const void *, void *, unsigned long,
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; }
/**
* Get the sample rate of audiolayer
* accessor only
*/
unsigned int getSampleRate() { return _sampleRate; }
unsigned int getFrameSize() { return _frameSize; }
int getDeviceCount();
AudioDevice* getAudioDeviceInfo(int index, int ioDeviceMask);
enum IODEVICE {InputDevice=0x01, OutputDevice=0x02 };
/**
* Toggle echo testing on/off
*/
void toggleEchoTesting();
private:
void closeStream (void);
RingBuffer _urgentRingBuffer;
RingBuffer _mainSndRingBuffer;
RingBuffer _micRingBuffer;
ManagerImpl* _manager; // augment coupling, reduce indirect access
// a audiolayer can't live without manager
portaudio::MemFunCallbackStream<AudioLayer> *_stream;
/**
* 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;
/**
* Length of the sound frame we capture or read in ms
* The value can be set in the user config file - now: 20ms
*/
unsigned int _frameSize;
/**
* Input channel (mic) should be 1 mono
*/
unsigned int _inChannel; // mic
/**
* Output channel (stereo) should be 1 mono
*/
unsigned int _outChannel; // speaker
/**
* Default volume for incoming RTP and Urgent sounds.
*/
unsigned short _defaultVolume; // 100
/**
* Echo testing or not
*/
bool _echoTesting;
std::string _errorMessage;
ost::Mutex _mutex;
float *table_;
int tableSize_;
int leftPhase_;
};
#endif // _AUDIO_LAYER_H_
......
/*
* Copyright (C) 2004-2007 Savoir-Faire Linux inc.
* Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
* Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com>
* 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
* 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.
*
* This program is distributed in the hope that it will be useful,
......@@ -44,476 +45,478 @@
////////////////////////////////////////////////////////////////////////////////
AudioRtp::AudioRtp ()
{
_RTXThread = 0;
_RTXThread = 0;
}
AudioRtp::~AudioRtp (void) {
delete _RTXThread; _RTXThread = 0;
delete _RTXThread; _RTXThread = 0;
}
int
AudioRtp::createNewSession (SIPCall *ca) {
ost::MutexLock m(_threadMutex);
// 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) {
_debug("! ARTP Failure: unable to start RTX Thread\n");
return -1;
}
} catch(...) {
_debugException("! ARTP Failure: when trying to start a thread");
throw;
}
return 0;
ost::MutexLock m(_threadMutex);
// 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) {
_debug("! ARTP Failure: unable to start RTX Thread\n");
return -1;
}
} catch(...) {
_debugException("! ARTP Failure: when trying to start a thread");
throw;
}
return 0;
}
void
AudioRtp::closeRtpSession () {
ost::MutexLock m(_threadMutex);
// This will make RTP threads finish.
// _debug("Stopping AudioRTP\n");
try {
delete _RTXThread; _RTXThread = 0;
} catch(...) {
_debugException("! ARTP Exception: when stopping audiortp\n");
throw;
}
ost::MutexLock m(_threadMutex);
// This will make RTP threads finish.
// _debug("Stopping AudioRTP\n");
try {
delete _RTXThread; _RTXThread = 0;
} catch(...) {
_debugException("! ARTP Exception: when stopping audiortp\n");
throw;
}
}
////////////////////////////////////////////////////////////////////////////////
// AudioRtpRTX Class //
////////////////////////////////////////////////////////////////////////////////
AudioRtpRTX::AudioRtpRTX (SIPCall *sipcall, bool sym)
// : _fstream("/tmp/audio.dat", std::ofstream::binary)
{
setCancel(cancelDeferred);
time = new ost::Time();
_ca = sipcall;
_sym = sym;
// AudioRtpRTX should be close if we change sample rate
_receiveDataDecoded = new int16[RTP_20S_48KHZ_MAX];
_sendDataEncoded = new unsigned char[RTP_20S_8KHZ_MAX];
// we estimate that the number of format after a conversion 8000->48000 is expanded to 6 times
_dataAudioLayer = new SFLDataFormat[RTP_20S_48KHZ_MAX];
_floatBuffer8000 = new float32[RTP_20S_8KHZ_MAX];
_floatBuffer48000 = new float32[RTP_20S_48KHZ_MAX];
_intBuffer8000 = new int16[RTP_20S_8KHZ_MAX];
// 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;
}
// 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);
// : _fstream("/tmp/audio.dat", std::ofstream::binary)
{
setCancel(cancelDeferred);
time = new ost::Time();
_ca = sipcall;
_sym = sym;
// AudioRtpRTX should be close if we change sample rate
_codecSampleRate = _ca->getAudioCodec()->getClockRate();
// 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;
}
// libsamplerate-related
// Set the converter type for the upsampling and the downsampling
// interpolator SRC_SINC_BEST_QUALITY
_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 () {
_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;
}
delete [] _intBuffer8000; _intBuffer8000 = NULL;
delete [] _floatBuffer48000; _floatBuffer48000 = NULL;
delete [] _floatBuffer8000; _floatBuffer8000 = NULL;
delete [] _dataAudioLayer; _dataAudioLayer = NULL;
delete [] _sendDataEncoded; _sendDataEncoded = NULL;
delete [] _receiveDataDecoded; _receiveDataDecoded = NULL;
delete time; time = NULL;
// libsamplerate-related
_src_state_mic = src_delete(_src_state_mic);
_src_state_spkr = src_delete(_src_state_spkr);
_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;
}
delete [] _intBufferDown; _intBufferDown = NULL;
delete [] _floatBufferUp; _floatBufferUp = NULL;
delete [] _floatBufferDown; _floatBufferDown = NULL;
delete [] _dataAudioLayer; _dataAudioLayer = NULL;
delete [] _sendDataEncoded; _sendDataEncoded = NULL;
delete [] _receiveDataDecoded; _receiveDataDecoded = NULL;
delete time; time = NULL;
// libsamplerate-related
_src_state_mic = src_delete(_src_state_mic);
_src_state_spkr = src_delete(_src_state_spkr);
}
void
AudioRtpRTX::initAudioRtpSession (void)
void
AudioRtpRTX::initBuffers()
{
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()));
}
}
_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;
}
int nbSamplesMax = (int) (_layerSampleRate * _layerFrameSize /1000);
_dataAudioLayer = new SFLDataFormat[nbSamplesMax];
_receiveDataDecoded = new int16[nbSamplesMax];
_floatBufferDown = new float32[nbSamplesMax];
_floatBufferUp = new float32[nbSamplesMax];
_sendDataEncoded = new unsigned char[nbSamplesMax];
_intBufferDown = new int16[nbSamplesMax];
}
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()));
}
}
_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()));
}