diff --git a/src/audio/Makefile.am b/src/audio/Makefile.am index 7c82edb0a47df84b4b3639d1c845142e38afbceb..5bd7d1ab1e1a6d3b1a9a745093f728730d39d846 100644 --- a/src/audio/Makefile.am +++ b/src/audio/Makefile.am @@ -3,21 +3,13 @@ SUBDIRS = gsm pacpp noinst_LTLIBRARIES = libaudio.la -libaudio_la_SOURCES = \ - alaw.cpp alaw.h \ - audiocodec.cpp audiocodec.h \ - audiolayer.cpp audiolayer.h \ - audiortp.cpp audiortp.h \ - codecDescriptor.cpp codecDescriptor.h \ - common.h \ - dtmf.cpp dtmf.h \ - dtmfgenerator.cpp dtmfgenerator.h \ - g711.cpp g711.h \ - gsmcodec.cpp gsmcodec.h \ - ringbuffer.cpp ringbuffer.h \ - tonegenerator.cpp tonegenerator.h \ - ulaw.cpp ulaw.h +libaudio_la_SOURCES = alaw.cpp alaw.h audiocodec.cpp audiocodec.h \ + audiolayer.cpp audiolayer.h audiortp.cpp audiortp.h codecDescriptor.cpp \ + codecDescriptor.h common.h dtmf.cpp dtmf.h dtmfgenerator.cpp dtmfgenerator.h g711.cpp \ + g711.h gsmcodec.cpp gsmcodec.h ringbuffer.cpp ringbuffer.h \ + tonegenerator.cpp tonegenerator.h ulaw.cpp ulaw.h tone.cpp tonelist.cpp AM_CXXFLAGS = -I$(top_srcdir) -I$(srcdir)/pacpp/include/ $(libccext2_CFLAGS) $(libccrtp1_CFLAGS) $(portaudio_CFLAGS) libaudio_la_LIBADD = gsm/libgsm.la pacpp/source/portaudiocpp/libportaudiocpp.la +noinst_HEADERS = tone.h tonelist.h diff --git a/src/audio/audiolayer.cpp b/src/audio/audiolayer.cpp index f66e73072f02fea48008efb37f2b143ba1879b61..4140947d18457f898f7fa930df5dba87e8dea3e5 100644 --- a/src/audio/audiolayer.cpp +++ b/src/audio/audiolayer.cpp @@ -88,9 +88,9 @@ AudioLayer::openDevice (int index) NULL); - // we could put 0 instead of FRAME_PER_BUFFER to be variable + // we could put paFramesPerBufferUnspecified instead of FRAME_PER_BUFFER to be variable portaudio::StreamParameters const params(inParams, outParams, - SAMPLING_RATE, paFramesPerBufferUnspecified, paPrimeOutputBuffersUsingStreamCallback | paNeverDropInput /*paNoFlag*/); + SAMPLING_RATE, paFramesPerBufferUnspecified, paNoFlag /*paPrimeOutputBuffersUsingStreamCallback | paNeverDropInput*/); // Create (and open) a new Stream, using the AudioLayer::audioCallback _stream = new portaudio::MemFunCallbackStream<AudioLayer>(params, @@ -102,25 +102,21 @@ void AudioLayer::startStream(void) { ost::MutexLock guard(_mutex); - if (Manager::instance().isDriverLoaded()) { - if (_stream && !_stream->isActive()) { - _debug("Thread: start audiolayer stream\n"); - _stream->start(); - } - } + if (_stream && !_stream->isActive()) { + _debug("Thread: start audiolayer stream\n"); + _stream->start(); + } } void AudioLayer::stopStream(void) { ost::MutexLock guard(_mutex); - if (Manager::instance().isDriverLoaded()) { - if (_stream && !_stream->isStopped()) { - _debug("Thread: stop audiolayer stream\n"); - _stream->stop(); - _mainSndRingBuffer.flush(); - } - } + if (_stream && !_stream->isStopped()) { + _debug("Thread: stop audiolayer stream\n"); + _stream->stop(); + _mainSndRingBuffer.flush(); + } } void @@ -145,7 +141,12 @@ void AudioLayer::putMain(void* buffer, int toCopy) { ost::MutexLock guard(_mutex); - _mainSndRingBuffer.Put(buffer, toCopy); + int a = _mainSndRingBuffer.AvailForPut(); + if ( a >= toCopy ) { + _mainSndRingBuffer.Put(buffer, toCopy); + } else { + _mainSndRingBuffer.Put(buffer, a); + } } void @@ -159,7 +160,12 @@ void AudioLayer::putUrgent(void* buffer, int toCopy) { ost::MutexLock guard(_mutex); - _urgentRingBuffer.Put(buffer, toCopy); + int a = _mainSndRingBuffer.AvailForPut(); + if ( a >= toCopy ) { + _urgentRingBuffer.Put(buffer, toCopy); + } else { + _urgentRingBuffer.Put(buffer, a); + } } void @@ -195,38 +201,43 @@ AudioLayer::audioCallback (const void *inputBuffer, void *outputBuffer, int urgentAvail, // number of int16 right and int16 left normalAvail, // number of int16 right and int16 left micAvailPut; - unsigned short spkrVolume = Manager::instance().getSpkrVolume(); - unsigned short micVolume = Manager::instance().getMicVolume(); + ManagerImpl& _manager = Manager::instance(); + 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) - framesPerBuffer *= NBCHARFORTWOINT16; urgentAvail = _urgentRingBuffer.AvailForGet(); if (urgentAvail > 0) { // Urgent data (dtmf, incoming call signal) come first. - toGet = (urgentAvail < (int)framesPerBuffer) ? urgentAvail : framesPerBuffer; + toGet = (urgentAvail < (int)framesPerBuffer * NBCHARFORTWOINT16) ? urgentAvail : framesPerBuffer * NBCHARFORTWOINT16; _urgentRingBuffer.Get(out, toGet, spkrVolume); // Consume the regular one as well (same amount of bytes) _mainSndRingBuffer.Discard(toGet); } else { - // If nothing urgent, play the regular sound samples - normalAvail = _mainSndRingBuffer.AvailForGet(); - toGet = (normalAvail < (int)framesPerBuffer) ? normalAvail : framesPerBuffer; - - if (toGet) { - _mainSndRingBuffer.Get(out, toGet, spkrVolume); + Tone* tone = _manager.getTelephoneTone(); + if ( tone != 0) { + tone->getNext(out, framesPerBuffer, spkrVolume); } else { - toGet = framesPerBuffer; - _mainSndRingBuffer.PutZero(toGet); - _mainSndRingBuffer.Get(out, toGet, 100); - } + // If nothing urgent, play the regular sound samples + normalAvail = _mainSndRingBuffer.AvailForGet(); + toGet = (normalAvail < (int)framesPerBuffer * NBCHARFORTWOINT16) ? normalAvail : framesPerBuffer * NBCHARFORTWOINT16; + + if (toGet) { + _mainSndRingBuffer.Get(out, toGet, spkrVolume); + } else { + toGet = framesPerBuffer; + _mainSndRingBuffer.PutZero(toGet); + _mainSndRingBuffer.Get(out, toGet, 100); + } + } } // Additionally handle the mic's audio stream micAvailPut = _micRingBuffer.AvailForPut(); - toPut = (micAvailPut <= (int)framesPerBuffer) ? micAvailPut : framesPerBuffer; + toPut = (micAvailPut <= (int)framesPerBuffer) ? micAvailPut : framesPerBuffer * NBCHARFORTWOINT16; _micRingBuffer.Put(in, toPut, micVolume ); return paContinue; diff --git a/src/audio/audiolayer.h b/src/audio/audiolayer.h index f04d53c9336a0432e8eb22b39f567c034755443d..3c0cdab7592940fe816c13a1b8a5f432ed933a72 100644 --- a/src/audio/audiolayer.h +++ b/src/audio/audiolayer.h @@ -29,7 +29,6 @@ #include "../global.h" #include "ringbuffer.h" #include <cc++/thread.h> -#include "../manager.h" #define FRAME_PER_BUFFER 160 #define MIC_CHANNELS 2 // 1=mono 2=stereo diff --git a/src/audio/tone.cpp b/src/audio/tone.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fba483d5dc8f1b47614038c9aaa16b206f7483d4 --- /dev/null +++ b/src/audio/tone.cpp @@ -0,0 +1,169 @@ +/** + * Copyright (C) 2005 Savoir-Faire Linux inc. + * Author: Yan Morin <yan.morin@savoirfairelinux.com> + * + * Inspired by tonegenerator of + * Laurielle Lea <laurielle.lea@savoirfairelinux.com> (2004) + * Inspired by ringbuffer of Audacity Project + * + * 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 + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "tone.h" +#include <math.h> + +int INT16_AMPLITUDE = 32767; + +Tone::Tone(const std::string& definition) +{ + _buffer = 0; + _pos = 0; + _size = 0; + genBuffer(definition); // allocate memory with definition parameter +} + +Tone::~Tone() +{ + delete _buffer; _buffer = 0; +} + +void +Tone::genBuffer(const std::string& definition) +{ + _size = 0; + + int16 *buffer = new int16[SIZEBUF]; //1kb + int16 *bufferPos = buffer; + + // Number of format sections + unsigned int posStart = 0; // position of precedent comma + unsigned int posEnd = 0; // position of the next comma + + std::string s; // portion of frequency + int count; // number of int for one sequence + + unsigned int deflen = definition.length(); + do { + posEnd = definition.find(',', posStart); + if (posEnd == std::string::npos) { + posEnd = deflen; + } + + { + // Sample string: "350+440" or "350+440/2000,244+655/2000" + int freq1, freq2, time; + s = definition.substr(posStart, posEnd-posStart); + + // The 1st frequency is before the first + or the / + unsigned int pos_plus = s.find('+'); + unsigned int pos_slash = s.find('/'); + unsigned int len = s.length(); + unsigned int endfrequency = 0; + + if ( pos_slash == std::string::npos ) { + time = 0; + endfrequency = len; + } else { + time = atoi((s.substr(pos_slash+1,len-pos_slash-1)).data()); + endfrequency = pos_slash; + } + + // without a plus = 1 frequency + if (pos_plus == std::string::npos ) { + freq1 = atoi((s.substr(0,endfrequency)).data()); + freq2 = 0; + } else { + freq1 = atoi((s.substr(0,pos_plus)).data()); + freq2 = atoi((s.substr(pos_plus+1, endfrequency-pos_plus-1)).data()); + } + + // If there is time or if it's unlimited + if (time == 0) { + count = SAMPLING_RATE; + } else { + count = (SAMPLING_RATE * time) / 1000; + } + // Generate SAMPLING_RATE samples of sinus, buffer is the result + genSin(bufferPos, freq1, freq2, count); + + // To concatenate the different buffers for each section. + _size += (count<<1); + bufferPos += (count<<1); + } + + posStart = posEnd+1; + } while (posStart < deflen); + + _buffer = new int16[_size]; + // src, dest, tocopy + bcopy(buffer, _buffer, _size<<1); // copy char, not int16.. + delete[] buffer; buffer=0; bufferPos=0; +} + +void +Tone::genSin(int16 *buffer, int frequency1, int frequency2, int nb) +{ + double var1 = (double)2 * (double)M_PI * (double)frequency1 / (double)SAMPLING_RATE; + double var2 = (double)2 * (double)M_PI * (double)frequency2 / (double)SAMPLING_RATE; + + double amp = (double)(INT16_AMPLITUDE >> 2); + int k = 0; + for(int t = 0; t < nb; t++) { + k = t << 1; // double channel : left/right + buffer[k] = buffer[k+1] = (int16)(amp * ((sin(var1 * t) + sin(var2 * t)))); + } +} + +int +Tone::getNext(int16* output, int nb, short volume) +{ + int copied = 0; + int block; + int pos = _pos; + nb<<=1; // double the number of int16 (stereo) + while(nb) { + block = nb; + if ( block > (_size-pos) ) { + block = _size-pos; + } + // src, dest, len + bcopy(_buffer+pos, output, block<<1); // short>char conversion + if (volume!=100) { + for (int i=0;i<block;i++) { + *output = (*output * volume)/100; + output++; + } + } else { + output += block; // this is the destination... + } + // should adjust sound here, in output??? + pos = (pos + block ) % _size; + nb -= block; + copied += block; + } + _pos = pos; + return copied; +} + +int +Tone::contains (const std::string& str, char c) +{ + int nb = 0; + unsigned int pos = str.find(c); + while (pos != std::string::npos ) { + nb++; + pos = str.find(c, pos+1); + } + return nb; +} diff --git a/src/audio/tone.h b/src/audio/tone.h new file mode 100644 index 0000000000000000000000000000000000000000..7335844579e9308d7af46d81e0eadd693ce678fa --- /dev/null +++ b/src/audio/tone.h @@ -0,0 +1,73 @@ +/** + * Copyright (C) 2005 Savoir-Faire Linux inc. + * Author: Yan Morin <yan.morin@savoirfairelinux.com> + * + * Inspired by tonegenerator of + * Laurielle Lea <laurielle.lea@savoirfairelinux.com> (2004) + * + * 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 + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __TONE_H__ +#define __TONE_H__ + +#include <string> +#include "../global.h" // for int16 declaration and SAMPLING_RATE +#define TONE_NBTONE 4 +#define TONE_NBCOUNTRY 7 + +/** + * @author Yan Morin <yan.morin@savoirfairelinux.com> + */ +class Tone { +public: + Tone(const std::string& definition); + ~Tone(); + enum TONEID { + TONE_DIALTONE = 0, + TONE_BUSY, + TONE_RINGTONE, + TONE_CONGESTION, + TONE_NULL + }; + + /** + * get the next fragment of the tone + * the function change the intern position, and will loop + * @param nb of int16 (mono) to send + * @return the number of int16 sent (nb*2) + */ + int getNext(int16* output, int nb, short volume=100); + +private: + /** + * add a simple or double sin to the buffer, it double the sin in stereo + * @param nb are the number of int16 (mono) to generate + * by example nb=5 generate 10 int16, 5 for the left, 5 for the right + */ + void genSin(int16 *buffer, int frequency1, int frequency2, int nb); + + /** + * allocate the memory with the definition + */ + void genBuffer(const std::string& definition); + + int contains (const std::string& str, char c); + int16* _buffer; + int _size; // number of int16 inside the buffer, not the delay + int _pos; // current position, set to 0, when initialize +}; + +#endif // __TONE_H__ + diff --git a/src/audio/tonegenerator.cpp b/src/audio/tonegenerator.cpp index af84b27c2b9b0117dbd2f3bbba48a5c95f9c2a54..ef865aa1f7abed2de1beba8f1d0f89524c317576 100644 --- a/src/audio/tonegenerator.cpp +++ b/src/audio/tonegenerator.cpp @@ -337,7 +337,7 @@ ToneGenerator::toneHandle (unsigned int idr, const std::string& zone) { void ToneGenerator::stopTone() { - _currentTone = ZT_TONE_NULL; + //_currentTone = ZT_TONE_NULL; //_debug("Thread: delete tonethread\n"); delete tonethread; tonethread = NULL; diff --git a/src/audio/tonegenerator.h b/src/audio/tonegenerator.h index dd9ae6c54f73a6f06335372079f40b82fbae9971..a857b9df8fe35cb75e8ee4ad35af1a9305a362ab 100644 --- a/src/audio/tonegenerator.h +++ b/src/audio/tonegenerator.h @@ -18,8 +18,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#ifndef __TONE_GENRATOR_H__ -#define __TONE_GENRATOR_H__ +#ifndef __TONE_GENERATOR_H__ +#define __TONE_GENERATOR_H__ #include <string> diff --git a/src/audio/tonelist.cpp b/src/audio/tonelist.cpp new file mode 100644 index 0000000000000000000000000000000000000000..40087c6ca9cbd6377849c546285cbb2b2ec7d08a --- /dev/null +++ b/src/audio/tonelist.cpp @@ -0,0 +1,143 @@ +/** + * Copyright (C) 2005 Savoir-Faire Linux inc. + * Author: Yan Morin <yan.morin@savoirfairelinux.com> + * + * Inspired by tonegenerator of + * Laurielle Lea <laurielle.lea@savoirfairelinux.com> (2004) + * + * 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 + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "tonelist.h" + +ToneList::ToneList() { + _nbTone = TONE_NBTONE; // could be dynamic + _nbCountry = TONE_NBCOUNTRY; // could be dynamic + + _defaultCountryId = ZID_NORTH_AMERICA; + initToneDefinition(); +} + +ToneList::~ToneList() { +} + +void +ToneList::initToneDefinition() +{ + _toneZone[ZID_NORTH_AMERICA][Tone::TONE_DIALTONE] = "350+440"; + _toneZone[ZID_NORTH_AMERICA][Tone::TONE_BUSY] = "480+620/500,0/500"; + _toneZone[ZID_NORTH_AMERICA][Tone::TONE_RINGTONE] = "440+480/2000,0/4000"; + _toneZone[ZID_NORTH_AMERICA][Tone::TONE_CONGESTION] = "480+620/250,0/250"; + + _toneZone[ZID_FRANCE][Tone::TONE_DIALTONE] = "440"; + _toneZone[ZID_FRANCE][Tone::TONE_BUSY] = "440/500,0/500"; + _toneZone[ZID_FRANCE][Tone::TONE_RINGTONE] = "440/1500,0/3500"; + _toneZone[ZID_FRANCE][Tone::TONE_CONGESTION] = "440/250,0/250"; + + _toneZone[ZID_AUSTRALIA][Tone::TONE_DIALTONE] = "413+438"; + _toneZone[ZID_AUSTRALIA][Tone::TONE_BUSY] = "425/375,0/375"; + _toneZone[ZID_AUSTRALIA][Tone::TONE_RINGTONE] = + "413+438/400,0/200,413+438/400,0/2000"; + _toneZone[ZID_AUSTRALIA][Tone::TONE_CONGESTION] = "425/375,0/375,420/375,8/375"; + + _toneZone[ZID_UNITED_KINGDOM][Tone::TONE_DIALTONE] = "350+440"; + _toneZone[ZID_UNITED_KINGDOM][Tone::TONE_BUSY] = "400/375,0/375"; + _toneZone[ZID_UNITED_KINGDOM][Tone::TONE_RINGTONE] = + "400+450/400,0/200,400+450/400,0/2000"; + _toneZone[ZID_UNITED_KINGDOM][Tone::TONE_CONGESTION] = + "400/400,0/350,400/225,0/525"; + + _toneZone[ZID_SPAIN][Tone::TONE_DIALTONE] = "425"; + _toneZone[ZID_SPAIN][Tone::TONE_BUSY] = "425/200,0/200"; + _toneZone[ZID_SPAIN][Tone::TONE_RINGTONE] = "425/1500,0/3000"; + _toneZone[ZID_SPAIN][Tone::TONE_CONGESTION] = + "425/200,0/200,425/200,0/200,425/200,0/600"; + + _toneZone[ZID_ITALY][Tone::TONE_DIALTONE] = "425/600,0/1000,425/200,0/200"; + _toneZone[ZID_ITALY][Tone::TONE_BUSY] = "425/500,0/500"; + _toneZone[ZID_ITALY][Tone::TONE_RINGTONE] = "425/1000,0/4000"; + _toneZone[ZID_ITALY][Tone::TONE_CONGESTION] = "425/200,0/200"; + + _toneZone[ZID_JAPAN][Tone::TONE_DIALTONE] = "400"; + _toneZone[ZID_JAPAN][Tone::TONE_BUSY] = "400/500,0/500"; + _toneZone[ZID_JAPAN][Tone::TONE_RINGTONE] = "400+15/1000,0/2000"; + _toneZone[ZID_JAPAN][Tone::TONE_CONGESTION] = "400/500,0/500"; +} + +std::string +ToneList::getDefinition(COUNTRYID countryId, Tone::TONEID toneId) +{ + if (toneId == Tone::TONE_NULL) { return ""; } + return _toneZone[countryId][toneId]; +} + +ToneList::COUNTRYID +ToneList::getCountryId(const std::string& countryName) +{ + if (countryName.compare("North America") == 0) { + return ZID_NORTH_AMERICA; + } else if (countryName.compare("France") == 0) { + return ZID_FRANCE; + } else if (countryName.compare("Australia") == 0) { + return ZID_AUSTRALIA; + } else if (countryName.compare("United Kingdom") == 0) { + return ZID_UNITED_KINGDOM; + } else if (countryName.compare("Spain") == 0) { + return ZID_SPAIN; + } else if (countryName.compare("Italy") == 0) { + return ZID_ITALY; + } else if (countryName.compare("Japan") == 0) { + return ZID_JAPAN; + } else { + return _defaultCountryId; // default, we don't want segmentation fault + } +} + +TelephoneTone::TelephoneTone(const std::string& countryName) { + ToneList::COUNTRYID countryId = _toneList.getCountryId(countryName); + _tone[Tone::TONE_DIALTONE] = new Tone(_toneList.getDefinition(countryId, Tone::TONE_DIALTONE)); + _tone[Tone::TONE_BUSY] = new Tone(_toneList.getDefinition(countryId, Tone::TONE_BUSY)); + _tone[Tone::TONE_RINGTONE] = new Tone(_toneList.getDefinition(countryId, Tone::TONE_RINGTONE)); + _tone[Tone::TONE_CONGESTION] = new Tone(_toneList.getDefinition(countryId, Tone::TONE_CONGESTION)); +} + +TelephoneTone::~TelephoneTone() +{ + for (int i=0; i<_toneList.getNbTone(); i++) { + delete _tone[i]; _tone[i] = 0; + } +} + +void +TelephoneTone::setCurrentTone(Tone::TONEID toneId) +{ + _currentTone = toneId; +} + +Tone* +TelephoneTone::getCurrentTone() +{ + if ( _currentTone == Tone::TONE_NULL ) { + return 0; + } + return _tone[_currentTone]; +} + +bool +TelephoneTone::shouldPlay() +{ + return (( _currentTone != Tone::TONE_NULL ) ? true : false ); +} + + diff --git a/src/audio/tonelist.h b/src/audio/tonelist.h new file mode 100644 index 0000000000000000000000000000000000000000..b522fbac2bda7455b0868ce6bfe86ec145ab9aa4 --- /dev/null +++ b/src/audio/tonelist.h @@ -0,0 +1,97 @@ +/** + * Copyright (C) 2005 Savoir-Faire Linux inc. + * Author: Yan Morin <yan.morin@savoirfairelinux.com> + * + * Inspired by tonegenerator of + * Laurielle Lea <laurielle.lea@savoirfairelinux.com> (2004) + * + * 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 + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __TONELIST_H__ +#define __TONELIST_H__ + +#include "tone.h" + +/** + * @author Yan Morin <yan.morin@savoirfairelinux.com> + */ +class ToneList { +public: + ToneList(); + ~ToneList(); + + enum COUNTRYID { + ZID_NORTH_AMERICA = 0, + ZID_FRANCE, + ZID_AUSTRALIA, + ZID_UNITED_KINGDOM, + ZID_SPAIN, + ZID_ITALY, + ZID_JAPAN + }; + + /** + * get the string definition of a tone + * return the default country or default tone if id are invalid + * @param country the country Id, see ToneList constructor for the list + * @param toneId toneId + * @return a string definition of the tone + */ + std::string getDefinition(COUNTRYID countryId, Tone::TONEID toneId); + /** + * get the country id associate to a country name + * return the default country id if not found + * The default tone/country are set inside the ToneList constructor + * @param countryName countryName, see the ToneList constructor list + * @return Country Id or default Id + */ + COUNTRYID getCountryId(const std::string& countryName); + int getNbTone() { return _nbTone; } +private: + void initToneDefinition(); + std::string _toneZone[TONE_NBCOUNTRY][TONE_NBTONE]; + int _nbTone; + int _nbCountry; + COUNTRYID _defaultCountryId; +}; + +/** + * @author Yan Morin <yan.morin@savoirfairelinux.com> + */ +class TelephoneTone { +public: + /** Initialize the toneList and set the current tone to null */ + TelephoneTone(const std::string& countryName); + ~TelephoneTone(); + + /** send TONE::ZT_TONE_NULL to stop the playing */ + void setCurrentTone(Tone::TONEID toneId); + + /** + * @return the currentTone after setting it with setCurrentTone + * 0 if the current tone is null + */ + Tone* getCurrentTone(); + + /** @return true if you should play the tone (CurrentTone is not NULL) */ + bool shouldPlay(); + +private: + Tone* _tone[TONE_NBTONE]; + Tone::TONEID _currentTone; + ToneList _toneList; +}; + +#endif diff --git a/src/gui/server/requestconfig.cpp b/src/gui/server/requestconfig.cpp index 00983277d79855cf5515a8d0f7b7fcc5f2f2212a..3bfa954b5154c44fb872fd915f2740e1d610e963 100644 --- a/src/gui/server/requestconfig.cpp +++ b/src/gui/server/requestconfig.cpp @@ -137,6 +137,9 @@ RequestConfigSet::RequestConfigSet(const std::string &sequenceId, const TokenLis _value = *iter; _argList.pop_front(); argsAreValid = true; + } else { + _value = ""; + argsAreValid = true; } } } diff --git a/src/managerimpl.cpp b/src/managerimpl.cpp index ea70495b04f55cee9a5214198d83af427cb126a4..149d63d89d3fbc3cedfe802c15b0ad9bbd9d0104 100644 --- a/src/managerimpl.cpp +++ b/src/managerimpl.cpp @@ -39,6 +39,8 @@ #include "audio/audiolayer.h" #include "audio/ringbuffer.h" #include "audio/tonegenerator.h" +#include "audio/tonelist.h" + #include "call.h" #include "error.h" #include "user_cfg.h" @@ -65,6 +67,7 @@ ManagerImpl::ManagerImpl (void) // Init private variables _error = new Error(); _tone = new ToneGenerator(); + _hasZeroconf = false; #ifdef USE_ZEROCONF _hasZeroconf = true; @@ -78,7 +81,6 @@ ManagerImpl::ManagerImpl (void) _path = ""; _exist = 0; _setupLoaded = false; - _loaded = false; _gui = NULL; _audiodriverPA = NULL; @@ -123,7 +125,6 @@ ManagerImpl::init() try { _debugInit("Audio Driver Selection"); selectAudioDriver(); - loaded(true); } catch (const portaudio::PaException &e) { @@ -156,10 +157,15 @@ ManagerImpl::init() // the stun detection is long, so it's a better idea to do it after getEvents initZeroconf(); + + std::string country = getConfigString(PREFERENCES, ZONE_TONE); + _telephoneTone = new TelephoneTone(country); } void ManagerImpl::terminate() { + delete _telephoneTone; _telephoneTone = 0; + for(VoIPLinkVector::iterator pos = _voIPLinkVector.begin(); pos != _voIPLinkVector.end(); pos++) { @@ -574,7 +580,11 @@ ManagerImpl::playDtmf(char code) // put the size in bytes... // so size * CHANNELS * 2 (bytes for the int16) int nbInt16InChar = sizeof(int16)/sizeof(char); - audiolayer->urgentRingBuffer().Put(buf_ctrl_vol, size * CHANNELS * nbInt16InChar); + int toSend = audiolayer->urgentRingBuffer().AvailForPut(); + if (toSend > size * CHANNELS * nbInt16InChar ) { + toSend = size * CHANNELS * nbInt16InChar; + } + audiolayer->urgentRingBuffer().Put(buf_ctrl_vol, toSend); // We activate the stream if it's not active yet. if (!audiolayer->isStreamActive()) { @@ -846,14 +856,13 @@ ManagerImpl::stopVoiceMessageNotification (void) * Multi Thread */ bool -ManagerImpl::playATone(unsigned int tone) { - if (isDriverLoaded()) { - ost::MutexLock m(_toneMutex); - _toneType = tone; - _tone->toneHandle(_toneType, getConfigString(PREFERENCES, ZONE_TONE)); - return true; - } - return false; +ManagerImpl::playATone(Tone::TONEID toneId) { + ost::MutexLock m(_toneMutex); + //_toneType = tone; + //_tone->toneHandle(_toneType, getConfigString(PREFERENCES, ZONE_TONE)); + _telephoneTone->setCurrentTone(toneId); + getAudioDriver()->startStream(); + return true; } /** @@ -861,15 +870,14 @@ ManagerImpl::playATone(unsigned int tone) { */ void ManagerImpl::stopTone() { - if (isDriverLoaded()) { - _toneMutex.enterMutex(); - if ( _toneType != ZT_TONE_NULL ) { - _toneType = ZT_TONE_NULL; - _tone->stopTone(); - } - _toneMutex.leaveMutex(); - getAudioDriver()->stopStream(); - } + _toneMutex.enterMutex(); + _telephoneTone->setCurrentTone(Tone::TONE_NULL); +// if ( _toneType != ZT_TONE_NULL ) { +// _toneType = ZT_TONE_NULL; +// _tone->stopTone(); +// } + _toneMutex.leaveMutex(); + getAudioDriver()->stopStream(); } /** @@ -878,7 +886,7 @@ ManagerImpl::stopTone() { bool ManagerImpl::playTone() { - return playATone(ZT_TONE_DIALTONE); + return playATone(Tone::TONE_DIALTONE); } /** @@ -886,7 +894,7 @@ ManagerImpl::playTone() */ void ManagerImpl::congestion () { - playATone(ZT_TONE_CONGESTION); + playATone(Tone::TONE_CONGESTION); } /** @@ -894,7 +902,7 @@ ManagerImpl::congestion () { */ void ManagerImpl::ringback () { - playATone(ZT_TONE_RINGTONE); + playATone(Tone::TONE_RINGTONE); } /** @@ -902,7 +910,7 @@ ManagerImpl::ringback () { */ void ManagerImpl::callBusy(CALLID id) { - playATone(ZT_TONE_BUSY); + playATone(Tone::TONE_BUSY); Call* call = getCall(id); if (call != NULL) { call->setState(Call::Busy); @@ -914,7 +922,7 @@ ManagerImpl::callBusy(CALLID id) { */ void ManagerImpl::callFailure(CALLID id) { - playATone(ZT_TONE_BUSY); + playATone(Tone::TONE_BUSY); Call* call = getCall(id); if (call != NULL) { getCall(id)->setState(Call::Error); @@ -930,21 +938,19 @@ ManagerImpl::callFailure(CALLID id) { */ void ManagerImpl::ringtone() -{ - if (isDriverLoaded()) { - _toneMutex.enterMutex(); - _toneType = ZT_TONE_FILE; - std::string ringchoice = getConfigString(AUDIO, RING_CHOICE); - // if there is no / inside the path - if ( ringchoice.find(DIR_SEPARATOR_CH) == std::string::npos ) { - // check inside global share directory - ringchoice = std::string(PROGSHAREDIR) + DIR_SEPARATOR_STR + RINGDIR + DIR_SEPARATOR_STR + ringchoice; - } - int play = _tone->playRingtone(ringchoice.c_str()); - _toneMutex.leaveMutex(); - if (play!=1) { - ringback(); - } +{ + _toneMutex.enterMutex(); + _toneType = ZT_TONE_FILE; + std::string ringchoice = getConfigString(AUDIO, RING_CHOICE); + // if there is no / inside the path + if ( ringchoice.find(DIR_SEPARATOR_CH) == std::string::npos ) { + // check inside global share directory + ringchoice = std::string(PROGSHAREDIR) + DIR_SEPARATOR_STR + RINGDIR + DIR_SEPARATOR_STR + ringchoice; + } + int play = _tone->playRingtone(ringchoice.c_str()); + _toneMutex.leaveMutex(); + if (play!=1) { + ringback(); } } diff --git a/src/managerimpl.h b/src/managerimpl.h index 8ac3a53fd344a17a8614bd98de81420e1ded879a..d5786c0b642a305d5538566d22203e0d562ec900 100644 --- a/src/managerimpl.h +++ b/src/managerimpl.h @@ -25,6 +25,7 @@ #include <string> #include <vector> +#include "audio/tonelist.h" // for Tone::TONEID declaration #include "../stund/stun.h" #include "call.h" #include "audio/audiodevice.h" @@ -38,6 +39,9 @@ class CodecDescriptor; class Error; class GuiFramework; class ToneGenerator; + +class TelephoneTone; + class VoIPLink; #ifdef USE_ZEROCONF class DNSService; @@ -70,14 +74,6 @@ typedef std::vector< VoIPLink* > VoIPLinkVector; */ typedef std::vector< CodecDescriptor* > CodecDescriptorVector; -/* - * Structure for audio device - */ -//struct device_t{ -// const char* hostApiName; -// const char* deviceName; -//}; - /** * To send multiple string */ @@ -206,6 +202,9 @@ name); void callBusy(CALLID id); void callFailure(CALLID id); + // return 0 if no tone (init before calling this function) + Tone* getTelephoneTone() { return _telephoneTone->getCurrentTone(); }; + /** * @return true is there is one or many incoming call waiting * new call, not anwsered or refused @@ -250,12 +249,6 @@ name); inline void setFirewallPort (int port) { _firewallPort = port; } inline std::string getFirewallAddress (void) { return _firewallAddr; } - /* - * Manage information about audio driver - */ - inline bool isDriverLoaded (void) const { return _loaded; } - inline void loaded (bool l) { _loaded = l; } - /* * Init default values for the different fields */ @@ -327,12 +320,14 @@ private: * Play one tone * @return false if the driver is uninitialize */ - bool playATone(unsigned int tone); + bool playATone(Tone::TONEID toneId); + //bool playATone(unsigned int tone); ///////////////////// // Private variables ///////////////////// ToneGenerator* _tone; + TelephoneTone* _telephoneTone; ost::Mutex _toneMutex; int _toneType; @@ -398,9 +393,6 @@ private: int _firewallPort; std::string _firewallAddr; - // Variables used in exception - bool _loaded; - // true if we tried to register Once void initRegisterVoIPLink(); bool _hasTriedToRegister; diff --git a/src/sipvoiplink.cpp b/src/sipvoiplink.cpp index cd395eff1a5e3dad8d47afdcee47191a9bb470d7..56f384ba9e6c9f9c9a3c23af76e5fd67be86afd8 100644 --- a/src/sipvoiplink.cpp +++ b/src/sipvoiplink.cpp @@ -290,8 +290,11 @@ SipVoIPLink::outgoingInvite (CALLID id, const std::string& to_url) // TODO: should be inside account settings ManagerImpl& manager = Manager::instance(); // Form the From header field basis on configuration panel - from = fromHeader(manager.getConfigString(SIGNALISATION, USER_PART), - manager.getConfigString(SIGNALISATION, HOST_PART)); + std::string host = manager.getConfigString(SIGNALISATION, HOST_PART); + if ( host.empty() ) { + host = getLocalIpAddress(); + } + from = fromHeader(manager.getConfigString(SIGNALISATION, USER_PART), host); to = toHeader(to_url); @@ -783,6 +786,11 @@ SipVoIPLink::getEvent (void) } break; case EXOSIP_CALL_RELEASED: + id = findCallId(event); + if (id!=0) { + Manager::instance().peerHungupCall(id); + deleteSipCall(id); + } break; case EXOSIP_CALL_REQUESTFAILURE: id = findCallId(event);