diff --git a/autogen.sh b/autogen.sh index 06b6a97c95e0c7f4db9c8bd21a358a14784e9187..ac85bd137c9dcf2f99eef6992751d1a92876cdcd 100755 --- a/autogen.sh +++ b/autogen.sh @@ -4,6 +4,6 @@ aclocal -I m4 libtoolize --force autoheader -autoconf -f +autoconf -v -f automake -a ./configure $@ diff --git a/configure.ac b/configure.ac index b07bc5ccf138ce263ede685185445b28019e9d81..b79bb61592859d9ab248973e624725313167b77c 100644 --- a/configure.ac +++ b/configure.ac @@ -36,7 +36,10 @@ AC_CONFIG_FILES([src/Makefile \ src/audio/codecs/Makefile src/audio/codecs/ilbc/Makefile \ src/config/Makefile \ - src/dbus/Makefile ]) + src/dbus/Makefile \ + src/plug-in/audiorecorder/Makefile \ + src/plug-in/Makefile \ + src/plug-in/test/Makefile]) dnl Unitary test section AC_CONFIG_FILES([test/Makefile]) diff --git a/globals.mak b/globals.mak index c03985035c4058b00b378f1b0809017241339313..7a0b085b9efbe0f7deefb226deed286cbba7982a 100644 --- a/globals.mak +++ b/globals.mak @@ -1,6 +1,7 @@ # Global variables src=$(top_srcdir) sflcodecdir=$(libdir)/sflphone/codecs +sflplugindir=$(libdir)/sflphone/plugins PJSIP_LIBS = -lpjnath-sfl -lpjsua-sfl -lpjsip-sfl -lpjmedia-sfl -lpjsip-simple-sfl -lpjsip-ua-sfl -lpjmedia-codec-sfl -lpjlib-util-sfl -lpj-sfl @@ -16,5 +17,6 @@ AM_CPPFLAGS = \ @SIP_CFLAGS@ \ @DBUSCPP_CFLAGS@ \ -DCODECS_DIR=\""$(sflcodecdir)"\" \ + -DPLUGINS_DIR=\""$(sflplugindir)"\" \ -DENABLE_TRACE diff --git a/src/Makefile.am b/src/Makefile.am index b7c1a2839d2f02c089c3c17d24aa359d7c532dfa..dc83d84f8a88dce7600a278648ba0b2d265180b3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -13,7 +13,7 @@ IAXSOURCES = IAXHEADERS = endif -SUBDIRS = audio config dbus +SUBDIRS = audio config dbus plug-in # Add here the cpp files to be build with sflphone sflphoned_SOURCES = \ @@ -75,6 +75,8 @@ libsflphone_la_LIBADD = \ ./audio/libaudio.la \ ./dbus/libdbus.la \ ./config/libconfig.la \ + ./plug-in/libplugin.la \ + ./plug-in/audiorecorder/libaudiorecorder.la \ $(IAX_LIBS) libsflphone_la_SOURCES = diff --git a/src/account.h b/src/account.h index faf33dc162725e39c3dd4ad23985c0bb207b83c3..97e0b2bb3cbfa8510a03e675f0f8578a392d5a50 100644 --- a/src/account.h +++ b/src/account.h @@ -96,6 +96,8 @@ class Account{ */ inline VoIPLink* getVoIPLink() { return _link; } + inline void setVoIPLink (VoIPLink *link) { _link = link; } + /** * Register the underlying VoIPLink. Launch the event listener. * This should update the getRegistrationState() return value. diff --git a/src/audio/alsalayer.cpp b/src/audio/alsalayer.cpp index 3ddb66a845e3a05ac1dbeed0a829a47433d63b79..bac1fe2fcd80275e6d232279846ec658b6c73cab 100644 --- a/src/audio/alsalayer.cpp +++ b/src/audio/alsalayer.cpp @@ -193,9 +193,10 @@ void AlsaLayer::startCaptureStream (void) void AlsaLayer::prepareCaptureStream (void) { if (is_capture_open() ) { - _debug("Prepare the capture\n"); - if(snd_pcm_prepare (_CaptureHandle) < 0) _debug("Error preparing the device\n"); - prepare_capture (); + if(snd_pcm_prepare (_CaptureHandle) < 0) + _debug(""); + else + prepare_capture (); } } @@ -383,11 +384,11 @@ AlsaLayer::open_device(std::string pcm_p, std::string pcm_c, int flag) } /* Start the secondary audio thread for callbacks */ - try { + try{ _audioThread->start(); } - catch(...){ - _debug("Fail to start audio thread\n"); + catch (...) { + _debugException("Fail to start audio thread\n"); } return true; diff --git a/src/audio/audiorecord.cpp b/src/audio/audiorecord.cpp new file mode 100644 index 0000000000000000000000000000000000000000..65f63803942947e3cac58e91adcab2e76e1a9cf4 --- /dev/null +++ b/src/audio/audiorecord.cpp @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2008 Savoir-Faire Linux inc. + * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 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 "audiorecord.h" + +AudioRecord::AudioRecord(){ + sndSmplRate_ = 44100; + channels_ = 1; + byteCounter_ = 0; + +} + + +void AudioRecord::setSndSamplingRate(int smplRate){ + sndSmplRate_ = smplRate; +} + + +void AudioRecord::openFile(std::string fileName, FILE_TYPE type, SOUND_FORMAT format) { + + channels_ =1; + fileType_ = type; + byteCounter_ = 0; + sndFormat_ = format; + + bool result = false; + + if(fileType_ == FILE_RAW){ + result = setRawFile( fileName.c_str() ); + } + else if (fileType_ == FILE_WAV){ + result = setWavFile( fileName.c_str() ); + } + +} + + +void AudioRecord::closeFile() { + + if (fp == 0) return; + + if (fileType_ == FILE_RAW) + fclose(fp); + else if (fileType_ == FILE_WAV) + this->closeWavFile(); + +} + + +bool AudioRecord::isOpenFile() { + + if(fp) + return true; + else + return false; +} + + +bool AudioRecord::setRawFile(const char *fileName) { + + char name[8192]; + strncpy(name, fileName, 8192); + if ( strstr(name, ".raw") == NULL) strcat(name, ".raw"); + fp = fopen(name, "wb"); + if ( !fp ) { + cout << "AudioRecord: could not create RAW file: " << name << '.'; + return false; + } + + if ( sndFormat_ != INT16 ) { // TODO need to change INT16 to SINT16 + sndFormat_ = INT16; + cout << "AudioRecord: using 16-bit signed integer data format for file " << name << '.'; + } + + cout << "AudioRecord: creating RAW file: " << name; + return true; +} + + +bool AudioRecord::setWavFile(const char *fileName) { + + char name[8192]; + strncpy(name, fileName, 8192); + if ( strstr(name, ".wav") == NULL) strcat(name, ".wav"); + fp = fopen(name, "wb"); + if ( !fp ) { + cout << "AudioRecord: could not create WAV file: " << name; + return false; + } + + struct wavhdr hdr = {"RIF", 44, "WAV", "fmt", 16, 1, 1, + 44100, 0, 2, 16, "dat", 0}; + hdr.riff[3] = 'F'; + hdr.wave[3] = 'E'; + hdr.fmt[3] = ' '; + hdr.data[3] = 'a'; + hdr.num_chans = channels_; + if ( sndFormat_ == INT16 ) { // TODO need to write INT16 to SINT16 + hdr.bits_per_samp = 16; + } + hdr.bytes_per_samp = (SINT16) (channels_ * hdr.bits_per_samp / 8); + hdr.bytes_per_sec = (SINT32) (hdr.sample_rate * hdr.bytes_per_samp); + + + if ( fwrite(&hdr, 4, 11, fp) != 11 ) { + cout << "AudioRecord: could not write WAV header for file " << name << '.'; + return false; + } + + cout << "AudioRecord: creating WAV file: " << name; + return true; +} + + +void AudioRecord::closeWavFile() +{ + int bytes_per_sample = 1; + if ( sndFormat_ == INT16 ) + bytes_per_sample = 2; + + + SINT32 bytes = byteCounter_ * channels_ * bytes_per_sample; + fseek(fp, 40, SEEK_SET); // jump to data length + fwrite(&bytes, 4, 1, fp); + + bytes = byteCounter_ * channels_ * bytes_per_sample + 44; // + 44 for the wave header + fseek(fp, 4, SEEK_SET); // jump to file size + fwrite(&bytes, 4, 1, fp); + fclose( fp ); +} + + +void AudioRecord::recData(SFLDataFormat* buffer, int nSamples) { + + if (fp == 0){ + cout << "AudioRecord: Can't record data, a file has not yet been opened!"; + return; + } + + if ( sndFormat_ == INT16 ) { // TODO change INT16 to SINT16 + if (nSamples <= 1){ + if ( fwrite(buffer, 2, 1, fp) != 1) + cout << "AudioRecord: Could not record data!"; + } + else { + for ( int k=0; k<nSamples; k++ ) { + cout << "Buffer[" << k << "] : " << buffer[k] << "\n"; + if ( fwrite(&buffer[k], 2, 1, fp) != 1 ) + cout << "AudioRecord: Could not record data!"; + } + } + } + + + + + byteCounter_ += (unsigned long)(sizeof(buffer) / sizeof(SINT16)); + + return; +} + diff --git a/src/audio/audiorecord.h b/src/audio/audiorecord.h new file mode 100644 index 0000000000000000000000000000000000000000..b38eefb29a59be117d896e9c2c6147ff43011ef3 --- /dev/null +++ b/src/audio/audiorecord.h @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2008 Savoir-Faire Linux inc. + * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 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 <iostream> +#include <string.h> + +#include "global.h" + +using namespace std; + + +// structure for the wave header +struct wavhdr { + char riff[4]; // "RIFF" + SINT32 file_size; // in bytes + char wave[4]; // "WAVE" + char fmt[4]; // "fmt " + SINT32 chunk_size; // in bytes (16 for PCM) + SINT16 format_tag; // 1=PCM, 2=ADPCM, 3=IEEE float, 6=A-Law, 7=Mu-Law + SINT16 num_chans; // 1=mono, 2=stereo + SINT32 sample_rate; + SINT32 bytes_per_sec; + SINT16 bytes_per_samp; // 2=16-bit mono, 4=16-bit stereo + SINT16 bits_per_samp; + char data[4]; // "data" + SINT32 data_length; // in bytes +}; + +class AudioRecord +{ + +public: + + AudioRecord(); + + void setSndSamplingRate(int smplRate); + + /** + * Check if no otehr file is opened, then create a new one + * @param fileName A string containing teh file (with/without extension) + * @param type The sound file format (FILE_RAW, FILE_WAVE) + * @param format Internal sound format (INT16 / INT32) + */ + void openFile(std::string fileName, FILE_TYPE type, SOUND_FORMAT format); + + /** + * Close the opend recording file. If wave: cout the number of byte + */ + void closeFile(); + + /** + * Check if a file is already opened + */ + bool isOpenFile(); + + /** + * Record a chunk of data in an openend file + * @param buffer The data chunk to be recorded + * @param nSamples Number of samples (number of bytes) to be recorded + */ + void recData(SFLDataFormat* buffer, int nSamples); // TODO ad the data to rec + +protected: + + /** + * Set the header for raw files + */ + bool setRawFile(const char* fileName); + + /** + * Set the header for wave files + */ + bool setWavFile(const char* fileName); + + /** + * Compute the number of byte recorded and close the file + */ + void closeWavFile(); + + /** + * Pointer to the recorded file + */ + FILE *fp; //file pointer + + /** + * File format (RAW / WAVE) + */ + FILE_TYPE fileType_; + + /** + * Sound format (SINT16/SINT32) + */ + SOUND_FORMAT sndFormat_; + + /** + * Number of channels + */ + int channels_; + + /** + * Number f byte recorded + */ + unsigned long byteCounter_; + + /** + * Sampling rate + */ + int sndSmplRate_; + +}; diff --git a/src/audio/audiortp.cpp b/src/audio/audiortp.cpp index 56dc7174d9e6acd7229f3682dc6efd68e51538f4..34adf65db881d1e5fba25db81fd217e2315169c6 100644 --- a/src/audio/audiortp.cpp +++ b/src/audio/audiortp.cpp @@ -82,7 +82,7 @@ void AudioRtp::closeRtpSession () { ost::MutexLock m(_threadMutex); // This will make RTP threads finish. - // _debug("Stopping AudioRTP\n"); + _debug("Stopping AudioRTP\n"); try { delete _RTXThread; _RTXThread = 0; } catch(...) { @@ -126,7 +126,6 @@ AudioRtpRTX::~AudioRtpRTX () { _debugException("! ARTP: Thread destructor didn't terminate correctly"); throw; } - //_debug("terminate audiortprtx ended...\n"); _ca = 0; if (!_sym) { delete _sessionRecv; _sessionRecv = NULL; @@ -145,6 +144,7 @@ AudioRtpRTX::~AudioRtpRTX () { delete time; time = NULL; delete converter; converter = NULL; + } void diff --git a/src/audio/pulselayer.cpp b/src/audio/pulselayer.cpp index 45fb6edbae5810fec4c1b66935583532857327cf..8882ebe09ae56b369768b4b09a8b23e8034925e5 100644 --- a/src/audio/pulselayer.cpp +++ b/src/audio/pulselayer.cpp @@ -44,16 +44,10 @@ static void audioCallback ( pa_stream* s, size_t bytes, void* userdata ) // Destructor PulseLayer::~PulseLayer (void) { - //closeLayer(); - - /* Delete the pointer streams */ - delete playback; - delete record; - + closeLayer (); + pa_context_disconnect( context ); pa_context_unref( context ); - - sleep(2); } void diff --git a/src/audio/pulselayer.h b/src/audio/pulselayer.h index bdb34085b62e9abea85f27f4517b4f76b701e780..36ca8057ce47dccc78c23455dfa9b4ae40cb6ce7 100644 --- a/src/audio/pulselayer.h +++ b/src/audio/pulselayer.h @@ -22,6 +22,7 @@ #include "audiolayer.h" #include "audiostream.h" +#include "plug-in/audiorecorder/audiorecord.h" #include <pulse/pulseaudio.h> diff --git a/src/eventthread.cpp b/src/eventthread.cpp index b0378c57ec651746988f822f6206254ac6bec2bd..0ecc444b41b1f2bdc52167d6796859d4173bf983 100644 --- a/src/eventthread.cpp +++ b/src/eventthread.cpp @@ -54,6 +54,7 @@ void AudioThread::run (void) { while(!testCancel()) { _alsa->audioCallback(); + Thread::sleep(3); } } diff --git a/src/global.h b/src/global.h index 45332563dc0bbb28a0f22a777d997deafa5c32f5..6dfe9a1e1ba3c2a34eb2231a15f4b222ca033085 100644 --- a/src/global.h +++ b/src/global.h @@ -37,6 +37,19 @@ typedef float float32; typedef short int16; +//useful typedefs. +typedef signed short SINT16; +typedef signed int SINT32; + +typedef unsigned long FILE_TYPE; +typedef unsigned long SOUND_FORMAT; + +const FILE_TYPE FILE_RAW = 1; +const FILE_TYPE FILE_WAV = 2; + +static const SOUND_FORMAT INT16 = 0x2; // TODO shold change these symbols +static const SOUND_FORMAT INT32 = 0x8; + #define SUCCESS 0 #define ASSERT( expected , value) if( value == expected ) return SUCCESS; \ diff --git a/src/managerimpl.cpp b/src/managerimpl.cpp index e5292532c720e874939a541b2bc6c4ee436bc915..1881dae46c12cd08ff1fcf14523063e72758215a 100644 --- a/src/managerimpl.cpp +++ b/src/managerimpl.cpp @@ -249,6 +249,7 @@ ManagerImpl::answerCall(const CallID& id) bool ManagerImpl::hangupCall(const CallID& id) { + _debug("ManagerImpl::hangupCall(): This function is called when user hangup \n"); PulseLayer *pulselayer; AccountID accountid; bool returnValue; @@ -370,6 +371,7 @@ ManagerImpl::transferCall(const CallID& id, const std::string& to) bool ManagerImpl::refuseCall (const CallID& id) { + _debug("ManagerImpl::refuseCall(): method called"); stopTone(true); AccountID accountid = getAccountFromCall( id ); if (accountid == AccountNULL) { @@ -510,6 +512,7 @@ ManagerImpl::playDtmf(char code, bool isTalking) // Put buffer to urgentRingBuffer // put the size in bytes... // so size * 1 channel (mono) * sizeof (bytes for the data) + audiolayer->startStream(); audiolayer->putUrgent (buf, size * sizeof(SFLDataFormat)); } ret = true; @@ -631,8 +634,10 @@ ManagerImpl::peerRingingCall(const CallID& id) void ManagerImpl::peerHungupCall(const CallID& id) { + _debug("ManagerImpl::peerHungupCall():this function is called when peer hangup \n"); PulseLayer *pulselayer; AccountID accountid; + bool returnValue; accountid = getAccountFromCall( id ); if (accountid == AccountNULL) { @@ -648,6 +653,8 @@ ManagerImpl::peerHungupCall(const CallID& id) switchCall(""); } + returnValue = getAccountLink(accountid)->hangup(id); + removeWaitingCall(id); removeCallAccount(id); @@ -1408,9 +1415,14 @@ int ManagerImpl::isStunEnabled (void) void ManagerImpl::enableStun (void) { - ( getConfigInt( SIGNALISATION , STUN_ENABLE ) == STUN_ENABLED )? setConfig(SIGNALISATION , STUN_ENABLE , NO_STR ) : setConfig( SIGNALISATION , STUN_ENABLE , YES_STR ); + /* Update the config */ + ( getConfigInt( SIGNALISATION , STUN_ENABLE ) == STUN_ENABLED )? setConfig(SIGNALISATION , STUN_ENABLE , NO_STR ) : setConfig( SIGNALISATION , STUN_ENABLE , YES_STR ); + + /* Restart PJSIP */ + this->restartPJSIP (); } + int ManagerImpl::getVolumeControls( void ) { @@ -1945,6 +1957,7 @@ void ManagerImpl::setAccountDetails( const std::string& accountID, const std::ma setConfig(accountID, CONFIG_ACCOUNT_MAILBOX,(*details.find(CONFIG_ACCOUNT_MAILBOX)).second); // SIP SPECIFIC + /* if (accountType == "SIP") { link = Manager::instance().getAccountLink( accountID ); @@ -1966,8 +1979,8 @@ void ManagerImpl::setAccountDetails( const std::string& accountID, const std::ma { link->setStunServer(""); } - //restartPjsip(); - } + restartPJSIP(); + }*/ saveConfig(); @@ -2232,6 +2245,30 @@ AccountMap ManagerImpl::getSipAccountMap( void ) return sipaccounts; } +void ManagerImpl::restartPJSIP (void) +{ + //SIPVoIPLink *siplink; + + //unloadAccountMap (); + + /* First unregister all SIP accounts */ + //this->unregisterCurSIPAccounts(); + /* Terminate and initialize the PJSIP library */ + //siplink = dynamic_cast<SIPVoIPLink*> (getSIPAccountLink ()); + //if (siplink) + //{ + // siplink->terminate (); + // _debug ("*************************************************Terminate done\n"); + //siplink = SIPVoIPLink::instance(""); + //siplink->init (); + //} + //_debug("***************************************************Init Done\n"); + //loadAccountMap(); + //initRegisterAccounts (); + /* Then register all enabled SIP accounts */ + //this->registerCurSIPAccounts(siplink); +} + VoIPLink* ManagerImpl::getAccountLink(const AccountID& accountID) { Account* acc = getAccount(accountID); @@ -2241,6 +2278,23 @@ VoIPLink* ManagerImpl::getAccountLink(const AccountID& accountID) return 0; } +VoIPLink* ManagerImpl::getSIPAccountLink() +{ + /* We are looking for the first SIP account we met because all the SIP accounts have the same voiplink */ + Account *account; + AccountMap::iterator iter; + for(iter = _accountMap.begin(); iter != _accountMap.end(); ++iter) { + account = iter->second; + if( account->getType() == "sip" ){ + return account->getVoIPLink(); + } + } + return NULL; +} + + + + pjsip_regc *getSipRegcFromID(const AccountID& id UNUSED) { @@ -2253,32 +2307,35 @@ pjsip_regc void ManagerImpl::unregisterCurSIPAccounts() { - AccountMap::iterator iter = _accountMap.begin(); - while( iter != _accountMap.end() ) { - if ( iter->second) { - std::string p = Manager::instance().getConfigString( iter->first , CONFIG_ACCOUNT_TYPE ); - if ( iter->second->isEnabled() && p == "SIP") { - // NOW - iter->second->unregisterVoIPLink(); - } - } + Account *current; + + AccountMap::iterator iter = _accountMap.begin(); + while( iter != _accountMap.end() ) { + current = iter->second; + if (current) { + if ( current->isEnabled() && current->getType() == "sip") { + current->unregisterVoIPLink(); + } + } iter++; - } + } } -void ManagerImpl::registerCurSIPAccounts() +void ManagerImpl::registerCurSIPAccounts(VoIPLink *link) { - AccountMap::iterator iter = _accountMap.begin(); - while( iter != _accountMap.end() ) { - if ( iter->second) { - std::string p = Manager::instance().getConfigString( iter->first , CONFIG_ACCOUNT_TYPE ); - if ( iter->second->isEnabled() && p == "SIP") { - // NOW - iter->second->registerVoIPLink(); - } - } + Account *current; + + AccountMap::iterator iter = _accountMap.begin(); + while( iter != _accountMap.end() ) { + current = iter->second; + if (current) { + if ( current->isEnabled() && current->getType() == "sip") { + //current->setVoIPLink(link); + current->registerVoIPLink(); + } + } iter++; - } + } } #ifdef TEST diff --git a/src/managerimpl.h b/src/managerimpl.h index cc3411f3ade26470030f558b6cba32e18795bfdd..45471b7b211e5b23a93d2c40d74eceb958cbd85a 100644 --- a/src/managerimpl.h +++ b/src/managerimpl.h @@ -789,11 +789,11 @@ class ManagerImpl { * @param void * @return void */ - void restartPjsip(); + void restartPJSIP( ); void unregisterCurSIPAccounts(); - void registerCurSIPAccounts(); + void registerCurSIPAccounts(VoIPLink *link); /** * Returns a map with only the existing SIP accounts @@ -1014,6 +1014,8 @@ public: */ VoIPLink* getAccountLink(const AccountID& accountID); + VoIPLink* getSIPAccountLink (void); + AccountID getAccountIdFromNameAndServer(const std::string& userName, const std::string& server); int getSipPort(); diff --git a/src/plug-in/Makefile.am b/src/plug-in/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..c97ccdc21ad9d23126553e6efeda496aba88d944 --- /dev/null +++ b/src/plug-in/Makefile.am @@ -0,0 +1,12 @@ +include ../../globals.mak + +SUBDIRS=audiorecorder + +noinst_LTLIBRARIES = libplugin.la + +SUBDIRS=test + +libplugin_la_SOURCES = \ + pluginmanager.cpp \ + librarymanager.cpp + diff --git a/src/plug-in/audiorecorder/Makefile.am b/src/plug-in/audiorecorder/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..37a2ce4ed072fc300b0d85771f72e81d2fdf42e6 --- /dev/null +++ b/src/plug-in/audiorecorder/Makefile.am @@ -0,0 +1,7 @@ +include $(top_srcdir)/globals.mak + +noinst_LTLIBRARIES = libaudiorecorder.la + +libaudiorecorder_la_SOURCES = \ + audiorecord.cpp + diff --git a/src/plug-in/audiorecorder/audiorecord.cpp b/src/plug-in/audiorecorder/audiorecord.cpp new file mode 100644 index 0000000000000000000000000000000000000000..65f63803942947e3cac58e91adcab2e76e1a9cf4 --- /dev/null +++ b/src/plug-in/audiorecorder/audiorecord.cpp @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2008 Savoir-Faire Linux inc. + * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 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 "audiorecord.h" + +AudioRecord::AudioRecord(){ + sndSmplRate_ = 44100; + channels_ = 1; + byteCounter_ = 0; + +} + + +void AudioRecord::setSndSamplingRate(int smplRate){ + sndSmplRate_ = smplRate; +} + + +void AudioRecord::openFile(std::string fileName, FILE_TYPE type, SOUND_FORMAT format) { + + channels_ =1; + fileType_ = type; + byteCounter_ = 0; + sndFormat_ = format; + + bool result = false; + + if(fileType_ == FILE_RAW){ + result = setRawFile( fileName.c_str() ); + } + else if (fileType_ == FILE_WAV){ + result = setWavFile( fileName.c_str() ); + } + +} + + +void AudioRecord::closeFile() { + + if (fp == 0) return; + + if (fileType_ == FILE_RAW) + fclose(fp); + else if (fileType_ == FILE_WAV) + this->closeWavFile(); + +} + + +bool AudioRecord::isOpenFile() { + + if(fp) + return true; + else + return false; +} + + +bool AudioRecord::setRawFile(const char *fileName) { + + char name[8192]; + strncpy(name, fileName, 8192); + if ( strstr(name, ".raw") == NULL) strcat(name, ".raw"); + fp = fopen(name, "wb"); + if ( !fp ) { + cout << "AudioRecord: could not create RAW file: " << name << '.'; + return false; + } + + if ( sndFormat_ != INT16 ) { // TODO need to change INT16 to SINT16 + sndFormat_ = INT16; + cout << "AudioRecord: using 16-bit signed integer data format for file " << name << '.'; + } + + cout << "AudioRecord: creating RAW file: " << name; + return true; +} + + +bool AudioRecord::setWavFile(const char *fileName) { + + char name[8192]; + strncpy(name, fileName, 8192); + if ( strstr(name, ".wav") == NULL) strcat(name, ".wav"); + fp = fopen(name, "wb"); + if ( !fp ) { + cout << "AudioRecord: could not create WAV file: " << name; + return false; + } + + struct wavhdr hdr = {"RIF", 44, "WAV", "fmt", 16, 1, 1, + 44100, 0, 2, 16, "dat", 0}; + hdr.riff[3] = 'F'; + hdr.wave[3] = 'E'; + hdr.fmt[3] = ' '; + hdr.data[3] = 'a'; + hdr.num_chans = channels_; + if ( sndFormat_ == INT16 ) { // TODO need to write INT16 to SINT16 + hdr.bits_per_samp = 16; + } + hdr.bytes_per_samp = (SINT16) (channels_ * hdr.bits_per_samp / 8); + hdr.bytes_per_sec = (SINT32) (hdr.sample_rate * hdr.bytes_per_samp); + + + if ( fwrite(&hdr, 4, 11, fp) != 11 ) { + cout << "AudioRecord: could not write WAV header for file " << name << '.'; + return false; + } + + cout << "AudioRecord: creating WAV file: " << name; + return true; +} + + +void AudioRecord::closeWavFile() +{ + int bytes_per_sample = 1; + if ( sndFormat_ == INT16 ) + bytes_per_sample = 2; + + + SINT32 bytes = byteCounter_ * channels_ * bytes_per_sample; + fseek(fp, 40, SEEK_SET); // jump to data length + fwrite(&bytes, 4, 1, fp); + + bytes = byteCounter_ * channels_ * bytes_per_sample + 44; // + 44 for the wave header + fseek(fp, 4, SEEK_SET); // jump to file size + fwrite(&bytes, 4, 1, fp); + fclose( fp ); +} + + +void AudioRecord::recData(SFLDataFormat* buffer, int nSamples) { + + if (fp == 0){ + cout << "AudioRecord: Can't record data, a file has not yet been opened!"; + return; + } + + if ( sndFormat_ == INT16 ) { // TODO change INT16 to SINT16 + if (nSamples <= 1){ + if ( fwrite(buffer, 2, 1, fp) != 1) + cout << "AudioRecord: Could not record data!"; + } + else { + for ( int k=0; k<nSamples; k++ ) { + cout << "Buffer[" << k << "] : " << buffer[k] << "\n"; + if ( fwrite(&buffer[k], 2, 1, fp) != 1 ) + cout << "AudioRecord: Could not record data!"; + } + } + } + + + + + byteCounter_ += (unsigned long)(sizeof(buffer) / sizeof(SINT16)); + + return; +} + diff --git a/src/plug-in/audiorecorder/audiorecord.h b/src/plug-in/audiorecorder/audiorecord.h new file mode 100644 index 0000000000000000000000000000000000000000..b38eefb29a59be117d896e9c2c6147ff43011ef3 --- /dev/null +++ b/src/plug-in/audiorecorder/audiorecord.h @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2008 Savoir-Faire Linux inc. + * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 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 <iostream> +#include <string.h> + +#include "global.h" + +using namespace std; + + +// structure for the wave header +struct wavhdr { + char riff[4]; // "RIFF" + SINT32 file_size; // in bytes + char wave[4]; // "WAVE" + char fmt[4]; // "fmt " + SINT32 chunk_size; // in bytes (16 for PCM) + SINT16 format_tag; // 1=PCM, 2=ADPCM, 3=IEEE float, 6=A-Law, 7=Mu-Law + SINT16 num_chans; // 1=mono, 2=stereo + SINT32 sample_rate; + SINT32 bytes_per_sec; + SINT16 bytes_per_samp; // 2=16-bit mono, 4=16-bit stereo + SINT16 bits_per_samp; + char data[4]; // "data" + SINT32 data_length; // in bytes +}; + +class AudioRecord +{ + +public: + + AudioRecord(); + + void setSndSamplingRate(int smplRate); + + /** + * Check if no otehr file is opened, then create a new one + * @param fileName A string containing teh file (with/without extension) + * @param type The sound file format (FILE_RAW, FILE_WAVE) + * @param format Internal sound format (INT16 / INT32) + */ + void openFile(std::string fileName, FILE_TYPE type, SOUND_FORMAT format); + + /** + * Close the opend recording file. If wave: cout the number of byte + */ + void closeFile(); + + /** + * Check if a file is already opened + */ + bool isOpenFile(); + + /** + * Record a chunk of data in an openend file + * @param buffer The data chunk to be recorded + * @param nSamples Number of samples (number of bytes) to be recorded + */ + void recData(SFLDataFormat* buffer, int nSamples); // TODO ad the data to rec + +protected: + + /** + * Set the header for raw files + */ + bool setRawFile(const char* fileName); + + /** + * Set the header for wave files + */ + bool setWavFile(const char* fileName); + + /** + * Compute the number of byte recorded and close the file + */ + void closeWavFile(); + + /** + * Pointer to the recorded file + */ + FILE *fp; //file pointer + + /** + * File format (RAW / WAVE) + */ + FILE_TYPE fileType_; + + /** + * Sound format (SINT16/SINT32) + */ + SOUND_FORMAT sndFormat_; + + /** + * Number of channels + */ + int channels_; + + /** + * Number f byte recorded + */ + unsigned long byteCounter_; + + /** + * Sampling rate + */ + int sndSmplRate_; + +}; diff --git a/src/plug-in/librarymanager.cpp b/src/plug-in/librarymanager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..138b59f5f49b2c2ed19b170deb36dfb373b00846 --- /dev/null +++ b/src/plug-in/librarymanager.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2009 Savoir-Faire Linux inc. + * Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 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 "librarymanager.h" + + LibraryManager::LibraryManager (const std::string &filename) + : _filename(filename), _handlePtr(NULL) +{ + _handlePtr = loadLibrary (filename); +} + +LibraryManager::~LibraryManager (void) +{ + unloadLibrary (); +} + +LibraryManager::LibraryHandle LibraryManager::loadLibrary (const std::string &filename) +{ + LibraryHandle pluginHandlePtr = NULL; + const char *error; + + _debug("Loading dynamic library %s\n", filename.c_str()); + + /* Load the library */ + pluginHandlePtr = dlopen( filename.c_str(), RTLD_LAZY ); + if( !pluginHandlePtr ) { + error = dlerror(); + _debug("Error while opening plug-in: %s\n", error); + return NULL; + } + dlerror(); + return pluginHandlePtr; +} + +int LibraryManager::unloadLibrary () +{ + if (_handlePtr == NULL) + return 1; + + _debug("Unloading dynamic library ...\n"); + dlclose( _handlePtr ); + if (dlerror()) + { + _debug("Error unloading the library : %s\n...", dlerror()); + return 1; + } + return 0; +} + +int LibraryManager::resolveSymbol (const std::string &symbol, SymbolHandle *symbolPtr) +{ + SymbolHandle sy = 0; + + if (_handlePtr){ + try { + sy = dlsym(_handlePtr, symbol.c_str()); + if(sy != NULL) { + *symbolPtr = sy; + return 0; + } + } + catch (...) {} + + throw LibraryManagerException ( _filename, symbol, LibraryManagerException::symbolNotFound); + } + else + return 1; +} + + +/************************************************************************************************/ + +LibraryManagerException::LibraryManagerException (const std::string &libraryName, const std::string &details, Reason reason) : + _reason (reason), _details (""), std::runtime_error ("") + +{ + if (_reason == loadingFailed) + _details = "Error when loading " + libraryName + "\n" + details; + else + _details = "Error when resolving symbol " + details + " in " + libraryName; +} + +const char* LibraryManagerException::what () const throw() +{ + return _details.c_str(); +} diff --git a/src/plug-in/librarymanager.h b/src/plug-in/librarymanager.h new file mode 100644 index 0000000000000000000000000000000000000000..e244d448a1152a46950d4b0ec95e06847eac4ff5 --- /dev/null +++ b/src/plug-in/librarymanager.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2009 Savoir-Faire Linux inc. + * Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 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 LIBRARY_MANAGER_H +#define LIBRARY_MANAGER_H + +#include "dlfcn.h" +#include <stdexcept> + +#include "global.h" + +class LibraryManager { + + public: + typedef void* LibraryHandle; + typedef void* SymbolHandle; + + LibraryManager (const std::string &filename); + ~LibraryManager (void); + + int resolveSymbol (const std::string &symbol, SymbolHandle *ptr); + + int unloadLibrary (void); + + protected: + LibraryHandle loadLibrary (const std::string &filename); + + private: + std::string _filename; + LibraryHandle _handlePtr; +}; + +class LibraryManagerException : public std::runtime_error { + + public: + + typedef enum Reason { + loadingFailed = 0, + symbolNotFound + }Reason; + + LibraryManagerException (const std::string &libraryName, const std::string &details, Reason reason); + ~LibraryManagerException (void) throw() {} + + inline Reason getReason (void) { return _reason; } + + const char* what () const throw(); + + private: + Reason _reason; + std::string _details; +}; + +#endif // LIBRARY_MANAGER_H diff --git a/src/plug-in/plugin.h b/src/plug-in/plugin.h new file mode 100644 index 0000000000000000000000000000000000000000..2769c56c372e22be24334107ef6efdf5bf4e8b31 --- /dev/null +++ b/src/plug-in/plugin.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2009 Savoir-Faire Linux inc. + * Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 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 PLUGIN_H +#define PLUGIN_H + +#include "global.h" + +#include "pluginmanager.h" + +/* + * @file plugin.h + * @brief Define a plugin object + */ + +class Plugin { + + public: + Plugin( const std::string &name ){ + _name = name; + } + + virtual ~Plugin() {} + + inline std::string getPluginName (void) { return _name; } + + /** + * Return the minimal core version required so that the plugin could work + * @return int The version required + */ + virtual int initFunc (PluginInfo **info) = 0; + + private: + Plugin &operator =(const Plugin &plugin); + + std::string _name; +}; + +typedef Plugin* createFunc (void); + +typedef void destroyFunc (Plugin*); + +#endif //PLUGIN_H + diff --git a/src/plug-in/pluginmanager.cpp b/src/plug-in/pluginmanager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8d391f6ae6383c18220484b0c98d00991184ac9b --- /dev/null +++ b/src/plug-in/pluginmanager.cpp @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2009 Savoir-Faire Linux inc. + * Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 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 <dirent.h> +#include <dlfcn.h> + +#include "pluginmanager.h" + +PluginManager* PluginManager::_instance = 0; + + PluginManager* +PluginManager::instance() +{ + if(!_instance){ + return new PluginManager(); + } + return _instance; +} + + PluginManager::PluginManager() +:_loadedPlugins() +{ + _instance = this; +} + +PluginManager::~PluginManager() +{ + _instance = 0; +} + + int +PluginManager::loadPlugins (const std::string &path) +{ + std::string pluginDir, current; + DIR *dir; + dirent *dirStruct; + LibraryManager *library; + Plugin *plugin; + + const std::string pDir = ".."; + const std::string cDir = "."; + + /* The directory in which plugins are dropped. Default: /usr/lib/sflphone/plugins/ */ + ( path == "" )? pluginDir = std::string(PLUGINS_DIR).append("/"):pluginDir = path; + _debug("Loading plugins from %s...\n", pluginDir.c_str()); + + dir = opendir( pluginDir.c_str() ); + /* Test if the directory exists or is readable */ + if( dir ){ + /* Read the directory */ + while( (dirStruct=readdir(dir)) ){ + /* Get the name of the current item in the directory */ + current = dirStruct->d_name; + /* Test if the current item is not the parent or the current directory */ + if( current != pDir && current != cDir ){ + + /* Load the dynamic library */ + library = loadDynamicLibrary( pluginDir + current ); + + /* Instanciate the plugin object */ + if(instanciatePlugin (library, &plugin) != 0) + { + _debug("Error instanciating the plugin ...\n"); + return 1; + } + + /* Regitering the current plugin */ + if(registerPlugin (plugin, library) != 0) + { + _debug("Error registering the plugin ...\n"); + return 1; + } + } + } + } + else + return 1; + + /* Close the directory */ + closedir( dir ); + + return 0; +} + +int +PluginManager::unloadPlugins (void) +{ + PluginInfo *info; + + if(_loadedPlugins.empty()) return 0; + + /* Use an iterator on the loaded plugins map */ + pluginMap::iterator iter; + + iter = _loadedPlugins.begin(); + while( iter != _loadedPlugins.end() ) { + info = iter->second; + + if (deletePlugin (info) != 0) + { + _debug("Error deleting the plugin ... \n"); + return 1; + } + + unloadDynamicLibrary (info->_libraryPtr); + + if (unregisterPlugin (info) != 0) + { + _debug("Error unregistering the plugin ... \n"); + return 1; + } + + iter++; + } + return 0; +} + + bool +PluginManager::isPluginLoaded (const std::string &name) +{ + if(_loadedPlugins.empty()) return false; + + /* Use an iterator on the loaded plugins map */ + pluginMap::iterator iter; + iter = _loadedPlugins.find (name); + + /* Returns map::end if the specified key has not been found */ + if(iter==_loadedPlugins.end()) + return false; + + /* Returns the plugin pointer */ + return true; +} + + + LibraryManager* +PluginManager::loadDynamicLibrary (const std::string& filename) +{ + /* Load the library through the library manager */ + return new LibraryManager (filename); +} + + int +PluginManager::unloadDynamicLibrary (LibraryManager *libraryPtr) +{ + _debug("Unloading dynamic library ...\n"); + /* Close it */ + return libraryPtr->unloadLibrary (); +} + + int +PluginManager::instanciatePlugin (LibraryManager *libraryPtr, Plugin **plugin) +{ + createFunc *createPlugin; + LibraryManager::SymbolHandle symbol; + + if (libraryPtr->resolveSymbol ("createPlugin", &symbol) != 0) + return 1; + createPlugin = (createFunc*)symbol; + *plugin = createPlugin(); + return 0; +} + + int +PluginManager::deletePlugin (PluginInfo *plugin) +{ + destroyFunc *destroyPlugin; + LibraryManager::SymbolHandle symbol; + + if (plugin->_libraryPtr->resolveSymbol ("destroyPlugin", &symbol) != 0) + return 1; + destroyPlugin = (destroyFunc*)symbol; + /* Call it */ + destroyPlugin (plugin->_plugin); + return 0; +} + + int +PluginManager::registerPlugin (Plugin *plugin, LibraryManager *library) +{ + std::string key; + PluginInfo *p_info; + + if( plugin==0 ) + return 1; + + p_info = new PluginInfo(); + /* Retrieve information from the plugin */ + plugin->initFunc (&p_info); + key = p_info->_name; + + //p_info->_plugin = plugin; + p_info->_libraryPtr = library; + + /* Add the data in the loaded plugin map */ + _loadedPlugins[ key ] = p_info; + return 0; +} + +int +PluginManager::unregisterPlugin (PluginInfo *plugin) +{ + pluginMap::iterator iter; + std::string key; + + key = plugin->_name; + + if (!isPluginLoaded(key)) + return 1; + + iter = _loadedPlugins.find (key); + _loadedPlugins.erase (iter); + + return 0; +} diff --git a/src/plug-in/pluginmanager.h b/src/plug-in/pluginmanager.h new file mode 100644 index 0000000000000000000000000000000000000000..4b3a1869200ce7deaac770d661d360223adbc7b0 --- /dev/null +++ b/src/plug-in/pluginmanager.h @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2009 Savoir-Faire Linux inc. + * Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 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 PLUGIN_MANAGER_H +#define PLUGIN_MANAGER_H + +/* + * @file pluginmanager.h + * @brief Base class of the plugin manager + */ + +#include "librarymanager.h" +#include "global.h" + +#include <map> +#include <string> +#include <vector> + +class Plugin; + +typedef struct PluginInfo { + std::string _name; + LibraryManager *_libraryPtr; + Plugin *_plugin; + int _major_version; + int _minor_version; +} PluginInfo; + +#include "plugin.h" + +class PluginManager { + public: + /** + * Destructor + */ + ~PluginManager(); + + /** + * Returns the unique instance of the plugin manager + */ + static PluginManager* instance(); + + /** + * Load all the plugins found in a specific directory + * @param path The absolute path to the directory + * @return int The number of items loaded + */ + int loadPlugins (const std::string &path = ""); + + int unloadPlugins (void); + + int instanciatePlugin (LibraryManager* libraryPtr, Plugin** plugin); + + /** + * Check if a plugin has been already loaded + * @param name The name of the plugin looked for + * @return bool The pointer on the plugin or NULL if not found + */ + bool isPluginLoaded (const std::string &name); + + int registerPlugin (Plugin *plugin, LibraryManager *library); + + int unregisterPlugin (PluginInfo *plugin); + + int deletePlugin (PluginInfo *plugin); + + /** + * Load a unix dynamic/shared library + * @param filename The path to the dynamic/shared library + * @return LibraryManager* A pointer on the library + */ + LibraryManager* loadDynamicLibrary (const std::string &filename); + + /** + * Unload a unix dynamic/shared library + * @param LibraryManager* The pointer on the loaded library + */ + int unloadDynamicLibrary (LibraryManager* libraryPtr); + + private: + /** + * Default constructor + */ + PluginManager(); + + /* Map of plugins associated by their string name */ + typedef std::map<std::string, PluginInfo*> pluginMap; + pluginMap _loadedPlugins; + + /* The unique static instance */ + static PluginManager* _instance; + +}; + +#endif //PLUGIN_MANAGER_H diff --git a/src/plug-in/test/Makefile.am b/src/plug-in/test/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..6809be2c0a185e16f72edcef1b57103fbcbea8f8 --- /dev/null +++ b/src/plug-in/test/Makefile.am @@ -0,0 +1,19 @@ +include $(top_srcdir)/globals.mak + +PLUGIN_LIB = libplugintest.so +libplugintest_so_SOURCES = pluginTest.cpp +libplugintest_so_CXXFLAGS = -fPIC -g -Wall +libplugintest_so_LDFLAGS = --shared -lc +INSTALL_PLUGIN_RULE = install-libplugintest_so + +noinst_PROGRAMS = libplugintest.so + +install-exec-local: install-libplugintest_so +uninstall-local: uninstall-libplugintest_so + +install-libplugintest_so: libplugintest.so + mkdir -p $(sflplugindir) + $(INSTALL_PROGRAM) libplugintest.so $(sflplugindir) + +uninstall-libplugintest_so: + rm -f $(sflplugindir)/libplugintest.so diff --git a/src/plug-in/test/pluginTest.cpp b/src/plug-in/test/pluginTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cbd1b1d760dd79797bdafead09b73fb69c1836a4 --- /dev/null +++ b/src/plug-in/test/pluginTest.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2009 Savoir-Faire Linux inc. + * Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 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 "../plugin.h" + +#define MAJOR_VERSION 1 +#define MINOR_VERSION 0 + +class PluginTest : public Plugin { + + public: + PluginTest( const std::string &name ) + :Plugin( name ) { + } + + virtual int initFunc (PluginInfo **info) { + + (*info)->_plugin = this; + (*info)->_major_version = MAJOR_VERSION; + (*info)->_minor_version = MINOR_VERSION; + (*info)->_name = getPluginName(); + + return 0; + } +}; + +extern "C" Plugin* createPlugin (void){ + return new PluginTest("mytest"); +} + +extern "C" void destroyPlugin (Plugin *p){ + delete p; +} diff --git a/src/sipvoiplink.cpp b/src/sipvoiplink.cpp index 527876d6aefc78099b2366c37cfc4cf4f09623f9..21e899d63647ed257d112373ac5c471fe600aae2 100644 --- a/src/sipvoiplink.cpp +++ b/src/sipvoiplink.cpp @@ -149,18 +149,18 @@ SIPVoIPLink* SIPVoIPLink::_instance = NULL; , _useStun(false) , _clients(0) { + _debug("SIPVoIPLink::~SIPVoIPLink(): sipvoiplink constructor called \n"); + // to get random number for RANDOM_PORT srand (time(NULL)); - /* Instanciate the C++ thread */ - _evThread = new EventThread(this); - /* Start pjsip initialization step */ init(); } SIPVoIPLink::~SIPVoIPLink() { + _debug("SIPVoIPLink::~SIPVoIPLink(): sipvoiplink destructor called \n"); terminate(); } @@ -187,6 +187,10 @@ bool SIPVoIPLink::init() { if(initDone()) return false; + + /* Instanciate the C++ thread */ + _evThread = new EventThread(this); + /* Initialize the pjsip library */ pjsip_init(); initDone(true); @@ -197,7 +201,9 @@ bool SIPVoIPLink::init() void SIPVoIPLink::terminate() { - delete _evThread; _evThread = NULL; + if (_evThread){ + delete _evThread; _evThread = NULL; + } /* Clean shutdown of pjsip library */ if( initDone() ) @@ -210,7 +216,6 @@ SIPVoIPLink::terminate() void SIPVoIPLink::terminateSIPCall() { - ost::MutexLock m(_callMapMutex); CallMap::iterator iter = _callMap.begin(); SIPCall *call; @@ -225,6 +230,23 @@ SIPVoIPLink::terminateSIPCall() _callMap.clear(); } + void +SIPVoIPLink::terminateOneCall(const CallID& id) +{ + _debug("SIPVoIPLink::terminateOneCall(): function called \n"); + + SIPCall *call; + + call = getSIPCall(id); + if (call) { + // terminate the sip call + _debug("SIPVoIPLink::terminateOneCall()::the call is deleted, should close recording file \n"); + delete call; call = 0; + } +} + + + void SIPVoIPLink::getEvent() { @@ -235,6 +257,7 @@ SIPVoIPLink::getEvent() // PJSIP polling pj_time_val timeout = {0, 10}; pjsip_endpt_handle_events( _endpt, &timeout); + } int SIPVoIPLink::sendRegister( AccountID id ) @@ -379,7 +402,7 @@ SIPVoIPLink::sendUnregister( AccountID id ) return true; } - Call* +Call* SIPVoIPLink::newOutgoingCall(const CallID& id, const std::string& toUrl) { Account* account; @@ -449,6 +472,7 @@ SIPVoIPLink::answer(const CallID& id) _debug("! SIP Failure: Unable to start sound when answering %s/%d\n", __FILE__, __LINE__); } } + terminateOneCall(call->getCallId()); removeCall(call->getCallId()); return false; } @@ -483,7 +507,8 @@ SIPVoIPLink::hangup(const CallID& id) _debug("* SIP Info: Stopping AudioRTP for hangup\n"); _audiortp->closeRtpSession(); } - + + terminateOneCall(id); removeCall(id); return true; @@ -497,6 +522,7 @@ SIPVoIPLink::cancel(const CallID& id) _debug("- SIP Action: Cancel call %s [cid: %3d]\n", id.data(), call->getCid()); + terminateOneCall(id); removeCall(id); return true; @@ -684,7 +710,7 @@ SIPVoIPLink::refuse (const CallID& id) pj_status_t status; pjsip_tx_data *tdata; - + _debug("SIPVoIPLink::refuse() : teh call is refused \n"); call = getSIPCall(id); if (call==0) { @@ -708,6 +734,8 @@ SIPVoIPLink::refuse (const CallID& id) return false; call->getInvSession()->mod_data[getModId()] = NULL; + + terminateOneCall(id); return true; } @@ -899,59 +927,66 @@ std::string SIPVoIPLink::getSipTo(const std::string& to_url, std::string hostnam return true; } - void - SIPVoIPLink::SIPCallServerFailure(SIPCall *call) - { - //if (!event->response) { return; } - //switch(event->response->status_code) { - //case SIP_SERVICE_UNAVAILABLE: // 500 - //case SIP_BUSY_EVRYWHERE: // 600 - //case SIP_DECLINE: // 603 - //SIPCall* call = findSIPCallWithCid(event->cid); - if (call != 0) { - _debug("Server error!\n"); - CallID id = call->getCallId(); - Manager::instance().callFailure(id); - removeCall(id); - } - //break; - //} - } +void +SIPVoIPLink::SIPCallServerFailure(SIPCall *call) +{ + //if (!event->response) { return; } + //switch(event->response->status_code) { + //case SIP_SERVICE_UNAVAILABLE: // 500 + //case SIP_BUSY_EVRYWHERE: // 600 + //case SIP_DECLINE: // 603 + //SIPCall* call = findSIPCallWithCid(event->cid); + if (call != 0) { + _debug("Server error!\n"); + CallID id = call->getCallId(); + Manager::instance().callFailure(id); + terminateOneCall(id); + removeCall(id); + } + //break; + //} +} - void - SIPVoIPLink::SIPCallClosed(SIPCall *call) - { - // it was without did before - //SIPCall* call = findSIPCallWithCid(event->cid); - if (!call) { return; } +void +SIPVoIPLink::SIPCallClosed(SIPCall *call) +{ - CallID id = call->getCallId(); - //call->setDid(event->did); - if (Manager::instance().isCurrentCall(id)) { - call->setAudioStart(false); - _debug("* SIP Info: Stopping AudioRTP when closing\n"); - _audiortp->closeRtpSession(); - } - _debug("After close RTP\n"); - Manager::instance().peerHungupCall(id); - removeCall(id); - _debug("After remove call ID\n"); - } +void +SIPVoIPLink::SIPCallClosed(SIPCall *call) +{ + // it was without did before + //SIPCall* call = findSIPCallWithCid(event->cid); + if (!call) { return; } - void - SIPVoIPLink::SIPCallReleased(SIPCall *call) - { - // do cleanup if exists - // only cid because did is always 0 in these case.. - //SIPCall* call = findSIPCallWithCid(event->cid); - if (!call) { return; } - - // if we are here.. something when wrong before... - _debug("SIP call release\n"); - CallID id = call->getCallId(); - Manager::instance().callFailure(id); - removeCall(id); - } + CallID id = call->getCallId(); + //call->setDid(event->did); + if (Manager::instance().isCurrentCall(id)) { + call->setAudioStart(false); + _debug("* SIP Info: Stopping AudioRTP when closing\n"); + _audiortp->closeRtpSession(); + } + _debug("After close RTP\n"); + Manager::instance().peerHungupCall(id); + terminateOneCall(id); + removeCall(id); + _debug("After remove call ID\n"); +} + +void +SIPVoIPLink::SIPCallReleased(SIPCall *call) +{ + // do cleanup if exists + // only cid because did is always 0 in these case.. + //SIPCall* call = findSIPCallWithCid(event->cid); + if (!call) { return; } + + // if we are here.. something when wrong before... + _debug("SIP call release\n"); + CallID id = call->getCallId(); + Manager::instance().callFailure(id); + terminateOneCall(id); + removeCall(id); +} void SIPVoIPLink::SIPCallAnswered(SIPCall *call, pjsip_rx_data *rdata) @@ -1287,8 +1322,42 @@ std::string SIPVoIPLink::getSipTo(const std::string& to_url, std::string hostnam return returnValue; } + void SIPVoIPLink::busy_sleep(unsigned msec) + { +#if defined(PJ_SYMBIAN) && PJ_SYMBIAN != 0 + /* Ideally we shouldn't call pj_thread_sleep() and rather + * CActiveScheduler::WaitForAnyRequest() here, but that will + * drag in Symbian header and it doesn't look pretty. + */ + pj_thread_sleep(msec); +#else + pj_time_val timeout, now, tv; + + pj_gettimeofday(&timeout); + timeout.msec += msec; + pj_time_val_normalize(&timeout); + + tv.sec = 0; + tv.msec = 10; + pj_time_val_normalize(&tv); + + do { + pjsip_endpt_handle_events(_endpt, &tv); + pj_gettimeofday(&now); + } while (PJ_TIME_VAL_LT(now, timeout)); +#endif +} + bool SIPVoIPLink::pjsip_shutdown( void ) { + if (_endpt) { + _debug("UserAgent: Shutting down...\n"); + busy_sleep(1000); + } + + pj_thread_destroy( thread ); + thread = NULL; + /* Destroy endpoint. */ if (_endpt) { pjsip_endpt_destroy(_endpt); diff --git a/src/sipvoiplink.h b/src/sipvoiplink.h index 03b12e6c38ba2d0dc8eae5dd73f3a9a9916f5720..4a87f111c9d25160e947e0009f5fcea14404cac5 100644 --- a/src/sipvoiplink.h +++ b/src/sipvoiplink.h @@ -191,6 +191,11 @@ class SIPVoIPLink : public VoIPLink * Terminate every call not hangup | brutal | Protected by mutex */ void terminateSIPCall(); + + /** + * Terminate only one call + */ + void terminateOneCall(const CallID& id); /** * Build a sip address with the number that you want to call @@ -284,6 +289,7 @@ class SIPVoIPLink : public VoIPLink /* The singleton instance */ static SIPVoIPLink* _instance; + void busy_sleep(unsigned msec); int getModId(); /** diff --git a/test/Makefile.am b/test/Makefile.am index 14411aa140bbc3264308b27f0cd418287544821c..5c684888b422490c0e15316692bc4fcee3eceb78 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1,6 +1,6 @@ include ../globals.mak -bin_PROGRAMS = configurationTester +bin_PROGRAMS = configurationTester pluginmanagerTester audiorecorderTester OBJECT_FILES= \ ../src/sflphoned-managerimpl.o \ @@ -15,7 +15,8 @@ OBJECT_FILES= \ ../src/sflphoned-sipaccount.o \ ../src/sflphoned-iaxaccount.o \ ../src/sflphoned-eventthread.o \ - ../src/sflphoned-useragent.o \ + ../src/plug-in/pluginmanager.o \ + ../src/plug-in/audiorecorder/audiorecord.o \ ../src/sflphoned-samplerateconverter.o configurationTester_SOURCES = \ @@ -23,6 +24,17 @@ configurationTester_SOURCES = \ configurationTest.h \ TestMain.cpp +pluginmanagerTester_SOURCES = \ + pluginmanagerTest.h \ + pluginmanagerTest.cpp \ + TestMain.cpp + +audiorecorderTester_SOURCES = \ + audiorecorderTest.h \ + audiorecorderTest.cpp \ + TestMain.cpp + + configurationTester_LDADD = \ ../src/libsflphone.la \ $(SFLPHONE_LIBS) $(ZEROCONFLIB) $(LIB_DNSSD) $(IAX_LIBS) \ @@ -36,4 +48,32 @@ configurationTester_LDADD = \ @SAMPLERATE_LIBS@ \ $(PJSIP_LIBS) \ $(OBJECT_FILES) - + +pluginmanagerTester_LDADD = \ + ../src/libsflphone.la \ + $(SFLPHONE_LIBS) $(ZEROCONFLIB) $(LIB_DNSSD) $(IAX_LIBS) \ + @ALSA_LIBS@ \ + @PULSEAUDIO_LIBS@ \ + @CPPUNIT_LIBS@ \ + @CCEXT2_LIBS@ \ + @CCGNU2_LIBS@ \ + @CCRTP_LIBS@ \ + @DBUSCPP_LIBS@ \ + @SAMPLERATE_LIBS@ \ + $(PJSIP_LIBS) \ + $(OBJECT_FILES) + +audiorecorderTester_LDADD = \ + ../src/libsflphone.la \ + $(SFLPHONE_LIBS) $(ZEROCONFLIB) $(LIB_DNSSD) $(IAX_LIBS) \ + @ALSA_LIBS@ \ + @PULSEAUDIO_LIBS@ \ + @CPPUNIT_LIBS@ \ + @CCEXT2_LIBS@ \ + @CCGNU2_LIBS@ \ + @CCRTP_LIBS@ \ + @DBUSCPP_LIBS@ \ + @SAMPLERATE_LIBS@ \ + $(PJSIP_LIBS) \ + $(OBJECT_FILES) + diff --git a/test/audiorecorderTest.cpp b/test/audiorecorderTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f766d4af1d082307a256fe08c6506806810d733a --- /dev/null +++ b/test/audiorecorderTest.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2009 Savoir-Faire Linux inc. + * Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 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 <stdio.h> +#include <sstream> + +#include "audiorecorderTest.h" + +using std::cout; +using std::endl; + +void AudioRecorderTest::setUp(){ + // Instanciate the object + _ar = new AudioRecord(); +} + +void AudioRecorderTest::testRecordData(){ + + FILE_TYPE ft = FILE_WAV; + SOUND_FORMAT sf = INT16; + _ar->setSndSamplingRate(44100); + _ar->openFile("theWavFile.wav",ft,sf); + + cout << "file opened!\n"; + + SFLDataFormat buf [2]; + for (SFLDataFormat i = -32768; i < 32767; i++ ){ + buf[0] = i; + buf[1] = i; + _ar->recData(buf,2); + } + + _ar->closeFile(); +} + +void AudioRecorderTest::tearDown(){ + // Delete the audio recorder module + delete _ar; _ar = NULL; +} diff --git a/test/audiorecorderTest.h b/test/audiorecorderTest.h new file mode 100644 index 0000000000000000000000000000000000000000..216b657079562007a1eb04955f390e3263ef1c87 --- /dev/null +++ b/test/audiorecorderTest.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2009 Savoir-Faire Linux inc. + * Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 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. + */ + +// Cppunit import +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/TestCaller.h> +#include <cppunit/TestCase.h> +#include <cppunit/TestSuite.h> + +#include <assert.h> + +// Application import +#include "plug-in/pluginmanager.h" +#include "plug-in/audiorecorder/audiorecord.h" + +/* + * @file audiorecorderTest.cpp + * @brief Regroups unitary tests related to the plugin manager. + */ + +#ifndef _AUDIORECORDER_TEST_ +#define _AUDIORECORDER_TEST_ + +class AudioRecorderTest : public CppUnit::TestCase { + + /* + * Use cppunit library macros to add unit test the factory + */ + CPPUNIT_TEST_SUITE( AudioRecorderTest ); + CPPUNIT_TEST( testRecordData ); + CPPUNIT_TEST_SUITE_END(); + + public: + AudioRecorderTest() : CppUnit::TestCase("Audio Recorder Tests") {} + + /* + * Code factoring - Common resources can be initialized here. + * This method is called by unitcpp before each test + */ + void setUp(); + + /* + * Code factoring - Common resources can be released here. + * This method is called by unitcpp after each test + */ + inline void tearDown(); + + void testRecordData(); + + private: + AudioRecord *_ar; +}; + +/* Register our test module */ +CPPUNIT_TEST_SUITE_REGISTRATION( AudioRecorderTest ); + +#endif diff --git a/test/pluginmanagerTest.cpp b/test/pluginmanagerTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..96994b6925219cfc565906873e8d6574fcc3c238 --- /dev/null +++ b/test/pluginmanagerTest.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2009 Savoir-Faire Linux inc. + * Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 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 <stdio.h> +#include <sstream> +#include <dlfcn.h> + +#include "pluginmanagerTest.h" + +using std::cout; +using std::endl; + +#define PLUGIN_TEST_DIR "/usr/lib/sflphone/plugins/" +#define PLUGIN_TEST_DESC "mytest" +#define PLUGIN_TEST_NAME "/usr/lib/sflphone/plugins/libplugintest.so" + + +void PluginManagerTest::setUp(){ + // Instanciate the plugin manager singleton + _pm = PluginManager::instance(); + library = 0; + plugin = 0; +} + +void PluginManagerTest::testLoadDynamicLibrary(){ + CPPUNIT_ASSERT(_pm->loadDynamicLibrary(PLUGIN_TEST_NAME) != NULL); +} + +void PluginManagerTest::testUnloadDynamicLibrary(){ + library = _pm->loadDynamicLibrary(PLUGIN_TEST_NAME); + CPPUNIT_ASSERT(library != NULL); + CPPUNIT_ASSERT(_pm->unloadDynamicLibrary(library) == 0 ); +} + +void PluginManagerTest::testInstanciatePlugin(){ + library = _pm->loadDynamicLibrary (PLUGIN_TEST_NAME); + CPPUNIT_ASSERT(library != NULL); + CPPUNIT_ASSERT (_pm->instanciatePlugin (library, &plugin) == 0); + CPPUNIT_ASSERT (plugin!=NULL); +} + +void PluginManagerTest::testInitPlugin(){ + + library = _pm->loadDynamicLibrary (PLUGIN_TEST_NAME); + CPPUNIT_ASSERT(library != NULL); + CPPUNIT_ASSERT (_pm->instanciatePlugin (library, &plugin) == 0); + CPPUNIT_ASSERT (plugin!=NULL); + CPPUNIT_ASSERT (plugin->getPluginName() == PLUGIN_TEST_DESC); +} + +void PluginManagerTest::testRegisterPlugin(){ + library = _pm->loadDynamicLibrary (PLUGIN_TEST_NAME); + CPPUNIT_ASSERT(library != NULL); + CPPUNIT_ASSERT (_pm->instanciatePlugin (library, &plugin) == 0); + CPPUNIT_ASSERT (_pm->isPluginLoaded (PLUGIN_TEST_DESC) == false); + CPPUNIT_ASSERT (_pm->registerPlugin (plugin, library) == 0); + CPPUNIT_ASSERT (_pm->isPluginLoaded (PLUGIN_TEST_DESC) == true); +} + +void PluginManagerTest::testLoadPlugins (){ + CPPUNIT_ASSERT (_pm->loadPlugins (PLUGIN_TEST_DIR) == 0); + CPPUNIT_ASSERT (_pm->isPluginLoaded (PLUGIN_TEST_DESC) == true); +} + +void PluginManagerTest::testUnloadPlugins (){ + CPPUNIT_ASSERT (_pm->loadPlugins (PLUGIN_TEST_DIR) == 0); + CPPUNIT_ASSERT (_pm->isPluginLoaded (PLUGIN_TEST_DESC) == true); + CPPUNIT_ASSERT (_pm->unloadPlugins () == 0); + CPPUNIT_ASSERT (_pm->isPluginLoaded (PLUGIN_TEST_DESC) == false); +} + +void PluginManagerTest::tearDown(){ + // Delete the plugin manager object + delete _pm; _pm=0; + if(plugin) + delete plugin; plugin = 0; + if(library) + delete library; library = 0; +} diff --git a/test/pluginmanagerTest.h b/test/pluginmanagerTest.h new file mode 100644 index 0000000000000000000000000000000000000000..2e421958460445c3339ea1c2a97cef767258fabc --- /dev/null +++ b/test/pluginmanagerTest.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2009 Savoir-Faire Linux inc. + * Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 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. + */ + +// Cppunit import +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/TestCaller.h> +#include <cppunit/TestCase.h> +#include <cppunit/TestSuite.h> + +#include <assert.h> + +// Application import +#include "plug-in/pluginmanager.h" +#include "plug-in/librarymanager.h" +#include "plug-in/plugin.h" + +/* + * @file pluginManagerTest.cpp + * @brief Regroups unitary tests related to the plugin manager. + */ + +#ifndef _PLUGINMANAGER_TEST_ +#define _PLUGINMANAGER_TEST_ + +class PluginManagerTest : public CppUnit::TestCase { + + /* + * Use cppunit library macros to add unit test the factory + */ + CPPUNIT_TEST_SUITE( PluginManagerTest ); + CPPUNIT_TEST( testLoadDynamicLibrary ); + CPPUNIT_TEST( testUnloadDynamicLibrary ); + CPPUNIT_TEST( testInstanciatePlugin ); + CPPUNIT_TEST( testInitPlugin ); + CPPUNIT_TEST( testRegisterPlugin ); + CPPUNIT_TEST( testLoadPlugins ); + CPPUNIT_TEST( testUnloadPlugins ); + CPPUNIT_TEST_SUITE_END(); + + public: + PluginManagerTest() : CppUnit::TestCase("Plugin Manager Tests") {} + + /* + * Code factoring - Common resources can be initialized here. + * This method is called by unitcpp before each test + */ + void setUp(); + + /* + * Code factoring - Common resources can be released here. + * This method is called by unitcpp after each test + */ + inline void tearDown (); + + void testLoadDynamicLibrary (); + + void testUnloadDynamicLibrary (); + + void testInstanciatePlugin (); + + void testInitPlugin (); + + void testRegisterPlugin (); + + void testLoadPlugins (); + + void testUnloadPlugins (); + + private: + PluginManager *_pm; + LibraryManager *library; + Plugin *plugin; +}; + +/* Register our test module */ +CPPUNIT_TEST_SUITE_REGISTRATION( PluginManagerTest ); + +#endif