Skip to content
Snippets Groups Projects
Commit f8cdc96f authored by yanmorin's avatar yanmorin
Browse files

Audio refactoring to use float or integer with portaudio.

Samplerate is now a dependancy.
parent 10461835
No related branches found
No related tags found
No related merge requests found
Showing with 521 additions and 330 deletions
2006-08-30 Yan Morin
* Set libsamplerate as a dependency
* Refactoring samplerate conversion, -DDATAFORMAT_IS_FLOAT allow the user to use float instead of int
2006-08-02 Yan Morin
* Add IAX quelch/unquelch
......
......@@ -80,11 +80,14 @@ Building the dependencies
-------------------------
If you do not use either the development packages of your distribution or the source packages made by the upstream authors of dependencies, you may want to try our custom dependencies building script in tools/ directory:
Note that commoncpp, ccrtp, libosip and libexosip, samplerate are in debian and fedora.
1. cd tools/
2. edit config.sh to change the default prefix (/usr/local)
3. ./download.sh
4. ./install.sh
5. ./portaudio.sh <-- compile portaudio
2. ./portaudio.sh <-- compile portaudio
3. if you want to install other software, check inside the file config.sh
edit config.sh to change the default prefix (/usr/local)
./download.sh
./install.sh
You can also compile each dependency, one by one:
......@@ -108,7 +111,7 @@ You can also compile each dependency, one by one:
make
make install
Note: if you install portaudio in /usr/local, don't forget to set pkg-config path with:
Note: if you install any package in /usr/local, don't forget to set pkg-config path with:
export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig/
......@@ -175,8 +178,16 @@ How to enable IAX support?
--------------------------
Go inside libs directory and execute ./libiax2.sh script.
Run ./configure with --enable-iax2 option.
Then, run ./configure with --enable-iax2 option.
Debugging SFLPhone
------------------
You can use the --with-debug option with configure
./configure --with-debug
make
cd src
PATH=. ./gui/qt/sflphone-qt
Run-time troubleshooting
......@@ -219,7 +230,7 @@ Short description of content of source tree
audiodriver, rtp layer, audio codec ulaw, alaw and gsm.
- src/audio/gsm/ contains the implementation of gsm audiocodec library.
- src/audio/pacpp/ implements PortAudioCpp, a native C++ binding of
PortAudio V19.
PortAudio V19. (remove in sflphone 0.7)
- src/gui/ is the old directory that contains all about different user
interface.
- src/gui/server is the directory that talk (tcp socket on port 3999) to
......
......@@ -7,6 +7,7 @@ Management of account (add, remove, ...)
Management of exceptions
Remove all warnings in compilation
Better handling for an reINVITE request. (done?)
Mono channel, float for portaudio
For project dependencies:
------------------------
......
......@@ -129,16 +129,22 @@ dnl Check for exosip2
LP_CHECK_EXOSIP2
SFLPHONE_LIBS="$SFLPHONE_LIBS $EXOSIP_LIBS"
dnl Check for samplerate
AC_CHECK_HEADER([samplerate.h], [
AC_CHECK_LIB(samplerate, src_simple, [with_samplerate=yes], [with_samplerate=no])
], [ with_samplerate=no ]
)
AM_CONDITIONAL(USE_SAMPLERATE, test x$with_samplerate = xyes)
dnl AC_CHECK_HEADER([samplerate.h], [
dnl AC_CHECK_LIB(samplerate, src_simple, [with_samplerate=yes], [with_samplerate=no])
dnl ], [ with_samplerate=no ]
dnl )
dnl AM_CONDITIONAL(USE_SAMPLERATE, test x$with_samplerate = xyes)
dnl Check for GNU ccRTP
PKG_PROG_PKG_CONFIG
LIBSAMPLERATE_MIN_VERSION=0.1.2
PKG_CHECK_MODULES(samplerate, samplerate >= ${LIBSAMPLERATE_MIN_VERSION})
SFLPHONE_CFLAGS="$SFLPHONE_CFLAGS $samplerate_CFLAGS"
SFLPHONE_LIBS="$SFLPHONE_LIBS $samplerate_LIBS"
LIBCCGNU2_MIN_VERSION=1.3.1
PKG_CHECK_MODULES(libccgnu2, libccgnu2 >= ${LIBCCGNU2_MIN_VERSION})
SFLPHONE_CFLAGS="$SFLPHONE_CFLAGS $libccgnu2_CFLAGS"
......
......@@ -25,14 +25,6 @@ IAXSOURCES =
IAXHEADERS =
endif
if USE_SAMPLERATE
SAMPLERATE_FLAG=-DUSE_SAMPLERATE
SAMPLERATE_LIB =-lsamplerate
else
SAMPLERATE_FLAG=
SAMPLERATE_LIB=
endif
SUBDIRS = audio config gui $(ZEROCONFDIR)
sflphoned_SOURCES = eventthread.cpp main.cpp voIPLink.cpp \
......
......@@ -12,14 +12,6 @@ SPEEX_FLAG=
SPEEX_LIB=
endif
if USE_SAMPLERATE
SAMPLERATE_FLAG=-DUSE_SAMPLERATE
SAMPLERATE_LIB =-lsamplerate
else
SAMPLERATE_FLAG=
SAMPLERATE_LIB=
endif
libaudio_la_SOURCES = alaw.cpp audiofile.cpp g711.cpp tonelist.cpp \
audiortp.cpp dtmf.cpp tone.cpp audiocodec.cpp audiolayer.cpp audiodevice.cpp dtmfgenerator.cpp gsmcodec.cpp \
tonegenerator.cpp ulaw.cpp codecDescriptor.cpp \
......
......@@ -33,6 +33,9 @@ public:
AudioCodec(int payload, const std::string &codecName);
virtual ~AudioCodec(void);
/**
* @return the number of bytes decoded
*/
virtual int codecDecode(short *, unsigned char *, unsigned int) = 0;
virtual int codecEncode(unsigned char *, short *, unsigned int) = 0;
......
......@@ -23,6 +23,9 @@
#include "audiofile.h"
#include "codecDescriptor.h"
#include <fstream>
#include <math.h>
#include <samplerate.h>
AudioFile::AudioFile()
: AudioLoop()
......@@ -38,12 +41,13 @@ AudioFile::~AudioFile()
delete _ulaw;
}
// load file in mono format
bool
AudioFile::loadFile(const std::string& filename, unsigned int nbChannel=2)
AudioFile::loadFile(const std::string& filename, unsigned int sampleRate=8000)
{
_nbChannel = (nbChannel==2) ? 2 : 1;
if (_filename == filename) {
// if the filename was already load, with the same samplerate
// we do nothing
if (_filename == filename && _sampleRate == sampleRate) {
return true;
} else {
// reset to 0
......@@ -54,6 +58,7 @@ AudioFile::loadFile(const std::string& filename, unsigned int nbChannel=2)
// no filename to load
if (filename.empty()) {
_debug("Unable to open audio file: filename is empty\n");
return false;
}
......@@ -61,6 +66,7 @@ AudioFile::loadFile(const std::string& filename, unsigned int nbChannel=2)
file.open(filename.c_str(), std::fstream::in);
if (!file.is_open()) {
// unable to load the file
_debug("Unable to open audio file %s\n", filename.c_str());
return false;
}
......@@ -71,6 +77,7 @@ AudioFile::loadFile(const std::string& filename, unsigned int nbChannel=2)
// allocate memory:
char fileBuffer[length];
// read data as a block:
file.read (fileBuffer,length);
file.close();
......@@ -80,29 +87,61 @@ AudioFile::loadFile(const std::string& filename, unsigned int nbChannel=2)
// expandedsize should be exactly two time more, else failed
int16 monoBuffer[length];
unsigned int expandedsize = _ulaw->codecDecode (monoBuffer, (unsigned char *) fileBuffer, length);
if (expandedsize != length*sizeof(int16)) {
if (expandedsize != length*2) {
_debug("Audio file error on loading audio file!");
return false;
}
unsigned int nbSampling = expandedsize/sizeof(int16);
unsigned int int16size = expandedsize/sizeof(int16);
if (_nbChannel == 2) {
_size = int16size<<1; // multiply by two
_buffer = new int16[_size];
for(unsigned int i=0, k=0; i<int16size; i++) {
_buffer[k] = _buffer[k+1] = monoBuffer[i];
k+=2;
// we need to change the sample rating here:
// case 1: we don't have to resample : only do splitting and convert
if ( sampleRate == 8000 ) {
// just s
_size = nbSampling;
_buffer = new SFLDataFormat[_size];
// src to dest
for(unsigned int i=0; i<nbSampling; i++) {
_buffer[i] = SFLConvertInt16(monoBuffer[i]);
}
} else {
// copy the mono buffer to a mono buffer
_size = int16size;
_buffer = new int16[_size];
// src to dest
bcopy(monoBuffer, _buffer, expandedsize);
// case 2: we need to convert it and split it
// convert here
double factord = (double)sampleRate / 8000;
float* floatBufferIn = new float[nbSampling];
int sizeOut = (int)(ceil(factord*nbSampling));
src_short_to_float_array(monoBuffer, floatBufferIn, nbSampling);
SFLDataFormat* bufferTmp = new SFLDataFormat[sizeOut];
SRC_DATA src_data;
src_data.data_in = floatBufferIn;
src_data.input_frames = nbSampling;
src_data.output_frames = sizeOut;
src_data.src_ratio = factord;
#ifdef DATAFORMAT_IS_FLOAT
// case number 2.1: the output is float32 : convert directly in _bufferTmp
src_data.data_out = bufferTmp;
src_simple (&src_data, SRC_SINC_BEST_QUALITY, 1);
#else
// case number 2.2: the output is int16 : convert and change to int16
float* floatBufferOut = new float[sizeOut];
src_data.data_out = floatBufferOut;
src_simple (&src_data, SRC_SINC_BEST_QUALITY, 1);
src_float_to_short_array(floatBufferOut, bufferTmp, src_data.output_frames_gen);
delete [] floatBufferOut;
#endif
delete [] floatBufferIn;
nbSampling = src_data.output_frames_gen;
// if we are in mono, we send the bufferTmp location and don't delete it
// else we split the audio in 2 and put it into buffer
_size = nbSampling;
_buffer = bufferTmp; // just send the buffer pointer;
bufferTmp = 0;
}
return true;
}
......@@ -35,7 +35,7 @@ public:
AudioFile();
~AudioFile();
bool loadFile(const std::string& filename, unsigned int nbChannel/*=2*/);
bool loadFile(const std::string& filename, unsigned int sampleRate/*=8000*/);
void start() { _start = true; }
void stop() { _start = false; }
bool isStarted() { return _start; }
......
......@@ -25,29 +25,67 @@
#include "../global.h"
#include "../manager.h"
AudioLayer::AudioLayer()
//#define SFL_TEST
//#define SFL_TEST_SINE
#ifdef SFL_TEST_SINE
#include <cmath>
#endif
AudioLayer::AudioLayer(ManagerImpl* manager)
: _urgentRingBuffer(SIZEBUF)
, _mainSndRingBuffer(SIZEBUF)
, _micRingBuffer(SIZEBUF)
, _stream(NULL)
, _errorMessage("")
, _manager(manager)
{
_sampleRate = 8000;
_inChannel = 1;
_outChannel = 1;
_inChannel = 1; // don't put in stereo
_outChannel = 1; // don't put in stereo
try {
portaudio::AutoSystem autoSys;
portaudio::System::initialize();
}
catch (const portaudio::PaException &e) {
setErrorMessage(e.paErrorText());
}
catch (const portaudio::PaCppException &e) {
setErrorMessage(e.what());
} // std::runtime_error &e (e.what())
catch (...) {
setErrorMessage("Unknown type error in portaudio initialization");
}
#ifdef SFL_TEST_SINE
leftPhase_ = 0;
tableSize_ = 200;
const double PI = 3.14159265;
table_ = new float[tableSize_];
for (int i = 0; i < tableSize_; ++i)
{
table_[i] = 0.125f * (float)sin(((double)i/(double)tableSize_)*PI*2.);
_debug("%9.8f\n", table_[i]);
}
#endif
}
// Destructor
AudioLayer::~AudioLayer (void)
{
stopStream();
closeStream();
try {
portaudio::System::terminate();
} catch (const portaudio::PaException &e) {
_debug("! AL: Catch an exception when portaudio tried to terminate\n");
}
closeStream();
#ifdef SFL_TEST_SINE
delete [] table_;
#endif
}
void
......@@ -72,40 +110,117 @@ AudioLayer::openDevice (int indexIn, int indexOut, int sampleRate)
{
closeStream();
_sampleRate = sampleRate;
int portaudioFramePerBuffer = FRAME_PER_BUFFER; //=FRAME_PER_BUFFER; //= paFramesPerBufferUnspecified;
int nbDevice = getDeviceCount();
if (nbDevice == 0) {
_debug("Portaudio detect no sound card.");
return;
} else {
if (indexIn >= nbDevice) {
_debug(" Portaudio auto-select device #0 for input because device #%02d is not found\n", indexIn);
indexIn = 0;
}
if (indexOut >= nbDevice) {
_debug(" Portaudio auto-select device #0 for output because device #%02d is not found\n", indexOut);
indexOut = 0;
}
_debug(" Setting audiolayer: device in=%2d, out=%2d\n", indexIn, indexOut);
_debug(" : nb channel in=%2d, out=%2d\n", _inChannel, _outChannel);
_debug(" : sample rate=%5d, format=%s\n", _sampleRate, SFLPortaudioFormatString);
_debug(" : frame per buffer=%d\n", portaudioFramePerBuffer);
}
try {
// Set up the parameters required to open a (Callback)Stream:
portaudio::DirectionSpecificStreamParameters
outParams(portaudio::System::instance().deviceByIndex(indexOut),
_outChannel, portaudio::INT16, true,
portaudio::System::instance().deviceByIndex(indexOut).defaultLowOutputLatency(),
NULL);
portaudio::DirectionSpecificStreamParameters
inParams(portaudio::System::instance().deviceByIndex(indexIn),
_inChannel, portaudio::INT16, true,
_inChannel, SFLPortaudioFormat, true,
portaudio::System::instance().deviceByIndex(indexIn).defaultLowInputLatency(),
NULL);
#ifdef USE_SAMPLERATE
_sampleRate = sampleRate;
#else
_sampleRate = 8000;
#endif
portaudio::DirectionSpecificStreamParameters outParams(
portaudio::System::instance().deviceByIndex(indexOut),
_outChannel, SFLPortaudioFormat, true,
portaudio::System::instance().deviceByIndex(indexOut).defaultLowOutputLatency(),
NULL);
// we could put paFramesPerBufferUnspecified instead of FRAME_PER_BUFFER to be variable
portaudio::StreamParameters const params(inParams, outParams,
_sampleRate, FRAME_PER_BUFFER /*paFramesPerBufferUnspecified*/, paNoFlag /*paPrimeOutputBuffersUsingStreamCallback | paNeverDropInput*/);
// like audacity
// DON'T USE paFramesPerBufferUnspecified, it's 32, instead of 160 for FRAME_PER_BUFFER
// DON'T USE paDitherOff or paClipOff,
// FRAME_PER_BUFFER | paFramesPerBufferUnspecified
// paNoFlag | paClipOff || paDitherOff | paPrimeOutputBuffersUsingStreamCallback | paNeverDropInput
portaudio::StreamParameters const params(
inParams,
outParams,
_sampleRate, portaudioFramePerBuffer, paClipOff);
// Create (and open) a new Stream, using the AudioLayer::audioCallback
ost::MutexLock guard(_mutex);
_stream = new portaudio::MemFunCallbackStream<AudioLayer>(params,
*this,
&AudioLayer::audioCallback);
#ifdef SFL_TEST
_stream = new portaudio::MemFunCallbackStream<AudioLayer>(params, *this, &AudioLayer::miniAudioCallback);
#else
_stream = new portaudio::MemFunCallbackStream<AudioLayer>(params,*this, &AudioLayer::audioCallback);
#endif
}
catch (const portaudio::PaException &e) {
setErrorMessage(e.paErrorText());
_debug("Portaudio openDevice error: %s\n", e.paErrorText());
}
catch (const portaudio::PaCppException &e) {
setErrorMessage(e.what());
_debug("Portaudio openDevice error: %s\n", e.what());
} // std::runtime_error &e (e.what())
catch (...) {
setErrorMessage("Unknown type error in portaudio openDevice");
_debug("Portaudio openDevice: unknown error\n");
}
}
int
AudioLayer::getDeviceCount()
{
return portaudio::System::instance().deviceCount();
}
AudioDevice*
AudioLayer::getAudioDeviceInfo(int index, int ioDeviceMask)
{
try {
portaudio::System& sys = portaudio::System::instance();
portaudio::Device& device = sys.deviceByIndex(index);
int deviceIsSupported = false;
if (ioDeviceMask == InputDevice && !device.isOutputOnlyDevice()) {
deviceIsSupported = true;
} else if (ioDeviceMask == OutputDevice && !device.isInputOnlyDevice()) {
deviceIsSupported = true;
} else if (device.isFullDuplexDevice()) {
deviceIsSupported = true;
}
if (deviceIsSupported) {
AudioDevice* audiodevice = new AudioDevice(index, device.hostApi().name(), device.name());
if (audiodevice) {
audiodevice->setRate(device.defaultSampleRate());
}
return audiodevice;
}
} catch (...) {
throw;
return 0;
}
return 0;
}
void
AudioLayer::startStream(void)
{
......@@ -129,6 +244,7 @@ AudioLayer::startStream(void)
void
AudioLayer::stopStream(void)
{
_debug("- AL Action: Stopping sound stream\n");
try {
ost::MutexLock guard(_mutex);
if (_stream && !_stream->isStopped()) {
......@@ -254,76 +370,80 @@ AudioLayer::audioCallback (const void *inputBuffer, void *outputBuffer,
(void) timeInfo;
(void) statusFlags;
int16 *in = (int16 *) inputBuffer;
int16 *out = (int16 *) outputBuffer;
SFLDataFormat *in = (SFLDataFormat *) inputBuffer;
SFLDataFormat *out = (SFLDataFormat *) outputBuffer;
int toGet;
int toPut;
int urgentAvail; // number of int16 right and int16 left
int normalAvail; // number of int16 right and int16 left
int urgentAvail; // number of data right and data left
int normalAvail; // number of data right and data left
int micAvailPut;
unsigned short spkrVolume = Manager::instance().getSpkrVolume();
unsigned short micVolume = Manager::instance().getMicVolume();
unsigned short spkrVolume = _manager->getSpkrVolume();
unsigned short micVolume = _manager->getMicVolume();
// AvailForGet tell the number of chars inside the buffer
// framePerBuffer are the number of int16 for one channel (left)
// framePerBuffer are the number of data for one channel (left)
urgentAvail = _urgentRingBuffer.AvailForGet();
if (urgentAvail > 0) {
// Urgent data (dtmf, incoming call signal) come first.
toGet = (urgentAvail < (int)(framesPerBuffer * sizeof(int16) * _outChannel)) ? urgentAvail : framesPerBuffer * sizeof(int16) * _outChannel;
toGet = (urgentAvail < (int)(framesPerBuffer * sizeof(SFLDataFormat))) ? urgentAvail : framesPerBuffer * sizeof(SFLDataFormat);
_urgentRingBuffer.Get(out, toGet, spkrVolume);
// Consume the regular one as well (same amount of bytes)
_mainSndRingBuffer.Discard(toGet);
} else {
AudioLoop* tone = Manager::instance().getTelephoneTone();
AudioLoop* tone = _manager->getTelephoneTone();
if ( tone != 0) {
tone->getNext(out, framesPerBuffer*_outChannel, spkrVolume);
} else if ( (tone=Manager::instance().getTelephoneFile()) != 0 ) {
tone->getNext(out, framesPerBuffer*_outChannel, spkrVolume);
tone->getNext(out, framesPerBuffer, spkrVolume);
} else if ( (tone=_manager->getTelephoneFile()) != 0 ) {
tone->getNext(out, framesPerBuffer, spkrVolume);
} else {
// If nothing urgent, play the regular sound samples
normalAvail = _mainSndRingBuffer.AvailForGet();
toGet = (normalAvail < (int)(framesPerBuffer * sizeof(int16) * _outChannel)) ? normalAvail : framesPerBuffer * sizeof(int16) * (int)_outChannel;
toGet = (normalAvail < (int)(framesPerBuffer * sizeof(SFLDataFormat))) ? normalAvail : framesPerBuffer * sizeof(SFLDataFormat);
if (toGet) {
_mainSndRingBuffer.Get(out, toGet, spkrVolume);
} else {
bzero(out, framesPerBuffer * sizeof(int16) * _outChannel);
bzero(out, framesPerBuffer * sizeof(SFLDataFormat));
}
}
}
// Additionally handle the mic's audio stream
micAvailPut = _micRingBuffer.AvailForPut();
toPut = (micAvailPut <= (int)(framesPerBuffer * sizeof(int16) * _inChannel)) ? micAvailPut : framesPerBuffer * sizeof(int16) * _inChannel;
toPut = (micAvailPut <= (int)(framesPerBuffer * sizeof(SFLDataFormat))) ? micAvailPut : framesPerBuffer * sizeof(SFLDataFormat);
_micRingBuffer.Put(in, toPut, micVolume);
return paContinue;
}
unsigned int
AudioLayer::convert(int16* fromBuffer, int fromChannel, unsigned int fromSize, int16** toBuffer, int toChannel) {
if (fromChannel == toChannel ) { // 1=>1 or 2=>2
// src, dest, size in bytes
*toBuffer = fromBuffer;
//bcopy(fromBuffer, *toBuffer, fromSize*sizeof(int16));
return fromSize;
} else if (fromChannel > toChannel ) { // 2 => 1
unsigned int toSize = fromSize>>1; // divise by 2
for(unsigned int m=0, s=0; m<toSize; m++) {
s = m<<1;
(*toBuffer)[m] = (int16)(0.5f*(fromBuffer[s] + fromBuffer[s+1]));
}
return toSize;
} else { // (fromChannel > toChannel ) { // 1 => 2
for(unsigned int m=0, s=0; m<fromSize; m++) {
s = m<<1;
(*toBuffer)[s] = (*toBuffer)[s+1] = fromBuffer[m];
int
AudioLayer::miniAudioCallback (const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo *timeInfo,
PaStreamCallbackFlags statusFlags) {
(void) timeInfo;
(void) statusFlags;
_debug("mini audio callback!!\n");
#ifdef SFL_TEST_SINE
assert(outputBuffer != NULL);
float *out = static_cast<float *>(outputBuffer);
for (unsigned int i = 0; i < framesPerBuffer; ++i) {
out[i] = table_[leftPhase_];
leftPhase_ += 1;
if (leftPhase_ >= tableSize_) {
leftPhase_ -= tableSize_;
}
return fromSize<<1; // multiply by 2
}
return fromSize;
#else
SFLDataFormat *out = (SFLDataFormat *) outputBuffer;
AudioLoop* tone = _manager->getTelephoneTone();
if ( tone != 0) {
//_debug("Frames Per Buffer: %d\n", framesPerBuffer);
tone->getNext(out, framesPerBuffer, 100);
}
#endif
return paContinue;
}
......@@ -27,14 +27,16 @@
#include "../global.h"
#include "ringbuffer.h"
#include "audiodevice.h"
#define FRAME_PER_BUFFER 160
class RingBuffer;
class ManagerImpl;
class AudioLayer {
public:
AudioLayer();
AudioLayer(ManagerImpl* manager);
~AudioLayer(void);
/*
......@@ -57,15 +59,10 @@ public:
int getMic(void *, int);
void flushMic();
/**
* Try to convert a int16 fromBuffer into a int16 to Buffer
* If the channel are the same, it only pass the address and the size of the from Buffer
* Else, it double or reduce by 2 the fromBuffer with a 0.5 conversion
*/
unsigned int convert(int16* fromBuffer, int fromChannel, unsigned int fromSize, int16** toBuffer, int toChannel);
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; }
......@@ -75,8 +72,9 @@ public:
* accessor only
*/
unsigned int getSampleRate() { return _sampleRate; }
unsigned int getInChannel() { return _inChannel; }
unsigned int getOutChannel() { return _outChannel; }
int getDeviceCount();
AudioDevice* getAudioDeviceInfo(int index, int ioDeviceMask);
enum IODEVICE {InputDevice=0x01, OutputDevice=0x02 };
......@@ -85,8 +83,11 @@ private:
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
......@@ -94,18 +95,21 @@ private:
unsigned int _sampleRate;
/**
* Input channel (mic) should be 2 stereo or 1 mono
* Input channel (mic) should be 1 mono
*/
unsigned int _inChannel; // mic
/**
* Output channel (stereo) should be 2 stereo or 1 mono
* Output channel (stereo) should be 1 mono
*/
unsigned int _outChannel; // speaker
std::string _errorMessage;
// portaudio::AutoSystem autoSys;
ost::Mutex _mutex;
float *table_;
int tableSize_;
int leftPhase_;
};
#endif // _AUDIO_LAYER_H_
......
......@@ -28,16 +28,16 @@ AudioLoop::AudioLoop()
_buffer = 0;
_pos = 0;
_size = 0;
_nbChannel = 1;
_sampleRate = 0;
}
AudioLoop::~AudioLoop()
{
delete _buffer; _buffer = 0;
delete [] _buffer; _buffer = 0;
}
int
AudioLoop::getNext(int16* output, int nb, short volume)
AudioLoop::getNext(SFLDataFormat* output, int nb, short volume)
{
int copied = 0;
int block;
......@@ -48,7 +48,7 @@ AudioLoop::getNext(int16* output, int nb, short volume)
block = _size-pos;
}
// src, dest, len
bcopy(_buffer+pos, output, block<<1); // short>char conversion
bcopy(_buffer+pos, output, block*sizeof(SFLDataFormat)); // short>char conversion
if (volume!=100) {
for (int i=0;i<block;i++) {
*output = (*output * volume)/100;
......
......@@ -39,17 +39,18 @@ public:
* @param nb of int16 to send
* @return the number of int16 sent (nb*2)
*/
int getNext(int16* output, int nb, short volume=100);
int getNext(SFLDataFormat* output, int nb, short volume=100);
void reset() { _pos = 0; }
unsigned int getMonoSize() { return _size*_nbChannel; }
unsigned int getMonoSize() { return _size; }
unsigned int getSize() { return _size; }
protected:
int16* _buffer;
SFLDataFormat* _buffer;
int _size; // number of int16 inside the buffer, not the delay
int _pos; // current position, set to 0, when initialize
int _nbChannel;
int _sampleRate; // last samplerate
};
#endif // __AUDIOLOOP_H__
......@@ -23,6 +23,7 @@
#include <ccrtp/rtp.h>
#include <assert.h>
#include <string>
#include <cstring>
#include "../global.h"
#include "../manager.h"
......@@ -32,9 +33,7 @@
#include "ringbuffer.h"
#include "../user_cfg.h"
#include "../sipcall.h"
#ifdef USE_SAMPLERATE
#include <samplerate.h>
#endif
////////////////////////////////////////////////////////////////////////////////
// AudioRtp
......@@ -61,7 +60,7 @@ AudioRtp::createNewSession (SIPCall *ca) {
// Start RTP Send/Receive threads
_symmetric = Manager::instance().getConfigInt(SIGNALISATION,SYMMETRIC) ? true : false;
_RTXThread = new AudioRtpRTX (ca, Manager::instance().getAudioDriver(), _symmetric);
_RTXThread = new AudioRtpRTX (ca, _symmetric);
try {
if (_RTXThread->start() != 0) {
......@@ -92,30 +91,27 @@ AudioRtp::closeRtpSession () {
////////////////////////////////////////////////////////////////////////////////
// AudioRtpRTX Class //
////////////////////////////////////////////////////////////////////////////////
AudioRtpRTX::AudioRtpRTX (SIPCall *sipcall, AudioLayer* driver, bool sym) {
AudioRtpRTX::AudioRtpRTX (SIPCall *sipcall, bool sym) {
setCancel(cancelDeferred);
time = new ost::Time();
_ca = sipcall;
_sym = sym;
_audioDevice = driver;
if (_audioDevice!=0) {
// _nbFrames = 20 * _audioDevice->getSampleRate()/1000; // 20 ms
_nbFrames = _audioDevice->getSampleRate()/50; // 20 ms / 1000
} else {
_nbFrames = RTP_FRAMES2SEND;
}
#ifdef USE_SAMPLERATE
_floatBufferIn = new float[_nbFrames*2];
_floatBufferOut = new float[_nbFrames*2];
#endif
// 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());
//_debug("AudioRtpRTX ctor : Local IP:port %s:%d\tsymmetric:%d\n", local_ip.getHostname(), _ca->getLocalAudioPort(), _sym);
if (!_sym) {
_sessionRecv = new ost::RTPSession(local_ip, _ca->getLocalAudioPort());
_sessionSend = new ost::RTPSession(local_ip, _ca->getLocalAudioPort());
......@@ -125,6 +121,7 @@ AudioRtpRTX::AudioRtpRTX (SIPCall *sipcall, AudioLayer* driver, bool sym) {
_sessionRecv = NULL;
_sessionSend = NULL;
}
}
AudioRtpRTX::~AudioRtpRTX () {
......@@ -137,22 +134,25 @@ AudioRtpRTX::~AudioRtpRTX () {
throw;
}
//_debug("terminate audiortprtx ended...\n");
_ca = NULL;
_ca = 0;
if (!_sym) {
delete _sessionRecv; _sessionRecv = NULL;
delete _sessionSend; _sessionSend = NULL;
delete _sessionRecv; _sessionRecv = 0;
delete _sessionSend; _sessionSend = 0;
} else {
delete _session; _session = NULL;
delete _session; _session = 0;
}
delete time; time = NULL;
delete [] _intBuffer8000; _intBuffer8000 = 0;
delete [] _floatBuffer48000; _floatBuffer48000 = 0;
delete [] _floatBuffer8000; _floatBuffer8000 = 0;
delete [] _dataAudioLayer; _dataAudioLayer = 0;
delete [] _sendDataEncoded; _sendDataEncoded = 0;
delete [] _receiveDataDecoded; _receiveDataDecoded = 0;
#ifdef USE_SAMPLERATE
delete [] _floatBufferIn; _floatBufferIn = 0;
delete [] _floatBufferOut; _floatBufferOut = 0;
#endif
delete time; time = NULL;
}
void
......@@ -226,91 +226,100 @@ AudioRtpRTX::initAudioRtpSession (void)
}
void
AudioRtpRTX::sendSessionFromMic (unsigned char* data_to_send, int16* data_from_mic, int16* data_from_mic_to_codec, int timestamp)
AudioRtpRTX::sendSessionFromMic(int timestamp)
{
// STEP:
// 1. get data from mic
// 2. convert it to int16 - good sample, good rate
// 3. encode it
// 4. send it
try {
if (_ca==0) { return; } // no call, so we do nothing
short sizeOfData = sizeof(int16);
AudioLayer* audiolayer = Manager::instance().getAudioDriver();
int availBytesFromMic = audiolayer->canGetMic();
int fromChannel = audiolayer->getInChannel();
int toChannel = fromChannel;
if (!audiolayer) { return; }
AudioCodec* audiocodec = _ca->getAudioCodec();
if (audiocodec!=0) {
toChannel = audiocodec->getChannel();
}
if (!audiocodec) { return; }
// we have to get 20ms of data from the mic *20/1000 = /50
// rate/50 shall be lower than RTP_20S_48KHZ_MAX
int maxBytesToGet = audiolayer->getSampleRate()/50*sizeof(SFLDataFormat);
int maxBytesToGet = _nbFrames * fromChannel * sizeOfData; // * channels * int16/byte
// available bytes inside ringbuffer
int availBytesFromMic = audiolayer->canGetMic();
// take the lower
int bytesAvail;
if (availBytesFromMic < maxBytesToGet) {
bytesAvail = availBytesFromMic;
} else {
bytesAvail = maxBytesToGet;
}
int bytesAvail = (availBytesFromMic < maxBytesToGet) ? availBytesFromMic : maxBytesToGet;
// Get bytes from micRingBuffer to data_from_mic
audiolayer->getMic(data_from_mic, bytesAvail);
int nbInt16 = bytesAvail/sizeof(int16);
#ifdef USE_SAMPLERATE
// sample rate conversion here
if (audiocodec && audiolayer->getSampleRate() != audiocodec->getClockRate()) {
double factord = (double)audiocodec->getClockRate()/audiolayer->getSampleRate();
int nbSample = audiolayer->getMic(_dataAudioLayer, bytesAvail) / sizeof(SFLDataFormat);
int16* toSIP = 0;
if (audiolayer->getSampleRate() != audiocodec->getClockRate() && nbSample) {
SRC_DATA src_data;
src_data.data_in = _floatBufferIn;
src_data.data_out = _floatBufferOut;
src_data.input_frames = nbInt16/fromChannel;
src_data.output_frames = _nbFrames;
#ifdef DATAFORMAT_IS_FLOAT
src_data.data_in = _dataAudioLayer;
#else
src_short_to_float_array(_dataAudioLayer, _floatBuffer48000, nbSample);
src_data.data_in = _floatBuffer48000;
#endif
double factord = (double)audiocodec->getClockRate()/audiolayer->getSampleRate();
src_data.src_ratio = factord;
src_short_to_float_array(data_from_mic, _floatBufferIn, nbInt16);
src_simple (&src_data, SRC_SINC_MEDIUM_QUALITY, fromChannel);
src_float_to_short_array (_floatBufferOut, data_from_mic, src_data.output_frames_gen*fromChannel);
nbInt16 = src_data.output_frames_gen * fromChannel;
}
src_data.input_frames = nbSample;
src_data.output_frames = RTP_20S_8KHZ_MAX;
src_data.data_out = _floatBuffer8000;
src_simple (&src_data, SRC_SINC_BEST_QUALITY/*SRC_SINC_MEDIUM_QUALITY*/, 1); // 1 = channel
nbSample = src_data.output_frames_gen;
//if (nbSample > RTP_20S_8KHZ_MAX) { _debug("Alert from mic, nbSample %d is bigger than expected %d\n", nbSample, RTP_20S_8KHZ_MAX); }
src_float_to_short_array (_floatBuffer8000, _intBuffer8000, nbSample);
toSIP = _intBuffer8000;
} else {
#ifdef DATAFORMAT_IS_FLOAT
// convert _receiveDataDecoded to float inside _receiveData
src_float_to_short_array(_dataAudioLayer, _intBuffer8000, nbSample);
toSIP = _intBuffer8000;
//if (nbSample > RTP_20S_8KHZ_MAX) { _debug("Alert from mic, nbSample %d is bigger than expected %d\n", nbSample, RTP_20S_8KHZ_MAX); }
#else
toSIP = _dataAudioLayer; // int to int
#endif
}
unsigned int toSize = audiolayer->convert(data_from_mic, fromChannel, nbInt16, &data_from_mic_to_codec, toChannel);
if ( toSize != (RTP_FRAMES2SEND * toChannel) ) {
if ( nbSample < RTP_20S_8KHZ_MAX ) {
// fill end with 0...
bzero(data_from_mic_to_codec + toSize*sizeOfData, (RTP_FRAMES2SEND*toChannel-toSize)*sizeOfData);
toSize = RTP_FRAMES2SEND * toChannel;
//_debug("begin: %p, nbSample: %d\n", toSIP, nbSample);
//_debug("has to fill: %d chars at %p\n", (RTP_20S_8KHZ_MAX-nbSample)*sizeof(int16), toSIP + nbSample);
memset(toSIP + nbSample, 0, (RTP_20S_8KHZ_MAX-nbSample)*sizeof(int16));
//nbSample = RTP_20S_8KHZ_MAX;
}
// Encode acquired audio sample
if ( audiocodec != NULL ) {
// for the mono: range = 0 to RTP_FRAME2SEND * sizeof(int16)
// codecEncode(char *dest, int16* src, size in bytes of the src)
int compSize = audiocodec->codecEncode(data_to_send, data_from_mic_to_codec, toSize*sizeOfData);
int compSize = audiocodec->codecEncode(_sendDataEncoded, toSIP, nbSample*sizeof(int16));
// encode divise by two
// Send encoded audio sample over the network
if (compSize > RTP_FRAMES2SEND) { _debug("! ARTP: %d should be %d\n", compSize, _nbFrames);}
//fprintf(stderr, "S");
if (compSize > RTP_20S_8KHZ_MAX) { _debug("! ARTP: %d should be %d\n", compSize, RTP_20S_8KHZ_MAX);}
if (!_sym) {
_sessionSend->putData(timestamp, data_to_send, compSize);
_sessionSend->putData(timestamp, _sendDataEncoded, compSize);
} else {
_session->putData(timestamp, data_to_send, compSize);
}
_session->putData(timestamp, _sendDataEncoded, compSize);
}
toSIP = 0;
} catch(...) {
_debugException("! ARTP: sending failed");
throw;
}
}
void
AudioRtpRTX::receiveSessionForSpkr (int16* data_for_speakers_stereo, int16* data_for_speakers_recv, int& countTime)
AudioRtpRTX::receiveSessionForSpkr (int& countTime)
{
if (_ca == 0) { return; }
try {
AudioLayer* audiolayer = Manager::instance().getAudioDriver();
if (!audiolayer) { return; }
const ost::AppDataUnit* adu = NULL;
// Get audio data stream
......@@ -323,49 +332,66 @@ AudioRtpRTX::receiveSessionForSpkr (int16* data_for_speakers_stereo, int16* data
return;
}
int payload = adu->getType();
unsigned char* data = (unsigned char*)adu->getData();
unsigned int size = adu->getSize();
int payload = adu->getType(); // codec type
unsigned char* data = (unsigned char*)adu->getData(); // data in char
unsigned int size = adu->getSize(); // size in char
if ( size > RTP_20S_8KHZ_MAX ) {
_debug("We have received from RTP a packet larger than expected: %s VS %s\n", size, RTP_20S_8KHZ_MAX);
_debug("The packet size has been cropped\n");
size=RTP_20S_8KHZ_MAX;
}
// Decode data with relevant codec
int toPut = 0;
AudioCodec* audiocodec = _ca->getCodecMap().getCodec((CodecType)payload);
if (audiocodec != 0) {
// codecDecode(int16 *dest, char* src, size in bytes of the src)
// decode multiply by two
// decode multiply by two, so the number of byte should be double
// size shall be RTP_FRAME2SEND or lower
int expandedSize = audiocodec->codecDecode(data_for_speakers_recv, data, size);
int expandedSize = audiocodec->codecDecode(_receiveDataDecoded, data, size);
int nbInt16 = expandedSize/sizeof(int16);
if (nbInt16 > RTP_20S_8KHZ_MAX) {
_debug("We have decoded a RTP packet larger than expected: %s VS %s. crop\n", nbInt16, RTP_20S_8KHZ_MAX);
nbInt16=RTP_20S_8KHZ_MAX;
}
int toChannel = audiolayer->getOutChannel();
int fromChannel = audiocodec->getChannel();
SFLDataFormat* toAudioLayer;
int nbSample = nbInt16;
int nbSampleMaxRate = nbInt16 * 6; // TODO: change it
#ifdef USE_SAMPLERATE
if ( audiolayer->getSampleRate() != audiocodec->getClockRate() ) {
if ( audiolayer->getSampleRate() != audiocodec->getClockRate() && nbSample) {
// convert here
double factord = (double)audiolayer->getSampleRate()/audiocodec->getClockRate();
SRC_DATA src_data;
src_data.data_in = _floatBufferIn;
src_data.data_out = _floatBufferOut;
src_data.input_frames = nbInt16/fromChannel;
src_data.output_frames = _nbFrames;
src_data.data_in = _floatBuffer8000;
src_data.data_out = _floatBuffer48000;
src_data.input_frames = nbSample;
src_data.output_frames = nbSampleMaxRate;
src_data.src_ratio = factord;
src_short_to_float_array(data_for_speakers_recv, _floatBufferIn, nbInt16);
src_simple (&src_data, SRC_SINC_MEDIUM_QUALITY, fromChannel);
src_float_to_short_array(_floatBufferOut, data_for_speakers_recv, src_data.output_frames_gen*fromChannel);
nbInt16 = src_data.output_frames_gen*fromChannel;
}
src_short_to_float_array(_receiveDataDecoded, _floatBuffer8000, nbSample);
src_simple (&src_data, SRC_SINC_BEST_QUALITY/*SRC_SINC_MEDIUM_QUALITY*/, 1); // 1=mono channel
nbSample = ( src_data.output_frames_gen > RTP_20S_48KHZ_MAX) ? RTP_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
toPut = audiolayer->convert(data_for_speakers_recv, fromChannel, nbInt16, &data_for_speakers_stereo, toChannel);
// If the current call is the call which is answered
// Set decoded data to sound device
// expandedSize is in mono/bytes, since we double in stereo, we send two time more
//fprintf(stderr, "R");
audiolayer->putMain(data_for_speakers_stereo, toPut * sizeof(int16));
//Manager::instance().getAudioDriver()->startStream();
} 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
}
audiolayer->putMain(toAudioLayer, nbSample * sizeof(SFLDataFormat));
//_debug("ARTP: %d\n", nbSample * sizeof(SFLDataFormat));
// Notify (with a beep) an incoming call when there is already a call
countTime += time->getSecond();
......@@ -393,24 +419,10 @@ AudioRtpRTX::run () {
//encoding before sending
AudioLayer *audiolayer = Manager::instance().getAudioDriver();
int16 *data_from_mic = new int16[_nbFrames*audiolayer->getInChannel()];
int16 *data_from_mic_to_codec = new int16[_nbFrames*2]; // 2 = max channel
unsigned char *char_to_send = new unsigned char[_nbFrames]; // two time more for codec
//spkr, we receive from rtp in mono and we send in stereo
//decoding after receiving
// we could receive in stereo too...
int16 *data_for_speakers_recv = new int16[_nbFrames*2];
int16 *data_for_speakers_stereo = new int16[_nbFrames*2];
try {
//_debug("AudioRTP Thread is running\n");
// Init the session
initAudioRtpSession();
// flush stream:
// start running the packet queue scheduler.
//_debug("AudioRTP Thread started\n");
if (!_sym) {
......@@ -435,13 +447,13 @@ AudioRtpRTX::run () {
////////////////////////////
// Send session
////////////////////////////
sendSessionFromMic(char_to_send, data_from_mic, data_from_mic_to_codec, timestamp);
timestamp += RTP_FRAMES2SEND;
sendSessionFromMic(timestamp);
timestamp += RTP_20S_8KHZ_MAX;
////////////////////////////
// Recv session
////////////////////////////
receiveSessionForSpkr(data_for_speakers_stereo, data_for_speakers_recv, countTime);
receiveSessionForSpkr(countTime);
// Let's wait for the next transmit cycle
Thread::sleep(TimerPort::getTimer());
......@@ -458,11 +470,6 @@ AudioRtpRTX::run () {
_debugException("* ARTP Action: Stop");
throw;
}
delete [] data_for_speakers_stereo; data_for_speakers_stereo = 0;
delete [] data_for_speakers_recv; data_for_speakers_recv = 0;
delete [] char_to_send; char_to_send = 0;
delete [] data_from_mic_to_codec; data_from_mic_to_codec = 0;
delete [] data_from_mic; data_from_mic = 0;
}
......
......@@ -26,9 +26,12 @@
#include <ccrtp/rtp.h>
#include <cc++/numbers.h>
#define RTP_FRAMES2SEND 160
class AudioLayer;
#include "../global.h"
/** maximum of byte inside an incoming packet
* 8000 sampling/s * 20s/1000 = 160
*/
#define RTP_20S_8KHZ_MAX 160
#define RTP_20S_48KHZ_MAX 960
class SIPCall;
///////////////////////////////////////////////////////////////////////////////
......@@ -36,7 +39,7 @@ class SIPCall;
///////////////////////////////////////////////////////////////////////////////
class AudioRtpRTX : public ost::Thread, public ost::TimerPort {
public:
AudioRtpRTX (SIPCall *, AudioLayer*, bool);
AudioRtpRTX (SIPCall *, bool);
~AudioRtpRTX();
ost::Time *time; // For incoming call notification
......@@ -44,24 +47,32 @@ public:
private:
SIPCall* _ca;
AudioLayer* _audioDevice;
ost::RTPSession *_sessionSend;
ost::RTPSession *_sessionRecv;
ost::SymmetricRTPSession *_session;
ost::Semaphore _start;
bool _sym;
int _nbFrames;
#ifdef USE_SAMPLERATE
float *_floatBufferIn;
float *_floatBufferOut;
#endif
/** When we receive data, we decode it inside this buffer */
int16* _receiveDataDecoded;
/** When we send data, we encode it inside this buffer*/
unsigned char* _sendDataEncoded;
/** After that we send the data inside this buffer if there is a format conversion or rate conversion */
/** Also use for getting mic-ringbuffer data */
SFLDataFormat* _dataAudioLayer;
/** Buffer for 8000hz samples in conversion */
float32* _floatBuffer8000;
/** Buffer for 48000hz samples in conversion */
float32* _floatBuffer48000;
/** Buffer for 8000hz samples for mic conversion */
int16* _intBuffer8000;
void initAudioRtpSession(void);
// void sendSessionFromMic (unsigned char*, int16*, int16*, int, int);
void sendSessionFromMic (unsigned char*, int16*, int16*, int);
// void receiveSessionForSpkr (int16*, int16*, int, int&);
void receiveSessionForSpkr (int16*, int16*, int&);
void sendSessionFromMic(int);
void receiveSessionForSpkr(int&);
};
///////////////////////////////////////////////////////////////////////////////
......
......@@ -23,8 +23,8 @@
#include "dtmf.h"
DTMF::DTMF (unsigned int sampleRate, unsigned int nbChannel)
: dtmfgenerator(sampleRate, nbChannel)
DTMF::DTMF (unsigned int sampleRate)
: dtmfgenerator(sampleRate)
{
currentTone = 0;
newTone = 0;
......@@ -41,7 +41,7 @@ DTMF::startTone (char code)
}
bool
DTMF::generateDTMF (int16* buffer, size_t n)
DTMF::generateDTMF (SFLDataFormat* buffer, size_t n)
{
if (!buffer) return false;
......
......@@ -36,16 +36,16 @@ public:
* Create a new DTMF.
* @param samplingRate frequency of the sample (ex: 8000 hz)
*/
DTMF (unsigned int sampleRate, unsigned int nbChannel);
DTMF (unsigned int sampleRate);
~DTMF (void);
void startTone (char);
/**
* Copy the sound inside the int16* buffer
* @param buffer : a int16* buffer
* Copy the sound inside the sampling* buffer
* @param buffer : a SFLDataFormat* buffer
* @param n :
*/
bool generateDTMF (int16* buffer, size_t n);
bool generateDTMF (SFLDataFormat* buffer, size_t n);
char currentTone;
char newTone;
......
......@@ -72,9 +72,8 @@ const char* DTMFException::what() const throw()
/*
* Initialize the generator
*/
DTMFGenerator::DTMFGenerator(unsigned int sampleRate, unsigned int nbChannel) : tone("", sampleRate, nbChannel)
DTMFGenerator::DTMFGenerator(unsigned int sampleRate) : tone("", sampleRate)
{
_nbChannel = nbChannel;
_sampleRate = sampleRate;
state.offset = 0;
state.sample = 0;
......@@ -95,7 +94,7 @@ DTMFGenerator::~DTMFGenerator() {
/*
* Get n samples of the signal of code code
*/
void DTMFGenerator::getSamples(int16* buffer, size_t n, unsigned char code) throw(DTMFException) {
void DTMFGenerator::getSamples(SFLDataFormat* buffer, size_t n, unsigned char code) throw(DTMFException) {
size_t i;
if (!buffer) {
throw DTMFException("Invalid parameter value");
......@@ -140,7 +139,7 @@ void DTMFGenerator::getSamples(int16* buffer, size_t n, unsigned char code) thro
* Get next n samples (continues where previous call to
* genSample or genNextSamples stopped
*/
void DTMFGenerator::getNextSamples(int16* buffer, size_t n) throw(DTMFException)
void DTMFGenerator::getNextSamples(SFLDataFormat* buffer, size_t n) throw(DTMFException)
{
size_t i;
......@@ -163,11 +162,11 @@ void DTMFGenerator::getNextSamples(int16* buffer, size_t n) throw(DTMFException)
/*
* Generate a tone sample
*/
int16* DTMFGenerator::generateSample(unsigned char code) throw (DTMFException) {
int16* ptr;
SFLDataFormat* DTMFGenerator::generateSample(unsigned char code) throw (DTMFException) {
SFLDataFormat* ptr;
try {
ptr = new int16[_sampleRate*_nbChannel];
ptr = new SFLDataFormat[_sampleRate];
if (!ptr) {
throw new DTMFException("No memory left");
return 0;
......
......@@ -64,19 +64,18 @@ private:
*/
struct DTMFState {
unsigned int offset; // Offset in the sample currently being played
int16* sample; // Currently generated code
SFLDataFormat* sample; // Currently generated code
};
DTMFState state;
static const DTMFTone tones[NUM_TONES];
int16* samples[NUM_TONES]; // Generated samples
SFLDataFormat* samples[NUM_TONES]; // Generated samples
/**
* Sampling rate of generated dtmf
*/
int _sampleRate;
int _nbChannel;
Tone tone;
public:
......@@ -85,27 +84,27 @@ public:
* and can build one DTMF.
* @param sampleRate frequency of the sample (ex: 8000 hz)
*/
DTMFGenerator(unsigned int sampleRate, unsigned int nbChannel);
DTMFGenerator(unsigned int sampleRate);
~DTMFGenerator();
/*
* Get n samples of the signal of code code
* @param buffer a int16 pointer to an allocated buffer
* @param n number of int16 to get, should be lower or equal to buffer size
* @param buffer a SFLDataFormat pointer to an allocated buffer
* @param n number of sampling to get, should be lower or equal to buffer size
* @parma code dtmf code to get sound
*/
void getSamples(int16* buffer, size_t n, unsigned char code) throw (DTMFException);
void getSamples(SFLDataFormat* buffer, size_t n, unsigned char code) throw (DTMFException);
/*
* Get next n samples (continues where previous call to
* genSample or genNextSamples stopped
* @param buffer a int16 pointer to an allocated buffer
* @param n number of int16 to get, should be lower or equal to buffer size
* @param buffer a SFLDataFormat pointer to an allocated buffer
* @param n number of sampling to get, should be lower or equal to buffer size
*/
void getNextSamples(int16* buffer, size_t n) throw (DTMFException);
void getNextSamples(SFLDataFormat* buffer, size_t n) throw (DTMFException);
private:
int16* generateSample(unsigned char code) throw (DTMFException);
SFLDataFormat* generateSample(unsigned char code) throw (DTMFException);
};
......
......@@ -92,7 +92,7 @@ RingBuffer::Put(void* buffer, int toCopy, unsigned short volume) {
// put the data inside the buffer.
if (volume!=100) {
int16* src16 = (int16*)src;
SFLDataFormat* src16 = (SFLDataFormat*)src;
int int16len = (block >> 1);
for (int i=0; i < int16len; i++) { src16[i] = src16[i] * volume / 100; }
}
......@@ -142,7 +142,7 @@ RingBuffer::Get(void *buffer, int toCopy, unsigned short volume) {
block = mBufferSize - mStart;
if(volume!=100) {
int16* start = (int16*)(mBuffer + mStart);
SFLDataFormat* start = (SFLDataFormat*)(mBuffer + mStart);
int int16len = (block >> 1);
for (int i=0; i<int16len; i++) { start[i] = start[i] * volume / 100; }
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment