Commit 196df527 authored by llea's avatar llea

PortAudio library integration instead of alsa and oss

parent 7d410955
SFLphone (0.3.1) / 2005-05-27
SFLphone (0.3.1) / 2005-06-01
* Add PortAudio library to make easy sound portability
* Reorganisation of SFLphone architecture
* Handle error messages on screen
* Handle refused call
......
......@@ -4,6 +4,8 @@
# Author: Laurielle Lea (laurielle.lea@savoirfairelinux.com)
#
all:
cd stund; make
cd src/audio/portaudio; make
cd src/audio/gsm ; make
cd src; make
......@@ -14,6 +16,8 @@ uninstall:
cd src; make uninstall
clean:
cd src; make clean
cd stund; make clean
cd src/audio/portaudio; make clean
cd src/audio/gsm ; make clean
cd src; make clean
......@@ -33,10 +33,7 @@ CLASSIC_DIRS=/usr:/usr/local:/opt
usage () {
echo "Usage: $0 [options]"
echo "Options:
-prefix DIR Set install prefix
-oss Enable OSS support
-alsa Enable ALSA support
-macosx Enable MacOSX audio support [Not supported yet]"
-prefix DIR Set install prefix"
}
# Check if $1 is contained in $PATH-style $2. Optionally $3 is "-p" to print
......@@ -83,11 +80,11 @@ do
shift 2
;;
-oss)
DEFVARS="-DOSS ${DEFVARS}"
DEFVARS="-DAUDIO_OSS ${DEFVARS}"
shift
;;
-alsa)
DEFVARS="-DALSA ${DEFVARS}"
DEFVARS="-DAUDIO_ALSA ${DEFVARS}"
shift
;;
-help|--help|-h)
......
......@@ -17,13 +17,31 @@ SKINS = skins
RINGS = rings
METAL_SKINS = metal
INCPATH = -I. -I$(QTDIR)/include -I$(CCPPDIR)/include/cc++2 -I$(CCRTPDIR)/include -I$(OSIPDIR)/include -I$(EXOPSIP)/include -I/usr/include -Iaudio/gsm
# Platform-specific variables
HOSTMACH = $(shell uname -m | sed -e 's/ //g')
ifeq (${HOSTSYSTEM},PowerMacintosh)
MACHOPTS=-mpowerpc
HOSTDEFS=-DGUI_TEXT1 -DAUDIO_MACOSX
else
HOSTSYS = $(shell uname -s)
endif
ifeq (${HOSTSYS},Linux)
HOSTMACH = $(shell uname -m | sed -e 's/i.86/i386/')
HOSTLIBS=-lX11 -lXext -lasound -lqt-mt
# HOSTDEFS=-DGUI_TEXT1 -DAUDIO_OSS # eventually
HOSTDEFS=-DGUI_QT -DAUDIO_ALSA
ifeq (${HOSTMACH},i386)
MACHOPTS=-march=i386
endif
endif
CXXFLAGS = -pipe -Wall -W -g -pipe -march=i386 -mcpu=i686 -DQT_NO_DEBUG -DQT_SHARED -DQT_THREAD_SUPPORT -fpermissive -Wno-deprecated $(INCPATH)
INCPATH = -I. -I$(QTDIR)/include -I$(CCPPDIR)/include/cc++2 -I$(CCRTPDIR)/include -I$(OSIPDIR)/include -I$(EXOPSIP)/include -I/usr/include -Iaudio/gsm -Iaudio/portaudio/pa_common
CXXFLAGS = -pipe -Wall -W -g $(MACHOPTS) -pipe -DQT_NO_DEBUG -DQT_SHARED -DQT_THREAD_SUPPORT -fpermissive -Wno-deprecated $(INCPATH)
LIBS=-L$(QTDIR)/lib -L/usr/X11R6/lib -lqt-mt -lXext -lX11 -lm -L/opt/lib -losip2 -leXosip -lccrtp1 -lasound `$(CCPPDIR)/bin/ccgnu2-config --flags --stdlibs`
LIBS=-L$(QTDIR)/lib -L/usr/X11R6/lib -lm -L/opt/lib -losip2 -leXosip -lccrtp1 $(HOSTLIBS) `$(CCPPDIR)/bin/ccgnu2-config --flags --stdlibs`
EXTRALIBS=audio/gsm/libgsm.a
EXTRALIBS=audio/gsm/libgsm.a audio/portaudio/lib/libportaudio.a
CONFIGURE_CONF=$(shell ls ../configure.conf)
......@@ -35,6 +53,7 @@ OBJS = \
audio/audiodrivers.o \
audio/audiodriversalsa.o \
audio/audiodriversoss.o \
audio/audiodriversportaudio.o \
audio/audiortp.o \
audio/dtmf.o \
audio/dtmfgenerator.o \
......@@ -82,8 +101,8 @@ OBJS = \
udp.o
start: check prereq all
#start:check all
#start: check prereq all
start:check all
check:
ifeq ($(CONFIGURE_CONF),../configure.conf)
......@@ -93,7 +112,7 @@ else
endif
.cpp.o:
$(CXX) $(DEFVARS) $(CXXFLAGS) -c -o $@ $<
$(CXX) $(DEFVARS) -DAUDIO_PORTAUDIO $(CXXFLAGS) -c -o $@ $<
prereq: gui/qt/url_input.ui gui/qt/configurationpanel.ui
@echo "Making User Interface files..."
......
......@@ -18,11 +18,21 @@
*/
#include <endian.h>
#if defined(__APPLE__)
# include <machine/endian.h>
#else
# include <endian.h>
#endif
#include <string.h>
#include <iostream>
#include <string>
#include "portaudio/pa_common/portaudio.h"
#include "portaudio/pa_common/pa_converters.h"
#include "portaudio/pa_common/pa_dither.h"
#include "../global.h"
#include "audiocodec.h"
#include "../configuration.h"
......@@ -49,6 +59,29 @@ AudioCodec::getCodecName (void)
return _codecName;
}
void
AudioCodec::float32ToInt16 (float32* src, int16* dst, int size) {
PaUtilConverter* myconverter;
struct PaUtilTriangularDitherGenerator tdg;
PaUtil_InitializeTriangularDitherState (&tdg);
myconverter = PaUtil_SelectConverter (paFloat32, paInt16, paNoFlag);
if (myconverter != NULL) {
myconverter(dst, 1, src, 1, size, &tdg);
} else {
_debug("Format conversion is not supported\n");
}
}
void
AudioCodec::int16ToFloat32 (int16* src, float32* dst, int size) {
PaUtilConverter* myconverter;
myconverter = PaUtil_SelectConverter (paInt16, paFloat32, paNoFlag);
if (myconverter != NULL) {
myconverter(dst, 1, src, 1, size, NULL);
} else {
_debug("Format conversion is not supported\n");
}
}
......@@ -21,7 +21,8 @@
#define __CODEC_AUDIO_H__
#include <string>
#include <string>
#include "../global.h"
using namespace std;
......@@ -37,6 +38,8 @@ public:
void setCodecName (const string& codec);
string getCodecName (void);
void float32ToInt16 (float32* src, int16* dst, int size);
void int16ToFloat32 (int16* src, float32* dst, int size);
private:
string _codecName;
......
......@@ -44,7 +44,6 @@ public:
virtual int resetDevice (void) = 0;
virtual int writeBuffer (void) = 0;
virtual int readBuffer (void *, int) = 0;
virtual int readBuffer (int) = 0;
virtual unsigned int readableBytes (void) = 0;
......
......@@ -17,6 +17,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
//#if defined(AUDIO_ALSA)
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/time.h>
......@@ -237,4 +239,5 @@ AudioDriversALSA::resetDevice (void) {
return 0;
}
//#endif // defined(AUDIO_ALSA)
// EOF
......@@ -17,6 +17,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
//#ifdef AUDIO_ALSA
#ifndef _AUDIO_DRIVERS_ALSA_H_
#define _AUDIO_DRIVERS_ALSA_H_
......@@ -48,7 +50,6 @@ public:
int resetDevice (void);
int writeBuffer (void);
int readBuffer (void *, int);
int readBuffer (int) { return 0; }
unsigned int readableBytes (void) { return 0; }
private:
......@@ -59,3 +60,5 @@ private:
};
#endif // _AUDIO_DRIVERS_ALSA_H_
//#endif // defined(AUDIO_ALSA)
......@@ -20,6 +20,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if defined(AUDIO_OSS)
#include <errno.h>
#include <string.h>
#include <sys/ioctl.h>
......@@ -205,61 +207,6 @@ AudioDriversOSS::readBuffer (void *ptr, int bytes) {
return rc;
}
int
AudioDriversOSS::readBuffer (int bytes) {
if( devstate != DeviceOpened ) {
return -1;
}
audio_buf.resize(bytes);
ssize_t count = bytes;
short *buf;
buf = (short*)audio_buf.getData();
ssize_t rc;
rc = read (audio_fd, buf, count);
if (rc < 0) {
_debug ("rc < 0 read(): %s\n", strerror(errno));
}
else if (rc != count) {
_debug ("WARNING: asked microphone for %d got %d\n", count, rc);
}
return rc;
}
int
AudioDriversOSS::writeBuffer (void *ptr, int len) {
if (devstate != DeviceOpened ) {
error->errorName(DEVICE_NOT_OPEN, NULL);
return -1;
}
audio_buf_info info;
if (ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info) == 0 ) {
if (info.fragstotal - info.fragments > 15) {
// drop the fragment if the buffer starts to fill up
return 1;
}
}
// Loop into write() while buffer not complete.
for (;;) {
int a;
if ((a = write(audio_fd, ptr, len)) < 0) {
_debug ("write(): %s\n", strerror(errno));
break;
}
if (a > 0) {
return a;
break;
}
}
return 1;
}
int
AudioDriversOSS::writeBuffer (void) {
......@@ -323,4 +270,5 @@ AudioDriversOSS::readableBytes(void) {
return info.bytes;
}
#endif // defined(AUDIO_OSS)
......@@ -20,6 +20,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if defined(AUDIO_OSS)
#ifndef _AUDIO_DRIVERS_OSS_H
#define _AUDIO_DRIVERS_OSS_H
......@@ -38,10 +40,8 @@ public:
int initDevice (DeviceMode);
int resetDevice (void);
bool openDevice (int);
int writeBuffer (void *, int);
int writeBuffer (void);
int readBuffer (void *, int);
int readBuffer (int);
unsigned int readableBytes (void);
int audio_fd;
......@@ -51,3 +51,5 @@ private:
};
#endif // _AUDIO_DRIVERS_OSS_H
#endif // defined(AUDIO_OSS)
......@@ -27,6 +27,7 @@
#include "audiortp.h"
#include "../configuration.h"
#include "../manager.h"
#include "../global.h"
#include "../user_cfg.h"
#include "../sipcall.h"
#include "../stund/stun.h"
......@@ -65,17 +66,9 @@ AudioRtp::createNewSession (SipCall *ca) {
} else {
_symetric = true;
}
#ifdef ALSA
if (_manager->useAlsa()) {
_RTXThread = new AudioRtpRTX (ca, _manager->audiodriver,
_manager->audiodriverReadAlsa, _manager, _symetric);
}
#endif
if (!_manager->useAlsa()) {
_RTXThread = new AudioRtpRTX (ca, _manager->audiodriver, NULL,_manager,
_symetric);
}
_RTXThread = new AudioRtpRTX (ca, _manager->getAudioDriver(),
_manager, _symetric);
if (_RTXThread->start() != 0) {
return -1;
......@@ -96,25 +89,20 @@ AudioRtp::closeRtpSession (SipCall *ca) {
_RTXThread = NULL;
}
// Flush audio read buffer
_manager->audiodriver->resetDevice();
_manager->getAudioDriver()->stopStream();
}
}
////////////////////////////////////////////////////////////////////////////////
// AudioRtpRTX Class //
////////////////////////////////////////////////////////////////////////////////
AudioRtpRTX::AudioRtpRTX (SipCall *sipcall, AudioDrivers *driver,
AudioDrivers *read_driver, Manager *mngr, bool sym) {
AudioRtpRTX::AudioRtpRTX (SipCall *sipcall, AudioDriversPortAudio* driver,
Manager *mngr, bool sym) {
time = new Time();
_manager = mngr;
_ca = sipcall;
_sym =sym;
_audioDevice = driver;
#ifdef ALSA
if (_manager->useAlsa()) {
_audioDeviceRead = read_driver;
}
#endif
// TODO: Change bind address according to user settings.
InetHostAddress local_ip("0.0.0.0");
......@@ -152,20 +140,22 @@ AudioRtpRTX::~AudioRtpRTX () {
void
AudioRtpRTX::run (void) {
unsigned char *data_to_send;
short *data_mute;
short *data_from_mic;
short *data_from_mic_tmp;
int i,
compSize,
int16 *data_from_mic_int16;
float32 *data_mute;
float32 *data_from_mic;
float32 *data_from_mic_tmp;
int compSize,
timestamp;
int expandedSize;
short *data_for_speakers = NULL;
int countTime = 0;
data_for_speakers = new short[2048];
data_from_mic = new short[1024];
data_from_mic_tmp = new short[1024];
int16 *data_for_speakers = NULL;
float32 *data_for_speakers_float = NULL;
data_from_mic = new float32[1024];
data_from_mic_tmp = new float32[1024];
data_mute = new float32[1024];
data_to_send = new unsigned char[1024];
data_mute = new short[1024];
data_for_speakers = new int16[2048];
InetHostAddress remote_ip(_ca->getRemoteSdpAudioIp());
......@@ -238,47 +228,35 @@ AudioRtpRTX::run (void) {
// Send session
////////////////////////////
int size = 320;
if (!_manager->getCall(_ca->getId())->isOnMute()) {
#ifdef ALSA
if (_manager->useAlsa()) {
i = _audioDeviceRead->readBuffer (data_from_mic, size);
}
#endif
if (!_manager->useAlsa()) {
i = _audioDevice->readBuffer (data_from_mic, size);
}
}
else {
if (!_manager->getCall(_ca->getId())->isOnMute()) {
_manager->getAudioDriver()->mydata.dataIn = data_from_mic;
} else {
// When IP-phone user click on mute button, we read buffer of a
// temp buffer to avoid delay in sound.
#ifdef ALSA
if (_manager->useAlsa())
i = _audioDeviceRead->readBuffer (data_mute, size);
#endif
if (!_manager->useAlsa())
i = _audioDevice->readBuffer (data_mute, size);
}
// TODO : return an error because no sound
if (i < 0) {
break;
_manager->getAudioDriver()->mydata.dataIn = data_mute;
}
for (int j = 0; j < i; j++) {
for (int j = 0; j < size; j++) {
data_from_mic_tmp[j] = data_from_mic[j] *
_manager->getMicroVolume()/100;
}
// Convert float32 buffer to int16 to encode
data_from_mic_int16 = new int16[size];
_ca->getAudioCodec()->float32ToInt16 (data_from_mic_tmp,
data_from_mic_int16, size);
// Encode acquired audio sample
compSize = _ca->getAudioCodec()->codecEncode (data_to_send,
data_from_mic_tmp,
i);
data_from_mic_int16,
size);
// Send encoded audio sample
if (!_sym) {
_sessionSend->putData(timestamp, data_to_send, compSize);
} else {
_session->putData(timestamp, data_to_send, compSize);
}
timestamp += 160;
timestamp += MY_TIMESTAMP;
////////////////////////////
// Recv session
////////////////////////////
......@@ -302,10 +280,13 @@ AudioRtpRTX::run (void) {
(unsigned char*) adu->getData(),
adu->getSize());
// To convert int16 to float32 after decoding
data_for_speakers_float = new float32[expandedSize];
ac->int16ToFloat32 (data_for_speakers, data_for_speakers_float,
expandedSize);
// Set decoded data to sound device
_audioDevice->audio_buf.resize(expandedSize);
_audioDevice->audio_buf.setData (data_for_speakers,
_manager->getSpkrVolume());
_manager->getAudioDriver()->mydata.dataOut = data_for_speakers_float;
// Notify (with a bip) an incoming call when there is already a call
countTime += time->getSecond();
......@@ -316,18 +297,23 @@ AudioRtpRTX::run (void) {
}
}
// Write data or notification
i = _audioDevice->writeBuffer ();
delete cd;
delete adu;
// Let's wait for the next transmit cycle
Thread::sleep(TimerPort::getTimer());
TimerPort::incTimer(frameSize); // 'frameSize' ms
if (!_manager->getAudioDriver()->isStreamActive()) {
_manager->getAudioDriver()->mydata.dataToAddRem = 0;
_manager->getAudioDriver()->startStream();
}
}
delete[] data_for_speakers;
delete[] data_for_speakers_float;
delete[] data_from_mic;
delete[] data_from_mic_int16;
delete[] data_from_mic_tmp;
delete[] data_mute;
delete[] data_to_send;
......
......@@ -28,9 +28,9 @@
using namespace ost;
#define LEN_BUFFER 160
#define MY_TIMESTAMP 160
class AudioDrivers;
class AudioDriversPortAudio;
class Manager;
class SipCall;
......@@ -39,23 +39,20 @@ class SipCall;
///////////////////////////////////////////////////////////////////////////////
class AudioRtpRTX : public Thread, public TimerPort {
public:
AudioRtpRTX (SipCall *, AudioDrivers *, AudioDrivers *, Manager *, bool);
AudioRtpRTX (SipCall *, AudioDriversPortAudio*, Manager *, bool);
~AudioRtpRTX();
Time *time; // For incoming call notification
virtual void run ();
private:
SipCall* _ca;
AudioDrivers* _audioDevice;
#ifdef ALSA
AudioDrivers* _audioDeviceRead;
#endif
RTPSession* _sessionSend;
RTPSession* _sessionRecv;
SymmetricRTPSession* _session;
Manager* _manager;
bool _sym;
SipCall* _ca;
AudioDriversPortAudio* _audioDevice;
RTPSession* _sessionSend;
RTPSession* _sessionRecv;
SymmetricRTPSession* _session;
Manager* _manager;
bool _sym;
};
///////////////////////////////////////////////////////////////////////////////
......
......@@ -36,7 +36,7 @@ DTMF::startTone (char code) {
}
bool
DTMF::generateDTMF (short* buffer, size_t n) {
DTMF::generateDTMF (float32* buffer, size_t n) {
if (!buffer) return false;
if (currentTone != 0) {
......
......@@ -23,6 +23,7 @@
#ifndef __DTMF_H_
#define __DTMF_H_
#include "../global.h"
#include "dtmfgenerator.h"
class DTMF {
......@@ -31,7 +32,7 @@ public:
~DTMF (void);
void startTone (char);
bool generateDTMF (short*, size_t);
bool generateDTMF (float32*, size_t);
char currentTone;
char newTone;
......
......@@ -92,7 +92,7 @@ DTMFGenerator::~DTMFGenerator() {
/*
* Get n samples of the signal of code code
*/
void DTMFGenerator::getSamples(short* buffer, size_t n, unsigned char code) throw(DTMFException) {
void DTMFGenerator::getSamples(float32* buffer, size_t n, unsigned char code) throw(DTMFException) {
size_t i;
if (!buffer) {
// throw DTMFException("Invalid parameter value");
......@@ -137,7 +137,7 @@ void DTMFGenerator::getSamples(short* buffer, size_t n, unsigned char code) thro
* Get next n samples (continues where previous call to
* genSample or genNextSamples stopped
*/
void DTMFGenerator::getNextSamples(short* buffer, size_t n) throw(DTMFException)
void DTMFGenerator::getNextSamples(float32* buffer, size_t n) throw(DTMFException)
{
size_t i;
......@@ -162,17 +162,17 @@ void DTMFGenerator::getNextSamples(short* buffer, size_t n) throw(DTMFException)
/*
* Generate a tone sample
*/
short* DTMFGenerator::generateSample(unsigned char code) throw (DTMFException) {
short* ptr;
float32* DTMFGenerator::generateSample(unsigned char code) throw (DTMFException) {
float32* ptr;
// try {
ptr = new short[SAMPLING_RATE];
ptr = new float32[SAMPLING_RATE];
if (!ptr) {
//throw new DTMFException("No memory left");
return 0;
}
generateSin(tones[code].higher, tones[code].lower, AMPLITUDE,
generateSin(tones[code].higher, tones[code].lower,
SAMPLING_RATE, ptr);
return ptr;
......
......@@ -62,13 +62,13 @@ private:
*/
struct DTMFState {
unsigned int offset; // Offset in the sample currently being played
short* sample; // Currently generated code
float32* sample; // Currently generated code
};
DTMFState state;
static const DTMFTone tones[NUM_TONES];
short* samples[NUM_TONES]; // Generated samples
float32* samples[NUM_TONES]; // Generated samples
public:
DTMFGenerator();
......@@ -77,16 +77,16 @@ public:
/*
* Get n samples of the signal of code code
*/
void getSamples(short* buffer, size_t n, unsigned char code) throw (DTMFException);
void getSamples(float32* buffer, size_t n, unsigned char code) throw (DTMFException);
/*
* Get next n samples (continues where previous call to
* genSample or genNextSamples stopped
*/
void getNextSamples(short* buffer, size_t n) throw (DTMFException);
void getNextSamples(float32* buffer, size_t n) throw (DTMFException);
private:
short* generateSample(unsigned char code) throw (DTMFException);
float32* generateSample(unsigned char code) throw (DTMFException);
};
......
......@@ -32,13 +32,15 @@
using namespace std;
#define DTMF_FREQ_MIX_RATE 0.45f
///////////////////////////////////////////////////////////////////////////////
// ToneThread implementation
///////////////////////////////////////////////////////////////////////////////
ToneThread::ToneThread (Manager *mngr, short *buf) {
ToneThread::ToneThread (Manager *mngr, float32 *buf, int size) {
this->mngr = mngr;
this->buffer = buf;
this->size = size;
}
ToneThread::~ToneThread (void) {
......@@ -48,9 +50,11 @@ ToneThread::~ToneThread (void) {
void
ToneThread::run (void) {
while (mngr->getTonezone()) {
mngr->audiodriver->audio_buf.setData(buffer, mngr->getSpkrVolume());
mngr->audiodriver->writeBuffer();
}
if (mngr->getAudioDriver()->mydata.dataFilled >=
mngr->getAudioDriver()->mydata.dataToAddRem) {
mngr->getAudioDriver()->mydata.dataFilled = 0;
}
}
}
///////////////////////////////////////////////////////////////////////////////
......@@ -60,7 +64,7 @@ ToneThread::run (void) {
ToneGenerator::ToneGenerator (Manager *mngr) {
this->initTone();
this->manager = mngr;
buf = new short[SIZEBUF];
buf = new float32[SIZEBUF];
tonethread = NULL;
}
......@@ -124,21 +128,19 @@ ToneGenerator::initTone (void) {
*
* @param lower frequency
* @param higher frequency
* @param amplitude
* @param samplingRate
* @param ptr for result buffer
*/
void
ToneGenerator::generateSin (int lowerfreq, int higherfreq, int amplitude,
int samplingRate, short*ptr) {
ToneGenerator::generateSin (int lowerfreq, int higherfreq,
int samplingRate, float32*ptr) {
double var1, var2;
var1 = (double)2 * (double)M_PI * (double)higherfreq / (double)samplingRate;
var2 = (double)2 * (double)M_PI * (double)lowerfreq / (double)samplingRate;
for(int i = 0; i < samplingRate; i++) {
ptr[i] = (short)((double)(amplitude >> 2) * sin(var1 * i) +
(double)(amplitude >> 2) * sin(var2 * i));
for(int t = 0; t < samplingRate; t++) {
ptr[t] = DTMF_FREQ_MIX_RATE * (float32)(sin(var1 * t) + sin(var2 * t));
}