From 3a49a52b45ce067d19b174be28614222ce2eb655 Mon Sep 17 00:00:00 2001 From: Yun Liu Date: Fri, 23 Jan 2009 16:47:04 -0500 Subject: [PATCH 01/14] update build package script to support mutiple platforms (Ubuntu, Fedora 10 and OpenSUSE 11) --- build-package.sh | 100 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 77 insertions(+), 23 deletions(-) diff --git a/build-package.sh b/build-package.sh index a2c775ac0..8868baf61 100755 --- a/build-package.sh +++ b/build-package.sh @@ -2,16 +2,48 @@ # # @author: Yun Liu # -# Build sflphone debian packages for Ubuntu 8.04 +# Build sflphone rpm packages for Fedora 10 and openSUSE 11 # 1 - The SFLphone package must be build with a specific GnuPG key. Please contact us to have more information about that () # 2. The source code can be teched through anonymous http access. So no need of special access. -# 3. After having all the prerequisites, you can run "build-package.sh" to build debian packages for sflphone. -# All the source packages and binary packages will be generated in the current directory. +# 3. After having all the prerequisites, you can run "build-rpm-package.sh" to build rpm packages for sflphone. +# # Refer to http://www.sflphone.org for futher information +# Analyze parameters +if [ "$1" == "--help" ] || [ "$1" == "" ];then + echo -e '\E[34mThis script is used to build sflphone rpm packages on ubuntu series(8.04,8,10,9), Fedora 10 and SUSE 11 platform.' + echo -e '\E[34mYou can add --fedora, --suse or --ubuntu to start packaging.' + echo + echo "The SFLphone package must be build with a specific GnuPG key. Please contact us to have more information about that ()" + echo + echo "For fedora and SUSE, you also need to add the following lines to $HOME/.rpmmacros:" + echo -e '\E[32m%_gpg_path /home/yun/.gnupg' + echo -e '\E[32m%_gpg_name Savoir-Faire Linux Inc. (Génération des paquets pour SFLphone) ' + echo -e '\E[32m%_gpgbin /usr/bin/gpg' + echo + echo -e '\E[34mAfter all these preparations done, you can run ./build-package.sh --platform-name' + echo + echo -e '\E[36mHave fun!' + + tput sgr0 # Reset colors to "normal." + echo + exit 1 +elif [ $1 == "--fedora" ];then + BUILDDIR=$HOME/rpmbuild + platform="fedora" +elif [ $1 == "--suse" ];then + BUILDDIR=/usr/src/packages + platform="suse" +elif [ $1 == "--ubuntu" ];then + platform="ubuntu" +else + echo "This script can only be used for Ubuntu series, Fedora 10 and SUSE 11 platform. Use --help to get more information." + exit 1 +fi + if [ -d "sflphone" ]; then echo "Directory sflphone already exists. Please remove it first." - exit 1 + exit 1 fi # Anonymous git http access @@ -22,33 +54,55 @@ git checkout origin/release -b release # Get system parameters arch_flag=`getconf -a|grep LONG_BIT | sed -e 's/LONG_BIT\s*//'` os_version=`lsb_release -d -s -c | sed -e '1d'` +ver=0.9.2 + +if [ $platform == "ubuntu" ];then + # Generate the changelog, according to the distribution and the git commit messages + cp debian/changelog.$os_version debian/changelog + git-dch --debian-branch=release --release +fi -# Generate the changelog, according to the distribution and the git commit messages -cp debian/changelog.$os_version debian/changelog -git-dch --debian-branch=release --release cd .. # Remove useless git directory rm sflphone/.git/ -rf -# Copy the appropriate control file based on different archtecture -cp sflphone/debian/control.$os_version sflphone/debian/control - -echo "Building sflphone package on Ubuntu $os_version $arch_flag bit architecture...." - -# Provide prerequisite directories used by debuild -cp sflphone sflphone-0.9.2 -r -cp sflphone sflphone-0.9.2.orig -r - # Get the public gpg key to sign the packages wget -q http://www.sflphone.org/downloads/gpg/sflphone.gpg.asc -O- | gpg --import - -# Build packages -cd sflphone-0.9.2/debian; debuild -k'Savoir-Faire Linux Inc.' +if [ $platform == "ubuntu" ];then + # Copy the appropriate control file based on different archtecture + cp sflphone/debian/control.$os_version sflphone/debian/control -# Clean -cd ../.. -rm sflphone-0.9.2/ -rf -rm sflphone/ -rf + echo "Building sflphone package on Ubuntu $os_version $arch_flag bit architecture...." + exit + # Provide prerequisite directories used by debuild + cp sflphone sflphone-$ver -r + cp sflphone sflphone-$ver.orig -r + + # Build packages + cd sflphone-$ver/debian; debuild -k'Savoir-Faire Linux Inc.' -echo "Building package finished successullly!" + # Post clean + cd .. + rm sflphone-$ver sflphone -rf + echo "Done! All the source packages and binary packages are generated in the current directory" + +else + # Prepare for packaging + mv sflphone sflphone-$ver + + cp sflphone-$ver/platform/$platform.spec $BUILDDIR/SPECS/ + cp sflphone-$ver/libs/pjproject-1.0/libpj-sfl.pc $BUILDDIR/SOURCES + tar zcvf sflphone-$ver.tar.gz sflphone-$ver + + rm sflphone-$ver -rf + mv sflphone-$ver.tar.gz $BUILDDIR/SOURCES + echo "Building sflphone package on $platform $arch_flag bit architecture...." + + # Build packages + cd $BUILDDIR/SPECS/ + rpmbuild -ba --sign sflphone.spec + + echo "Done! All source rpms and binary rpms are stored in $BUILDDIR/SRPMS and $BUILDDIR/RPMS" +fi From a3fe8cd5cafed154366b0214a381f915dc9c5def Mon Sep 17 00:00:00 2001 From: Yun Liu Date: Fri, 23 Jan 2009 18:02:14 -0500 Subject: [PATCH 02/14] Fix bug in build script file --- build-package.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/build-package.sh b/build-package.sh index 8868baf61..78aa9774b 100755 --- a/build-package.sh +++ b/build-package.sh @@ -75,7 +75,6 @@ if [ $platform == "ubuntu" ];then cp sflphone/debian/control.$os_version sflphone/debian/control echo "Building sflphone package on Ubuntu $os_version $arch_flag bit architecture...." - exit # Provide prerequisite directories used by debuild cp sflphone sflphone-$ver -r cp sflphone sflphone-$ver.orig -r From 26393bbec7a6255ce1dadb70dfedc00a9838c026 Mon Sep 17 00:00:00 2001 From: Emmanuel Milou Date: Sun, 25 Jan 2009 12:36:53 -0500 Subject: [PATCH 03/14] Build template architecture for the plugin manager --- autogen.sh | 2 +- configure.ac | 7 +++--- src/Makefile.am | 2 +- src/plug-in/Makefile.am | 5 +++++ src/plug-in/plugin.cpp | 26 ++++++++++++++++++++++ src/plug-in/plugin.h | 41 +++++++++++++++++++++++++++++++++++ src/plug-in/pluginmanager.cpp | 6 +++++ src/plug-in/pluginmanager.h | 33 ++++++++++++++++++++++++++++ 8 files changed, 117 insertions(+), 5 deletions(-) create mode 100644 src/plug-in/Makefile.am create mode 100644 src/plug-in/plugin.cpp create mode 100644 src/plug-in/plugin.h create mode 100644 src/plug-in/pluginmanager.cpp create mode 100644 src/plug-in/pluginmanager.h diff --git a/autogen.sh b/autogen.sh index 06b6a97c9..ac85bd137 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 d9b4ed6dd..3cb974e0f 100644 --- a/configure.ac +++ b/configure.ac @@ -2,8 +2,8 @@ dnl SFLPhone - configure.ac for automake 1.9 and autoconf 2.59 dnl dnl Process this file with autoconf to produce a configure script. AC_PREREQ(2.59) -AC_INIT([SFLPhone],[0.7],[sflphoneteam@savoirfairelinux.com],[sflphone]) -AC_COPYRIGHT([[Copyright (c) Savoir-Faire Linux 2004-2008]]) +AC_INIT([SFLPhone],[0.9.2-7],[sflphoneteam@savoirfairelinux.com],[sflphone]) +AC_COPYRIGHT([[Copyright (c) Savoir-Faire Linux 2004-2009]]) AC_REVISION([$Revision$]) dnl Compute canonical system name @@ -37,7 +37,8 @@ AC_CONFIG_FILES([src/Makefile \ src/audio/codecs/ilbc/Makefile \ src/config/Makefile \ src/dbus/Makefile \ - src/zeroconf/Makefile]) + src/zeroconf/Makefile \ + src/plug-in/Makefile]) dnl Unitary test section AC_CONFIG_FILES([test/Makefile]) diff --git a/src/Makefile.am b/src/Makefile.am index 5be031174..f9af16aaf 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -23,7 +23,7 @@ IAXSOURCES = IAXHEADERS = endif -SUBDIRS = audio config dbus $(ZEROCONFDIR) +SUBDIRS = audio config dbus $(ZEROCONFDIR) plug-in # Add here the cpp files to be build with sflphone sflphoned_SOURCES = \ diff --git a/src/plug-in/Makefile.am b/src/plug-in/Makefile.am new file mode 100644 index 000000000..de286d046 --- /dev/null +++ b/src/plug-in/Makefile.am @@ -0,0 +1,5 @@ +noinst_LTLIBRARIES = libplugin.la + +libplugin_la_SOURCES = \ + pluginmanager.cpp + plugin.cpp diff --git a/src/plug-in/plugin.cpp b/src/plug-in/plugin.cpp new file mode 100644 index 000000000..bc7cf18c3 --- /dev/null +++ b/src/plug-in/plugin.cpp @@ -0,0 +1,26 @@ +#include "plugin.h" + +Plugin::Plugin( const std::string &filename ) +{ + //TODO IMPLEMENT +} + +Plugin::Plugin( const Plugin &plugin ) +{ + //TODO IMPLEMENT +} + +Plugin::~Plugin() +{ + //TODO IMPLEMENT +} + +int Plugin::getCoreVersion( void ) +{ + //TODO IMPLEMENT +} + +void Plugin::registerPlugin( PluginManager & ) +{ + //TODO IMPLEMENT +} diff --git a/src/plug-in/plugin.h b/src/plug-in/plugin.h new file mode 100644 index 000000000..5c825f872 --- /dev/null +++ b/src/plug-in/plugin.h @@ -0,0 +1,41 @@ +#ifndef PLUGIN_H +#define PLUGIN_H + +#include + +/* + * @file plugin.h + * @brief Define a plugin object + */ + +namespace sflphone { + +class PluginManager; + + class Plugin { + + public: + Plugin( const std::string &filename ); + Plugin( const Plugin &plugin ); + ~Plugin(); + + public: + /** + * Return the minimal core version required so that the plugin could work + * @return int The version required + */ + int getCoreVersion() const; + + /** + * Register the plugin to the plugin manager + */ + void registerPlugin( PluginManager & ); + + private: + Plugin &operator =(const Plugin &plugin); + + }; +} + +#endif //PLUGIN_H + diff --git a/src/plug-in/pluginmanager.cpp b/src/plug-in/pluginmanager.cpp new file mode 100644 index 000000000..9c792dc3f --- /dev/null +++ b/src/plug-in/pluginmanager.cpp @@ -0,0 +1,6 @@ +#include "pluginmanager.h" + +void ::sflphone::PluginManager::loadPlugins( const std::string &path ) +{ + //TODO IMPLEMENT +} diff --git a/src/plug-in/pluginmanager.h b/src/plug-in/pluginmanager.h new file mode 100644 index 000000000..d91d115d4 --- /dev/null +++ b/src/plug-in/pluginmanager.h @@ -0,0 +1,33 @@ +#ifndef PLUGIN_MANAGER_H +#define PLUGIN_MANAGER_H + +/* + * @file pluginmanager.h + * @brief Base class of the plugin manager + */ + +#include "plugin.h" + +#include +#include + +namespace sflphone { + + class PluginManager { + + public: + /** + * Load all the plugins found in a specific directory + * @param path The absolute path to the directory + */ + void loadPlugins( const std::string &path ); + + private: + /* Map of plugins associated by their string name */ + typedef std::map pluginMap; + + pluginMap _loadedPlugins; + }; +} + +#endif //PLUGIN_MANAGER_H From 6cfa328d7eb41e272c48c44008325b2b1436681f Mon Sep 17 00:00:00 2001 From: Emmanuel Milou Date: Sun, 25 Jan 2009 23:47:17 -0500 Subject: [PATCH 04/14] Add the dynamic loading for the plugin framework; integate unit tests --- globals.mak | 2 + src/Makefile.am | 1 + src/plug-in/Makefile.am | 7 ++- src/plug-in/plugin.cpp | 11 ++-- src/plug-in/plugin.h | 12 +++-- src/plug-in/pluginmanager.cpp | 96 ++++++++++++++++++++++++++++++++++- src/plug-in/pluginmanager.h | 45 ++++++++++++++-- test/Makefile.am | 24 ++++++++- test/pluginmanagerTest.cpp | 44 ++++++++++++++++ test/pluginmanagerTest.h | 75 +++++++++++++++++++++++++++ 10 files changed, 298 insertions(+), 19 deletions(-) create mode 100644 test/pluginmanagerTest.cpp create mode 100644 test/pluginmanagerTest.h diff --git a/globals.mak b/globals.mak index c03985035..7a0b085b9 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 f9af16aaf..90953f160 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -87,6 +87,7 @@ libsflphone_la_LIBADD = \ ./audio/libaudio.la \ ./dbus/libdbus.la \ ./config/libconfig.la \ + ./plug-in/libplugin.la \ $(IAX_LIBS) libsflphone_la_SOURCES = diff --git a/src/plug-in/Makefile.am b/src/plug-in/Makefile.am index de286d046..53bf6b050 100644 --- a/src/plug-in/Makefile.am +++ b/src/plug-in/Makefile.am @@ -1,5 +1,8 @@ +include ../../globals.mak + noinst_LTLIBRARIES = libplugin.la libplugin_la_SOURCES = \ - pluginmanager.cpp - plugin.cpp + pluginmanager.cpp \ + plugin.h + diff --git a/src/plug-in/plugin.cpp b/src/plug-in/plugin.cpp index bc7cf18c3..495437076 100644 --- a/src/plug-in/plugin.cpp +++ b/src/plug-in/plugin.cpp @@ -1,26 +1,27 @@ #include "plugin.h" -Plugin::Plugin( const std::string &filename ) +::sflphone::Plugin::Plugin( const std::string &filename UNUSED ) { //TODO IMPLEMENT } -Plugin::Plugin( const Plugin &plugin ) +::sflphone::Plugin::Plugin( const Plugin &plugin UNUSED ) { //TODO IMPLEMENT } -Plugin::~Plugin() +::sflphone::Plugin::~Plugin() { //TODO IMPLEMENT } -int Plugin::getCoreVersion( void ) +int ::sflphone::Plugin::getCoreVersion( void ) const { //TODO IMPLEMENT + return 1; } -void Plugin::registerPlugin( PluginManager & ) +void ::sflphone::Plugin::registerPlugin( PluginManager & ) { //TODO IMPLEMENT } diff --git a/src/plug-in/plugin.h b/src/plug-in/plugin.h index 5c825f872..100d6ea5b 100644 --- a/src/plug-in/plugin.h +++ b/src/plug-in/plugin.h @@ -3,6 +3,8 @@ #include +#include "global.h" + /* * @file plugin.h * @brief Define a plugin object @@ -15,21 +17,21 @@ class PluginManager; class Plugin { public: - Plugin( const std::string &filename ); - Plugin( const Plugin &plugin ); - ~Plugin(); + Plugin( const std::string &name ); + //Plugin( const Plugin &plugin ); + virtual ~Plugin() {} public: /** * Return the minimal core version required so that the plugin could work * @return int The version required */ - int getCoreVersion() const; + virtual int getCoreVersion() const = 0; /** * Register the plugin to the plugin manager */ - void registerPlugin( PluginManager & ); + virtual void registerPlugin( PluginManager & ) = 0; private: Plugin &operator =(const Plugin &plugin); diff --git a/src/plug-in/pluginmanager.cpp b/src/plug-in/pluginmanager.cpp index 9c792dc3f..6012a59bd 100644 --- a/src/plug-in/pluginmanager.cpp +++ b/src/plug-in/pluginmanager.cpp @@ -1,6 +1,98 @@ +#include +#include + #include "pluginmanager.h" -void ::sflphone::PluginManager::loadPlugins( const std::string &path ) +::sflphone::PluginManager::PluginManager():_loadedPlugins() { - //TODO IMPLEMENT + _instance = this; } + +::sflphone::PluginManager::~PluginManager() +{ + _instance = 0; +} + +int ::sflphone::PluginManager::loadPlugins( const std::string &path ) +{ + std::string pluginDir, current; + ::sflphone::Plugin *plugin; + DIR *dir; + dirent *dirStruct; + int result=0; + + 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 ){ + loadDynamicLibrary( current ); + result++; + } + } + } + /* Close the directory */ + closedir( dir ); + + return result; +} + +::sflphone::Plugin* ::sflphone::PluginManager::isPluginLoaded( const std::string &name ) +{ + if(_loadedPlugins.empty()) return NULL; + + /* Use an iterator on the loaded plugins map */ + pluginMap::iterator iter; + + iter = _loadedPlugins.begin(); + while( iter != _loadedPlugins.end() ) { + if ( iter->first == name ) { + /* Return the associated plugin */ + return iter->second; + } + iter++; + } + + /* If we are here, it means that the plugin we were looking for has not been loaded */ + return NULL; +} + +void* ::sflphone::PluginManager::loadDynamicLibrary( const std::string& filename ) { + + void *pluginHandlePtr = NULL; + const char *error; + + _debug("Loading dynamic library %s\n", filename.c_str()); + +#if defined(Q_OS_UNIX) + /* Load the library */ + pluginHandlePtr = dlopen( filename.c_str(), RTLD_LAZY ); + if( !pluginHandlePtr ) { + error = dlerror(); + _debug("Error while opening plug-in: %s\n", error); + } + dlerror(); +#endif + + return pluginHandlePtr; +} + +void ::sflphone::PluginManager::unloadDynamicLibrary( void * pluginHandlePtr ) { + + dlclose( pluginHandlePtr ); + dlerror(); +} + +::sflphone::PluginManager* ::sflphone::PluginManager::_instance = 0; + diff --git a/src/plug-in/pluginmanager.h b/src/plug-in/pluginmanager.h index d91d115d4..651a0902f 100644 --- a/src/plug-in/pluginmanager.h +++ b/src/plug-in/pluginmanager.h @@ -7,6 +7,7 @@ */ #include "plugin.h" +#include "global.h" #include #include @@ -16,17 +17,55 @@ namespace sflphone { class PluginManager { public: + /** + * Default constructor + */ + PluginManager(); + + /** + * 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 */ - void loadPlugins( const std::string &path ); + int loadPlugins( const std::string &path = "" ); + + /** + * Check if a plugin has been already loaded + * @param name The name of the plugin looked for + * @return Plugin* The pointer on the plugin or NULL if not found + */ + Plugin* isPluginLoaded( const std::string &name ); private: - /* Map of plugins associated by their string name */ - typedef std::map pluginMap; + /** + * Load a unix dynamic/shared library + * @param filename The path to the dynamic/shared library + * @return void* A pointer on it + */ + void * loadDynamicLibrary( const std::string &filename ); + /** + * Unload a unix dynamic/shared library + * @param pluginHandleptr The pointer on the loaded plugin + */ + void unloadDynamicLibrary( void * pluginHandlePtr ); + + /* Map of plugins associated by their string name */ + typedef std::map pluginMap; pluginMap _loadedPlugins; + + /* The unique static instance */ + static PluginManager* _instance; }; } diff --git a/test/Makefile.am b/test/Makefile.am index 14411aa14..86e70dbc3 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1,6 +1,6 @@ include ../globals.mak -bin_PROGRAMS = configurationTester +bin_PROGRAMS = configurationTester pluginmanagerTester OBJECT_FILES= \ ../src/sflphoned-managerimpl.o \ @@ -16,6 +16,7 @@ OBJECT_FILES= \ ../src/sflphoned-iaxaccount.o \ ../src/sflphoned-eventthread.o \ ../src/sflphoned-useragent.o \ + ../src/plug-in/pluginmanager.o \ ../src/sflphoned-samplerateconverter.o configurationTester_SOURCES = \ @@ -23,6 +24,11 @@ configurationTester_SOURCES = \ configurationTest.h \ TestMain.cpp +pluginmanagerTester_SOURCES = \ + pluginmanagerTest.h \ + pluginmanagerTest.cpp \ + TestMain.cpp + configurationTester_LDADD = \ ../src/libsflphone.la \ $(SFLPHONE_LIBS) $(ZEROCONFLIB) $(LIB_DNSSD) $(IAX_LIBS) \ @@ -36,4 +42,18 @@ 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) + diff --git a/test/pluginmanagerTest.cpp b/test/pluginmanagerTest.cpp new file mode 100644 index 000000000..b9a3d413a --- /dev/null +++ b/test/pluginmanagerTest.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2009 Savoir-Faire Linux inc. + * Author: Emmanuel Milou + * + * 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 +#include + +#include "pluginmanagerTest.h" + +using std::cout; +using std::endl; + +void PluginManagerTest::setUp(){ + // Instanciate the plugin manager object + _pm = new ::sflphone::PluginManager(); +} + +void PluginManagerTest::testLoadPluginDirectory(){ + _pm->loadPlugins(); +} + +void PluginManagerTest::testNonloadedPlugin(){ + CPPUNIT_ASSERT( _pm->isPluginLoaded("test") == NULL ); +} + +void PluginManagerTest::tearDown(){ + // Delete the plugin manager object + delete _pm; _pm=NULL; +} diff --git a/test/pluginmanagerTest.h b/test/pluginmanagerTest.h new file mode 100644 index 000000000..e43ba8f7a --- /dev/null +++ b/test/pluginmanagerTest.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2009 Savoir-Faire Linux inc. + * Author: Emmanuel Milou + * + * 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 +#include +#include +#include + +#include + +// Application import +#include "plug-in/pluginmanager.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( testLoadPluginDirectory ); + CPPUNIT_TEST( testNonloadedPlugin ); + 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 testLoadPluginDirectory(); + + void testNonloadedPlugin(); + + private: + ::sflphone::PluginManager *_pm; +}; + +/* Register our test module */ +CPPUNIT_TEST_SUITE_REGISTRATION( PluginManagerTest ); + +#endif From 25b02cfa06b70496a9c5b00d1b664afee07f47e9 Mon Sep 17 00:00:00 2001 From: alexandresavard Date: Mon, 26 Jan 2009 16:04:17 -0500 Subject: [PATCH 05/14] Add audio Recording class, edit global.h --- src/audio/audiorecord.cpp | 177 ++++++++++++++++++++++++++++++++++++++ src/audio/audiorecord.h | 127 +++++++++++++++++++++++++++ src/global.h | 13 +++ 3 files changed, 317 insertions(+) create mode 100644 src/audio/audiorecord.cpp create mode 100644 src/audio/audiorecord.h diff --git a/src/audio/audiorecord.cpp b/src/audio/audiorecord.cpp new file mode 100644 index 000000000..65f638039 --- /dev/null +++ b/src/audio/audiorecord.cpp @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2008 Savoir-Faire Linux inc. + * Author: Alexandre Savard + * + * 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 + * + * 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 +#include + +#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/global.h b/src/global.h index e752d41b2..259f34e76 100644 --- a/src/global.h +++ b/src/global.h @@ -32,6 +32,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; \ From 3d03dde08d8cdf62101e8514d26e741e118cf19a Mon Sep 17 00:00:00 2001 From: alexandresavard Date: Mon, 26 Jan 2009 17:04:48 -0500 Subject: [PATCH 06/14] Not much --- src/Makefile.am | 1 + src/audio/pulselayer.h | 1 + 2 files changed, 2 insertions(+) diff --git a/src/Makefile.am b/src/Makefile.am index 5be031174..632a388a9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -60,6 +60,7 @@ sflphoned_LDADD = \ @CCRTP_LIBS@ \ @ALSA_LIBS@ \ @PULSEAUDIO_LIBS@ \ + -luuid \ @SAMPLERATE_LIBS@ noinst_LTLIBRARIES = libsflphone.la diff --git a/src/audio/pulselayer.h b/src/audio/pulselayer.h index dc22bfaed..828a6b849 100644 --- a/src/audio/pulselayer.h +++ b/src/audio/pulselayer.h @@ -22,6 +22,7 @@ #include "audiolayer.h" #include "audiostream.h" +#include "audiorecord.h" #define PLAYBACK_STREAM_NAME "SFLphone out" #define CAPTURE_STREAM_NAME "SFLphone in" From 2fdc5057ce4b978983c6240642b1b8c4753fb368 Mon Sep 17 00:00:00 2001 From: alexandresavard Date: Mon, 26 Jan 2009 17:50:32 -0500 Subject: [PATCH 07/14] Add audiorecorder plugin and testaudiorecorder --- configure.ac | 1 + src/Makefile.am | 1 + src/audio/pulselayer.h | 2 +- src/global.h | 2 +- src/plug-in/Makefile.am | 2 + src/plug-in/audiorecorder/Makefile.am | 7 + src/plug-in/audiorecorder/audiorecord.cpp | 177 ++++++++++++++++++++++ src/plug-in/audiorecorder/audiorecord.h | 127 ++++++++++++++++ test/Makefile.am | 26 +++- test/audiorecorderTest.cpp | 57 +++++++ test/audiorecorderTest.h | 73 +++++++++ 11 files changed, 472 insertions(+), 3 deletions(-) create mode 100644 src/plug-in/audiorecorder/Makefile.am create mode 100644 src/plug-in/audiorecorder/audiorecord.cpp create mode 100644 src/plug-in/audiorecorder/audiorecord.h create mode 100644 test/audiorecorderTest.cpp create mode 100644 test/audiorecorderTest.h diff --git a/configure.ac b/configure.ac index 100f5d33d..6ee3762e6 100644 --- a/configure.ac +++ b/configure.ac @@ -38,6 +38,7 @@ AC_CONFIG_FILES([src/Makefile \ src/config/Makefile \ src/dbus/Makefile \ src/zeroconf/Makefile \ + src/plug-in/audiorecorder/Makefile \ src/plug-in/Makefile]) dnl Unitary test section diff --git a/src/Makefile.am b/src/Makefile.am index 16725b63f..53945f899 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -91,6 +91,7 @@ libsflphone_la_LIBADD = \ ./dbus/libdbus.la \ ./config/libconfig.la \ ./plug-in/libplugin.la \ + ./plug-in/audiorecorder/libaudiorecorder.la \ $(IAX_LIBS) libsflphone_la_SOURCES = diff --git a/src/audio/pulselayer.h b/src/audio/pulselayer.h index 828a6b849..521ff82e3 100644 --- a/src/audio/pulselayer.h +++ b/src/audio/pulselayer.h @@ -22,7 +22,7 @@ #include "audiolayer.h" #include "audiostream.h" -#include "audiorecord.h" +#include "plug-in/audiorecorder/audiorecord.h" #define PLAYBACK_STREAM_NAME "SFLphone out" #define CAPTURE_STREAM_NAME "SFLphone in" diff --git a/src/global.h b/src/global.h index 259f34e76..0321db6e1 100644 --- a/src/global.h +++ b/src/global.h @@ -32,7 +32,7 @@ typedef float float32; typedef short int16; -useful typedefs. +//useful typedefs. typedef signed short SINT16; typedef signed int SINT32; diff --git a/src/plug-in/Makefile.am b/src/plug-in/Makefile.am index 53bf6b050..7555fe7f3 100644 --- a/src/plug-in/Makefile.am +++ b/src/plug-in/Makefile.am @@ -1,5 +1,7 @@ include ../../globals.mak +SUBDIRS=audiorecorder + noinst_LTLIBRARIES = libplugin.la libplugin_la_SOURCES = \ diff --git a/src/plug-in/audiorecorder/Makefile.am b/src/plug-in/audiorecorder/Makefile.am new file mode 100644 index 000000000..37a2ce4ed --- /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 000000000..65f638039 --- /dev/null +++ b/src/plug-in/audiorecorder/audiorecord.cpp @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2008 Savoir-Faire Linux inc. + * Author: Alexandre Savard + * + * 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 + * + * 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 +#include + +#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/test/Makefile.am b/test/Makefile.am index 86e70dbc3..b3aaf8805 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1,6 +1,6 @@ include ../globals.mak -bin_PROGRAMS = configurationTester pluginmanagerTester +bin_PROGRAMS = configurationTester pluginmanagerTester audiorecorderTester OBJECT_FILES= \ ../src/sflphoned-managerimpl.o \ @@ -17,6 +17,7 @@ OBJECT_FILES= \ ../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 = \ @@ -29,6 +30,12 @@ pluginmanagerTester_SOURCES = \ pluginmanagerTest.cpp \ TestMain.cpp +audiorecorderTester_SOURCES = \ + audiorecorderTest.h \ + audiorecorderTest.cpp \ + TestMain.cpp + + configurationTester_LDADD = \ ../src/libsflphone.la \ $(SFLPHONE_LIBS) $(ZEROCONFLIB) $(LIB_DNSSD) $(IAX_LIBS) \ @@ -41,6 +48,7 @@ configurationTester_LDADD = \ @DBUSCPP_LIBS@ \ @SAMPLERATE_LIBS@ \ $(PJSIP_LIBS) \ + -luuid \ $(OBJECT_FILES) pluginmanagerTester_LDADD = \ @@ -55,5 +63,21 @@ pluginmanagerTester_LDADD = \ @DBUSCPP_LIBS@ \ @SAMPLERATE_LIBS@ \ $(PJSIP_LIBS) \ + -luuid \ + $(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) \ + -luuid \ $(OBJECT_FILES) diff --git a/test/audiorecorderTest.cpp b/test/audiorecorderTest.cpp new file mode 100644 index 000000000..8a9327cb5 --- /dev/null +++ b/test/audiorecorderTest.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2009 Savoir-Faire Linux inc. + * Author: Emmanuel Milou + * + * 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 +#include + +#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; + recAudio.recData(buf,2); + } + + recAudio.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 000000000..216b65707 --- /dev/null +++ b/test/audiorecorderTest.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2009 Savoir-Faire Linux inc. + * Author: Emmanuel Milou + * + * 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 +#include +#include +#include + +#include + +// 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 From 88c73791cfa55337a0e6565fc7e7009c8f0690ef Mon Sep 17 00:00:00 2001 From: Emmanuel Milou Date: Mon, 26 Jan 2009 18:40:37 -0500 Subject: [PATCH 08/14] Complete singleton pattern for the plugin manager --- src/plug-in/pluginmanager.cpp | 9 +++++++++ src/plug-in/pluginmanager.h | 10 +++++----- test/audiorecorderTest.cpp | 6 ++---- test/pluginmanagerTest.cpp | 2 +- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/plug-in/pluginmanager.cpp b/src/plug-in/pluginmanager.cpp index 6012a59bd..df88799a8 100644 --- a/src/plug-in/pluginmanager.cpp +++ b/src/plug-in/pluginmanager.cpp @@ -13,6 +13,15 @@ _instance = 0; } +::sflphone::PluginManager* ::sflphone::PluginManager::instance() +{ + if(! _instance ){ + _instance = new PluginManager(); + } + return _instance; +} + + int ::sflphone::PluginManager::loadPlugins( const std::string &path ) { std::string pluginDir, current; diff --git a/src/plug-in/pluginmanager.h b/src/plug-in/pluginmanager.h index 651a0902f..78d988cd0 100644 --- a/src/plug-in/pluginmanager.h +++ b/src/plug-in/pluginmanager.h @@ -17,11 +17,6 @@ namespace sflphone { class PluginManager { public: - /** - * Default constructor - */ - PluginManager(); - /** * Destructor */ @@ -47,6 +42,11 @@ namespace sflphone { Plugin* isPluginLoaded( const std::string &name ); private: + /** + * Default constructor + */ + PluginManager(); + /** * Load a unix dynamic/shared library * @param filename The path to the dynamic/shared library diff --git a/test/audiorecorderTest.cpp b/test/audiorecorderTest.cpp index 8a9327cb5..f766d4af1 100644 --- a/test/audiorecorderTest.cpp +++ b/test/audiorecorderTest.cpp @@ -43,12 +43,10 @@ void AudioRecorderTest::testRecordData(){ for (SFLDataFormat i = -32768; i < 32767; i++ ){ buf[0] = i; buf[1] = i; - recAudio.recData(buf,2); + _ar->recData(buf,2); } - recAudio.closeFile(); - - + _ar->closeFile(); } void AudioRecorderTest::tearDown(){ diff --git a/test/pluginmanagerTest.cpp b/test/pluginmanagerTest.cpp index b9a3d413a..e5dfff8e1 100644 --- a/test/pluginmanagerTest.cpp +++ b/test/pluginmanagerTest.cpp @@ -27,7 +27,7 @@ using std::endl; void PluginManagerTest::setUp(){ // Instanciate the plugin manager object - _pm = new ::sflphone::PluginManager(); + _pm = ::sflphone::PluginManager::instance(); } void PluginManagerTest::testLoadPluginDirectory(){ From d91dfd6d9117a24b21e81f03c123fce6e92d277a Mon Sep 17 00:00:00 2001 From: Emmanuel Milou Date: Mon, 26 Jan 2009 23:38:46 -0500 Subject: [PATCH 09/14] Continue plugin API definition --- configure.ac | 3 +- src/plug-in/Makefile.am | 7 ++-- src/plug-in/plugin_api.h | 65 +++++++++++++++++++++++++++++++++ src/plug-in/test/Makefile.am | 21 +++++++++++ src/plug-in/test/pluginTest.cpp | 15 ++++++++ 5 files changed, 107 insertions(+), 4 deletions(-) create mode 100644 src/plug-in/plugin_api.h create mode 100644 src/plug-in/test/Makefile.am create mode 100644 src/plug-in/test/pluginTest.cpp diff --git a/configure.ac b/configure.ac index 3cb974e0f..3fc535bcb 100644 --- a/configure.ac +++ b/configure.ac @@ -38,7 +38,8 @@ AC_CONFIG_FILES([src/Makefile \ src/config/Makefile \ src/dbus/Makefile \ src/zeroconf/Makefile \ - src/plug-in/Makefile]) + src/plug-in/Makefile \ + src/plug-in/test/Makefile]) dnl Unitary test section AC_CONFIG_FILES([test/Makefile]) diff --git a/src/plug-in/Makefile.am b/src/plug-in/Makefile.am index 53bf6b050..3e386fcc6 100644 --- a/src/plug-in/Makefile.am +++ b/src/plug-in/Makefile.am @@ -2,7 +2,8 @@ include ../../globals.mak noinst_LTLIBRARIES = libplugin.la -libplugin_la_SOURCES = \ - pluginmanager.cpp \ - plugin.h +noinst_HEADERS=plugin_api.h + +libplugin_la_SOURCES = \ + pluginmanager.cpp diff --git a/src/plug-in/plugin_api.h b/src/plug-in/plugin_api.h new file mode 100644 index 000000000..66f078b5c --- /dev/null +++ b/src/plug-in/plugin_api.h @@ -0,0 +1,65 @@ +#ifndef PLUGIN_API_H +#define PLUGIN_API_H + +#include + +#include "global.h" + +/* + * @file plugin_api.h + * @brief Define a plugin object + */ + +#ifdef __cplusplus +extern "C" { +#endif + + namespace sflphone { + + class PluginManager; + + typedef struct PluginApi_Version{ + int version; + int revision; + } + + typedef struct Register_Params{ + PluginApi_Version plugin_version; + create_t create_func; + destroy_t destroy_func; + }Register_Params; + + class PluginApi { + + public: + PluginApi( const std::string &name ); + //Plugin( const Plugin &plugin ); + virtual ~PluginApi() {} + + public: + /** + * Return the minimal core version required so that the plugin could work + * @return int The version required + */ + virtual int getCoreVersion() const = 0; + + /** + * Register the plugin to the plugin manager + */ + virtual void registerPlugin( PluginManager & ) = 0; + + private: + PluginApi &operator =(const PluginApi &plugin); + + }; + + typedef Plugin* create_t( void* ); + typedef int destroy_t( Plugin* ); + } + +#ifdef __cplusplus +} +#endif + +#endif //PLUGIN_API_H + diff --git a/src/plug-in/test/Makefile.am b/src/plug-in/test/Makefile.am new file mode 100644 index 000000000..f52231a05 --- /dev/null +++ b/src/plug-in/test/Makefile.am @@ -0,0 +1,21 @@ +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 + +noinst_HEADERS = plugin_api.h + +install-exec-local: install-libplugintest_so +uninstall-local: uninstall-libplugintest_so + +install-libplugintest_so: libplugintest.so + mkdir -p $(sflpluginsdir) + $(INSTALL_PROGRAM) libplugintest.so $(sflpluginsdir) + +uninstall-libplugintest_so: + rm -f $(sflpluginsdir)/libplugintest.so diff --git a/src/plug-in/test/pluginTest.cpp b/src/plug-in/test/pluginTest.cpp new file mode 100644 index 000000000..2e467dbe1 --- /dev/null +++ b/src/plug-in/test/pluginTest.cpp @@ -0,0 +1,15 @@ +#include "../plugin_api.h" + +class PluginTest : public Plugin { + public: + PluginTest():Plugin(){ + } +}; + +extern "C" Plugin* create_t( void * ){ + return new PluginTest(); +} + +extern "C" void* destroy_t( Plugin *p ){ + delete p; +} From 32b036d1c3b375447c9918f2b9e30b4606569380 Mon Sep 17 00:00:00 2001 From: Emmanuel Milou Date: Tue, 27 Jan 2009 20:18:31 -0500 Subject: [PATCH 10/14] api plugin for registration --- src/plug-in/Makefile.am | 2 +- src/plug-in/plugin.cpp | 27 --------------------- src/plug-in/plugin.h | 43 --------------------------------- src/plug-in/plugin_api.h | 43 ++++++++++++--------------------- src/plug-in/pluginmanager.cpp | 2 +- src/plug-in/pluginmanager.h | 17 ++++++++++--- src/plug-in/test/Makefile.am | 8 +++--- src/plug-in/test/pluginTest.cpp | 23 ++++++++++++------ 8 files changed, 50 insertions(+), 115 deletions(-) delete mode 100644 src/plug-in/plugin.cpp delete mode 100644 src/plug-in/plugin.h diff --git a/src/plug-in/Makefile.am b/src/plug-in/Makefile.am index 3e386fcc6..9f31ec25a 100644 --- a/src/plug-in/Makefile.am +++ b/src/plug-in/Makefile.am @@ -2,7 +2,7 @@ include ../../globals.mak noinst_LTLIBRARIES = libplugin.la -noinst_HEADERS=plugin_api.h +SUBDIRS=test libplugin_la_SOURCES = \ pluginmanager.cpp diff --git a/src/plug-in/plugin.cpp b/src/plug-in/plugin.cpp deleted file mode 100644 index 495437076..000000000 --- a/src/plug-in/plugin.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "plugin.h" - -::sflphone::Plugin::Plugin( const std::string &filename UNUSED ) -{ - //TODO IMPLEMENT -} - -::sflphone::Plugin::Plugin( const Plugin &plugin UNUSED ) -{ - //TODO IMPLEMENT -} - -::sflphone::Plugin::~Plugin() -{ - //TODO IMPLEMENT -} - -int ::sflphone::Plugin::getCoreVersion( void ) const -{ - //TODO IMPLEMENT - return 1; -} - -void ::sflphone::Plugin::registerPlugin( PluginManager & ) -{ - //TODO IMPLEMENT -} diff --git a/src/plug-in/plugin.h b/src/plug-in/plugin.h deleted file mode 100644 index 100d6ea5b..000000000 --- a/src/plug-in/plugin.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef PLUGIN_H -#define PLUGIN_H - -#include - -#include "global.h" - -/* - * @file plugin.h - * @brief Define a plugin object - */ - -namespace sflphone { - -class PluginManager; - - class Plugin { - - public: - Plugin( const std::string &name ); - //Plugin( const Plugin &plugin ); - virtual ~Plugin() {} - - public: - /** - * Return the minimal core version required so that the plugin could work - * @return int The version required - */ - virtual int getCoreVersion() const = 0; - - /** - * Register the plugin to the plugin manager - */ - virtual void registerPlugin( PluginManager & ) = 0; - - private: - Plugin &operator =(const Plugin &plugin); - - }; -} - -#endif //PLUGIN_H - diff --git a/src/plug-in/plugin_api.h b/src/plug-in/plugin_api.h index 66f078b5c..722215459 100644 --- a/src/plug-in/plugin_api.h +++ b/src/plug-in/plugin_api.h @@ -1,12 +1,12 @@ -#ifndef PLUGIN_API_H -#define PLUGIN_API_H +#ifndef PLUGIN_H +#define PLUGIN_H #include #include "global.h" /* - * @file plugin_api.h + * @file plugin.h * @brief Define a plugin object */ @@ -18,23 +18,14 @@ extern "C" { class PluginManager; - typedef struct PluginApi_Version{ - int version; - int revision; - } - - typedef struct Register_Params{ - PluginApi_Version plugin_version; - create_t create_func; - destroy_t destroy_func; - }Register_Params; - - class PluginApi { + class Plugin { public: - PluginApi( const std::string &name ); - //Plugin( const Plugin &plugin ); - virtual ~PluginApi() {} + Plugin( const std::string &name ){ + _name = name; + } + + virtual ~Plugin() {} public: /** @@ -43,23 +34,21 @@ extern "C" { */ virtual int getCoreVersion() const = 0; - /** - * Register the plugin to the plugin manager - */ - virtual void registerPlugin( PluginManager & ) = 0; - private: - PluginApi &operator =(const PluginApi &plugin); + Plugin &operator =(const Plugin &plugin); + std::string _name; }; + + typedef Plugin* createFunc( void* ); + + typedef void destroyFunc( Plugin* ); - typedef Plugin* create_t( void* ); - typedef int destroy_t( Plugin* ); } #ifdef __cplusplus } #endif -#endif //PLUGIN_API_H +#endif //PLUGIN_H diff --git a/src/plug-in/pluginmanager.cpp b/src/plug-in/pluginmanager.cpp index 6012a59bd..54f757216 100644 --- a/src/plug-in/pluginmanager.cpp +++ b/src/plug-in/pluginmanager.cpp @@ -48,7 +48,7 @@ int ::sflphone::PluginManager::loadPlugins( const std::string &path ) return result; } -::sflphone::Plugin* ::sflphone::PluginManager::isPluginLoaded( const std::string &name ) +::sflphone::PluginWrap* ::sflphone::PluginManager::isPluginLoaded( const std::string &name ) { if(_loadedPlugins.empty()) return NULL; diff --git a/src/plug-in/pluginmanager.h b/src/plug-in/pluginmanager.h index 651a0902f..5330b8764 100644 --- a/src/plug-in/pluginmanager.h +++ b/src/plug-in/pluginmanager.h @@ -6,14 +6,23 @@ * @brief Base class of the plugin manager */ -#include "plugin.h" +#include "plugin_api.h" #include "global.h" #include #include + namespace sflphone { + typedef struct { + Plugin *plugin; + createFunc *create_func; + destroyFunc *destroy_func; + std::string name; + } PluginWrap; + + class PluginManager { public: @@ -44,7 +53,9 @@ namespace sflphone { * @param name The name of the plugin looked for * @return Plugin* The pointer on the plugin or NULL if not found */ - Plugin* isPluginLoaded( const std::string &name ); + PluginWrap* isPluginLoaded( const std::string &name ); + + int initPlugins( void ); private: /** @@ -61,7 +72,7 @@ namespace sflphone { void unloadDynamicLibrary( void * pluginHandlePtr ); /* Map of plugins associated by their string name */ - typedef std::map pluginMap; + typedef std::map pluginMap; pluginMap _loadedPlugins; /* The unique static instance */ diff --git a/src/plug-in/test/Makefile.am b/src/plug-in/test/Makefile.am index f52231a05..6809be2c0 100644 --- a/src/plug-in/test/Makefile.am +++ b/src/plug-in/test/Makefile.am @@ -8,14 +8,12 @@ INSTALL_PLUGIN_RULE = install-libplugintest_so noinst_PROGRAMS = libplugintest.so -noinst_HEADERS = plugin_api.h - install-exec-local: install-libplugintest_so uninstall-local: uninstall-libplugintest_so install-libplugintest_so: libplugintest.so - mkdir -p $(sflpluginsdir) - $(INSTALL_PROGRAM) libplugintest.so $(sflpluginsdir) + mkdir -p $(sflplugindir) + $(INSTALL_PROGRAM) libplugintest.so $(sflplugindir) uninstall-libplugintest_so: - rm -f $(sflpluginsdir)/libplugintest.so + rm -f $(sflplugindir)/libplugintest.so diff --git a/src/plug-in/test/pluginTest.cpp b/src/plug-in/test/pluginTest.cpp index 2e467dbe1..6249a886f 100644 --- a/src/plug-in/test/pluginTest.cpp +++ b/src/plug-in/test/pluginTest.cpp @@ -1,15 +1,22 @@ #include "../plugin_api.h" -class PluginTest : public Plugin { - public: - PluginTest():Plugin(){ - } -}; +namespace sflphone { -extern "C" Plugin* create_t( void * ){ - return new PluginTest(); + class PluginTest : public Plugin { + public: + PluginTest( const std::string &name ):Plugin( name ){ + } + + virtual int getCoreVersion() const{ + return 1; + } + }; + +} +extern "C" ::sflphone::Plugin* create_t( void * ){ + return new ::sflphone::PluginTest("test"); } -extern "C" void* destroy_t( Plugin *p ){ +extern "C" void* destroy_t( ::sflphone::Plugin *p ){ delete p; } From f6d2fbf1147f5d23772f29e86368028e300f9141 Mon Sep 17 00:00:00 2001 From: Emmanuel Milou Date: Thu, 29 Jan 2009 00:48:31 -0500 Subject: [PATCH 11/14] Make the plugins registering against the plugin manager --- src/plug-in/Makefile.am | 3 +- src/plug-in/plugin.cpp | 15 ++++++ src/plug-in/plugin.h | 32 +++++++++++ src/plug-in/plugin_api.h | 54 ------------------- src/plug-in/plugininterface.h | 51 ++++++++++++++++++ src/plug-in/pluginmanager.cpp | 93 +++++++++++++++++++++++++++----- src/plug-in/pluginmanager.h | 96 ++++++++++++++++----------------- src/plug-in/test/pluginTest.cpp | 31 ++++++++--- test/Makefile.am | 1 - test/pluginmanagerTest.cpp | 19 ++++--- test/pluginmanagerTest.h | 7 ++- 11 files changed, 266 insertions(+), 136 deletions(-) create mode 100644 src/plug-in/plugin.cpp create mode 100644 src/plug-in/plugin.h delete mode 100644 src/plug-in/plugin_api.h create mode 100644 src/plug-in/plugininterface.h diff --git a/src/plug-in/Makefile.am b/src/plug-in/Makefile.am index 9f31ec25a..bd27f29a4 100644 --- a/src/plug-in/Makefile.am +++ b/src/plug-in/Makefile.am @@ -5,5 +5,6 @@ noinst_LTLIBRARIES = libplugin.la SUBDIRS=test libplugin_la_SOURCES = \ - pluginmanager.cpp + pluginmanager.cpp \ + plugin.cpp diff --git a/src/plug-in/plugin.cpp b/src/plug-in/plugin.cpp new file mode 100644 index 000000000..deaf1a481 --- /dev/null +++ b/src/plug-in/plugin.cpp @@ -0,0 +1,15 @@ +#include "plugin.h" + +::sflphone::Plugin::Plugin (void *handle, PluginInterface *interface) + :_handlePtr(handle), _interface(interface) +{ +} + +::sflphone::Plugin::Plugin (PluginInterface *interface) + :_interface(interface) +{ +} + +::sflphone::Plugin::~Plugin () +{ +} diff --git a/src/plug-in/plugin.h b/src/plug-in/plugin.h new file mode 100644 index 000000000..fe548361e --- /dev/null +++ b/src/plug-in/plugin.h @@ -0,0 +1,32 @@ +#ifndef PLUGIN_H +#define PLUGIN_H + +#include "plugininterface.h" + +namespace sflphone { + + class PluginInterface; + + class Plugin { + + public: + + Plugin (void*, PluginInterface *interface); + Plugin (PluginInterface *interface); + + ~Plugin (); + + void setName (std::string name); + private: + std::string _name; + int _version_major; + int _version_minor; + int _required; + void *_handlePtr; + PluginInterface *_interface; + + friend class PluginTest; + friend class PluginManager; + }; +} +#endif //PLUGIN_H diff --git a/src/plug-in/plugin_api.h b/src/plug-in/plugin_api.h deleted file mode 100644 index 722215459..000000000 --- a/src/plug-in/plugin_api.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef PLUGIN_H -#define PLUGIN_H - -#include - -#include "global.h" - -/* - * @file plugin.h - * @brief Define a plugin object - */ - -#ifdef __cplusplus -extern "C" { -#endif - - namespace sflphone { - - class PluginManager; - - class Plugin { - - public: - Plugin( const std::string &name ){ - _name = name; - } - - virtual ~Plugin() {} - - public: - /** - * Return the minimal core version required so that the plugin could work - * @return int The version required - */ - virtual int getCoreVersion() const = 0; - - private: - Plugin &operator =(const Plugin &plugin); - - std::string _name; - }; - - typedef Plugin* createFunc( void* ); - - typedef void destroyFunc( Plugin* ); - - } - -#ifdef __cplusplus -} -#endif - -#endif //PLUGIN_H - diff --git a/src/plug-in/plugininterface.h b/src/plug-in/plugininterface.h new file mode 100644 index 000000000..1bfad23e2 --- /dev/null +++ b/src/plug-in/plugininterface.h @@ -0,0 +1,51 @@ +#ifndef PLUGIN_INTERFACE_H +#define PLUGIN_INTERFACE_H + +#include +#include "global.h" + +#include "plugin.h" + +/* + * @file plugininterface.h + * @brief Define a plugin object + */ + +namespace sflphone { + + class PluginManager; + class Plugin; + + class PluginInterface { + + public: + PluginInterface( const std::string &name ){ + _name = name; + } + + virtual ~PluginInterface() {} + + inline std::string getInterfaceName (void) { return _name; } + + /** + * Return the minimal core version required so that the plugin could work + * @return int The version required + */ + virtual int initFunc () = 0; + + virtual int registerFunc (Plugin **plugin) = 0; + + private: + PluginInterface &operator =(const PluginInterface &plugin); + + std::string _name; + }; + + typedef PluginInterface* createFunc (void); + + typedef void destroyFunc( PluginInterface* ); + +} + +#endif //PLUGIN_INTERFACE_H + diff --git a/src/plug-in/pluginmanager.cpp b/src/plug-in/pluginmanager.cpp index 54f757216..f8135f578 100644 --- a/src/plug-in/pluginmanager.cpp +++ b/src/plug-in/pluginmanager.cpp @@ -3,7 +3,19 @@ #include "pluginmanager.h" -::sflphone::PluginManager::PluginManager():_loadedPlugins() +::sflphone::PluginManager* ::sflphone::PluginManager::_instance = 0; + + ::sflphone::PluginManager* +::sflphone::PluginManager::instance() +{ + if(!_instance){ + return new PluginManager(); + } + return _instance; +} + +::sflphone::PluginManager::PluginManager() + :_loadedPlugins() { _instance = this; } @@ -13,13 +25,16 @@ _instance = 0; } -int ::sflphone::PluginManager::loadPlugins( const std::string &path ) + int +::sflphone::PluginManager::loadPlugins (const std::string &path) { std::string pluginDir, current; - ::sflphone::Plugin *plugin; + ::sflphone::PluginInterface *interface; DIR *dir; dirent *dirStruct; int result=0; + void *handle; + createFunc* createPlugin; const std::string pDir = ".."; const std::string cDir = "."; @@ -37,18 +52,31 @@ int ::sflphone::PluginManager::loadPlugins( const std::string &path ) current = dirStruct->d_name; /* Test if the current item is not the parent or the current directory */ if( current != pDir && current != cDir ){ - loadDynamicLibrary( current ); - result++; - } + handle = loadDynamicLibrary( pluginDir + current ); + + if(instanciatePlugin (handle, &interface) != 0) + { + _debug("Error instanciating the plugin ...\n"); + return 1; + } + + if(registerPlugin (handle, interface) != 0) + _debug("Error registering the plugin ...\n"); + return 1; + } } } + else + return 1; + /* Close the directory */ closedir( dir ); - return result; + return 0; } -::sflphone::PluginWrap* ::sflphone::PluginManager::isPluginLoaded( const std::string &name ) + ::sflphone::Plugin* +::sflphone::PluginManager::isPluginLoaded (const std::string &name) { if(_loadedPlugins.empty()) return NULL; @@ -68,31 +96,68 @@ int ::sflphone::PluginManager::loadPlugins( const std::string &path ) return NULL; } -void* ::sflphone::PluginManager::loadDynamicLibrary( const std::string& filename ) { + + void* +::sflphone::PluginManager::loadDynamicLibrary (const std::string& filename) +{ void *pluginHandlePtr = NULL; const char *error; _debug("Loading dynamic library %s\n", filename.c_str()); -#if defined(Q_OS_UNIX) /* 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(); -#endif - return pluginHandlePtr; + } -void ::sflphone::PluginManager::unloadDynamicLibrary( void * pluginHandlePtr ) { + int +::sflphone::PluginManager::instanciatePlugin (void *handlePtr, ::sflphone::PluginInterface **plugin) +{ + createFunc *createPlugin; + + createPlugin = (createFunc*)dlsym(handlePtr, "create"); + if( dlerror() ) + { + _debug("Error creating the plugin: %s\n", dlerror()); + return 1; + } + *plugin = createPlugin(); + return 0; +} + + int +::sflphone::PluginManager::registerPlugin (void *handlePtr, PluginInterface *interface) +{ + Plugin *myplugin; + std::string name; + + if( !( handlePtr && interface!=0 ) ) + return 1; + /* Fetch information from the loaded plugin interface */ + if(interface->registerFunc (&myplugin) != 0) + return 1; + /* Creation of the plugin wrapper */ + myplugin = new Plugin (handlePtr, interface); + + /* Add the data in the loaded plugin map */ + _loadedPlugins[ myplugin->_name ] = myplugin; + return 0; +} + + void +::sflphone::PluginManager::unloadDynamicLibrary (void * pluginHandlePtr) +{ dlclose( pluginHandlePtr ); dlerror(); } -::sflphone::PluginManager* ::sflphone::PluginManager::_instance = 0; diff --git a/src/plug-in/pluginmanager.h b/src/plug-in/pluginmanager.h index 5330b8764..671834369 100644 --- a/src/plug-in/pluginmanager.h +++ b/src/plug-in/pluginmanager.h @@ -6,77 +6,71 @@ * @brief Base class of the plugin manager */ -#include "plugin_api.h" +#include "plugininterface.h" #include "global.h" #include #include - namespace sflphone { - typedef struct { - Plugin *plugin; - createFunc *create_func; - destroyFunc *destroy_func; - std::string name; - } PluginWrap; - - class PluginManager { + public: - /** - * Default constructor - */ - PluginManager(); + /** + * Destructor + */ + ~PluginManager(); - /** - * Destructor - */ - ~PluginManager(); + /** + * Returns the unique instance of the plugin manager + */ + static PluginManager* instance(); - /** - * 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 = "" ); - /** - * 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 instanciatePlugin( void *handlePtr, PluginInterface** plugin ); - /** - * Check if a plugin has been already loaded - * @param name The name of the plugin looked for - * @return Plugin* The pointer on the plugin or NULL if not found - */ - PluginWrap* isPluginLoaded( const std::string &name ); + /** + * Check if a plugin has been already loaded + * @param name The name of the plugin looked for + * @return Plugin* The pointer on the plugin or NULL if not found + */ + Plugin* isPluginLoaded( const std::string &name ); - int initPlugins( void ); + int registerPlugin (void *handle, PluginInterface *interface); private: - /** - * Load a unix dynamic/shared library - * @param filename The path to the dynamic/shared library - * @return void* A pointer on it - */ - void * loadDynamicLibrary( const std::string &filename ); + /** + * Default constructor + */ + PluginManager(); - /** - * Unload a unix dynamic/shared library - * @param pluginHandleptr The pointer on the loaded plugin - */ - void unloadDynamicLibrary( void * pluginHandlePtr ); + /** + * Load a unix dynamic/shared library + * @param filename The path to the dynamic/shared library + * @return void* A pointer on it + */ + void * loadDynamicLibrary( const std::string &filename ); - /* Map of plugins associated by their string name */ - typedef std::map pluginMap; - pluginMap _loadedPlugins; + /** + * Unload a unix dynamic/shared library + * @param pluginHandleptr The pointer on the loaded plugin + */ + void unloadDynamicLibrary( void * pluginHandlePtr ); - /* The unique static instance */ - static PluginManager* _instance; + /* Map of plugins associated by their string name */ + typedef std::map pluginMap; + pluginMap _loadedPlugins; + + /* The unique static instance */ + static PluginManager* _instance; }; } diff --git a/src/plug-in/test/pluginTest.cpp b/src/plug-in/test/pluginTest.cpp index 6249a886f..5e5f7cff1 100644 --- a/src/plug-in/test/pluginTest.cpp +++ b/src/plug-in/test/pluginTest.cpp @@ -1,22 +1,39 @@ -#include "../plugin_api.h" +#include "../plugininterface.h" namespace sflphone { - class PluginTest : public Plugin { + class PluginTest : public PluginInterface { + public: - PluginTest( const std::string &name ):Plugin( name ){ + PluginTest( const std::string &name ):PluginInterface( name ){ } - virtual int getCoreVersion() const{ - return 1; + virtual int initFunc (void) + { + return 0; + } + + virtual int registerFunc (Plugin **plugin) + { + Plugin *ret; + + ret = new Plugin(this); + + ret->_name = getInterfaceName(); + ret->_required = 1; + ret->_version_major=1; + ret->_version_minor=0; + + *plugin = ret; + return 0; } }; } -extern "C" ::sflphone::Plugin* create_t( void * ){ +extern "C" ::sflphone::PluginInterface* create (void){ return new ::sflphone::PluginTest("test"); } -extern "C" void* destroy_t( ::sflphone::Plugin *p ){ +extern "C" void* destroy( ::sflphone::PluginInterface *p ){ delete p; } diff --git a/test/Makefile.am b/test/Makefile.am index 86e70dbc3..652556ffb 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -15,7 +15,6 @@ OBJECT_FILES= \ ../src/sflphoned-sipaccount.o \ ../src/sflphoned-iaxaccount.o \ ../src/sflphoned-eventthread.o \ - ../src/sflphoned-useragent.o \ ../src/plug-in/pluginmanager.o \ ../src/sflphoned-samplerateconverter.o diff --git a/test/pluginmanagerTest.cpp b/test/pluginmanagerTest.cpp index b9a3d413a..ed3f4d7e2 100644 --- a/test/pluginmanagerTest.cpp +++ b/test/pluginmanagerTest.cpp @@ -26,19 +26,26 @@ using std::cout; using std::endl; void PluginManagerTest::setUp(){ - // Instanciate the plugin manager object - _pm = new ::sflphone::PluginManager(); + // Instanciate the plugin manager singleton + _pm = ::sflphone::PluginManager::instance(); } void PluginManagerTest::testLoadPluginDirectory(){ - _pm->loadPlugins(); + CPPUNIT_ASSERT(_pm->loadPlugins() == 0); } -void PluginManagerTest::testNonloadedPlugin(){ - CPPUNIT_ASSERT( _pm->isPluginLoaded("test") == NULL ); +void PluginManagerTest::testLoadPlugin(){ + CPPUNIT_ASSERT(_pm->loadPlugins() == 0); + //CPPUNIT_ASSERT( _pm->isPluginLoaded("test") == NULL ); +} + +void PluginManagerTest::testRegisterPlugin(){ + // First load the default directory + _pm->loadPlugins(); + // Resolve the symbol } void PluginManagerTest::tearDown(){ // Delete the plugin manager object - delete _pm; _pm=NULL; + delete _pm; _pm=0; } diff --git a/test/pluginmanagerTest.h b/test/pluginmanagerTest.h index e43ba8f7a..0cd92da42 100644 --- a/test/pluginmanagerTest.h +++ b/test/pluginmanagerTest.h @@ -43,7 +43,8 @@ class PluginManagerTest : public CppUnit::TestCase { */ CPPUNIT_TEST_SUITE( PluginManagerTest ); CPPUNIT_TEST( testLoadPluginDirectory ); - CPPUNIT_TEST( testNonloadedPlugin ); + CPPUNIT_TEST( testLoadPlugin ); + CPPUNIT_TEST( testRegisterPlugin ); CPPUNIT_TEST_SUITE_END(); public: @@ -63,7 +64,9 @@ class PluginManagerTest : public CppUnit::TestCase { void testLoadPluginDirectory(); - void testNonloadedPlugin(); + void testLoadPlugin(); + + void testRegisterPlugin(); private: ::sflphone::PluginManager *_pm; From 71e713789d1cff580fe1cc86daf013c452e4f7f3 Mon Sep 17 00:00:00 2001 From: Emmanuel Milou Date: Fri, 30 Jan 2009 00:38:41 -0500 Subject: [PATCH 12/14] Functional plug-in manager --- src/plug-in/Makefile.am | 3 +- src/plug-in/plugin.cpp | 15 ---------- src/plug-in/plugin.h | 41 ++++++++++++++++---------- src/plug-in/plugininterface.h | 51 --------------------------------- src/plug-in/pluginmanager.cpp | 26 ++++++++--------- src/plug-in/pluginmanager.h | 26 +++++++++-------- src/plug-in/test/pluginTest.cpp | 37 ++++++++---------------- test/pluginmanagerTest.cpp | 50 ++++++++++++++++++++++++++------ test/pluginmanagerTest.h | 19 +++++++++--- 9 files changed, 122 insertions(+), 146 deletions(-) delete mode 100644 src/plug-in/plugin.cpp delete mode 100644 src/plug-in/plugininterface.h diff --git a/src/plug-in/Makefile.am b/src/plug-in/Makefile.am index bd27f29a4..ae5675eef 100644 --- a/src/plug-in/Makefile.am +++ b/src/plug-in/Makefile.am @@ -5,6 +5,5 @@ noinst_LTLIBRARIES = libplugin.la SUBDIRS=test libplugin_la_SOURCES = \ - pluginmanager.cpp \ - plugin.cpp + pluginmanager.cpp diff --git a/src/plug-in/plugin.cpp b/src/plug-in/plugin.cpp deleted file mode 100644 index deaf1a481..000000000 --- a/src/plug-in/plugin.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "plugin.h" - -::sflphone::Plugin::Plugin (void *handle, PluginInterface *interface) - :_handlePtr(handle), _interface(interface) -{ -} - -::sflphone::Plugin::Plugin (PluginInterface *interface) - :_interface(interface) -{ -} - -::sflphone::Plugin::~Plugin () -{ -} diff --git a/src/plug-in/plugin.h b/src/plug-in/plugin.h index fe548361e..6adac44f9 100644 --- a/src/plug-in/plugin.h +++ b/src/plug-in/plugin.h @@ -1,32 +1,43 @@ #ifndef PLUGIN_H #define PLUGIN_H -#include "plugininterface.h" +#include +#include "global.h" + +/* + * @file plugin.h + * @brief Define a plugin object + */ namespace sflphone { - class PluginInterface; - class Plugin { public: + Plugin( const std::string &name ){ + _name = name; + } - Plugin (void*, PluginInterface *interface); - Plugin (PluginInterface *interface); + virtual ~Plugin() {} - ~Plugin (); + inline std::string getPluginName (void) { return _name; } - void setName (std::string name); + /** + * Return the minimal core version required so that the plugin could work + * @return int The version required + */ + virtual int initFunc (int i) = 0; + private: - std::string _name; - int _version_major; - int _version_minor; - int _required; - void *_handlePtr; - PluginInterface *_interface; + Plugin &operator =(const Plugin &plugin); - friend class PluginTest; - friend class PluginManager; + std::string _name; }; + } +typedef ::sflphone::Plugin* createFunc (void); + +typedef void destroyFunc (::sflphone::Plugin*); + #endif //PLUGIN_H + diff --git a/src/plug-in/plugininterface.h b/src/plug-in/plugininterface.h deleted file mode 100644 index 1bfad23e2..000000000 --- a/src/plug-in/plugininterface.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef PLUGIN_INTERFACE_H -#define PLUGIN_INTERFACE_H - -#include -#include "global.h" - -#include "plugin.h" - -/* - * @file plugininterface.h - * @brief Define a plugin object - */ - -namespace sflphone { - - class PluginManager; - class Plugin; - - class PluginInterface { - - public: - PluginInterface( const std::string &name ){ - _name = name; - } - - virtual ~PluginInterface() {} - - inline std::string getInterfaceName (void) { return _name; } - - /** - * Return the minimal core version required so that the plugin could work - * @return int The version required - */ - virtual int initFunc () = 0; - - virtual int registerFunc (Plugin **plugin) = 0; - - private: - PluginInterface &operator =(const PluginInterface &plugin); - - std::string _name; - }; - - typedef PluginInterface* createFunc (void); - - typedef void destroyFunc( PluginInterface* ); - -} - -#endif //PLUGIN_INTERFACE_H - diff --git a/src/plug-in/pluginmanager.cpp b/src/plug-in/pluginmanager.cpp index f8135f578..7a259f7fc 100644 --- a/src/plug-in/pluginmanager.cpp +++ b/src/plug-in/pluginmanager.cpp @@ -29,7 +29,7 @@ ::sflphone::PluginManager::loadPlugins (const std::string &path) { std::string pluginDir, current; - ::sflphone::PluginInterface *interface; + ::sflphone::Plugin *plugin; DIR *dir; dirent *dirStruct; int result=0; @@ -54,15 +54,18 @@ if( current != pDir && current != cDir ){ handle = loadDynamicLibrary( pluginDir + current ); - if(instanciatePlugin (handle, &interface) != 0) + if(instanciatePlugin (handle, &plugin) != 0) { _debug("Error instanciating the plugin ...\n"); return 1; } + /* if(registerPlugin (handle, interface) != 0) + { _debug("Error registering the plugin ...\n"); return 1; + }*/ } } } @@ -119,7 +122,7 @@ } int -::sflphone::PluginManager::instanciatePlugin (void *handlePtr, ::sflphone::PluginInterface **plugin) +::sflphone::PluginManager::instanciatePlugin (void *handlePtr, ::sflphone::Plugin **plugin) { createFunc *createPlugin; @@ -134,30 +137,25 @@ } int -::sflphone::PluginManager::registerPlugin (void *handlePtr, PluginInterface *interface) +::sflphone::PluginManager::registerPlugin (void *handlePtr, Plugin *plugin) { - Plugin *myplugin; std::string name; - if( !( handlePtr && interface!=0 ) ) + if( !(handlePtr && plugin!=0) ) return 1; - /* Fetch information from the loaded plugin interface */ - if(interface->registerFunc (&myplugin) != 0) - return 1; - /* Creation of the plugin wrapper */ - myplugin = new Plugin (handlePtr, interface); - + name = plugin->getPluginName(); /* Add the data in the loaded plugin map */ - _loadedPlugins[ myplugin->_name ] = myplugin; + _loadedPlugins[ name ] = plugin; return 0; } - void + int ::sflphone::PluginManager::unloadDynamicLibrary (void * pluginHandlePtr) { dlclose( pluginHandlePtr ); dlerror(); + return 0; } diff --git a/src/plug-in/pluginmanager.h b/src/plug-in/pluginmanager.h index 671834369..f24b1779f 100644 --- a/src/plug-in/pluginmanager.h +++ b/src/plug-in/pluginmanager.h @@ -6,7 +6,7 @@ * @brief Base class of the plugin manager */ -#include "plugininterface.h" +#include "plugin.h" #include "global.h" #include @@ -18,6 +18,7 @@ namespace sflphone { public: + /** * Destructor */ @@ -35,7 +36,7 @@ namespace sflphone { */ int loadPlugins( const std::string &path = "" ); - int instanciatePlugin( void *handlePtr, PluginInterface** plugin ); + int instanciatePlugin( void *handlePtr, Plugin** plugin ); /** * Check if a plugin has been already loaded @@ -44,27 +45,28 @@ namespace sflphone { */ Plugin* isPluginLoaded( const std::string &name ); - int registerPlugin (void *handle, PluginInterface *interface); - - private: - /** - * Default constructor - */ - PluginManager(); - + int registerPlugin (void *handle, Plugin *plugin); + /** * Load a unix dynamic/shared library * @param filename The path to the dynamic/shared library * @return void* A pointer on it */ void * loadDynamicLibrary( const std::string &filename ); - + /** * Unload a unix dynamic/shared library * @param pluginHandleptr The pointer on the loaded plugin */ - void unloadDynamicLibrary( void * pluginHandlePtr ); + int unloadDynamicLibrary( void * pluginHandlePtr ); + + private: + /** + * Default constructor + */ + PluginManager(); + /* Map of plugins associated by their string name */ typedef std::map pluginMap; pluginMap _loadedPlugins; diff --git a/src/plug-in/test/pluginTest.cpp b/src/plug-in/test/pluginTest.cpp index 5e5f7cff1..3aeb92707 100644 --- a/src/plug-in/test/pluginTest.cpp +++ b/src/plug-in/test/pluginTest.cpp @@ -1,39 +1,26 @@ -#include "../plugininterface.h" +#include "../plugin.h" namespace sflphone { - class PluginTest : public PluginInterface { + class PluginTest : public Plugin { public: - PluginTest( const std::string &name ):PluginInterface( name ){ - } + PluginTest( const std::string &name ) + :Plugin( name ) { + } - virtual int initFunc (void) + virtual int initFunc (int i) { - return 0; + return i; } - virtual int registerFunc (Plugin **plugin) - { - Plugin *ret; - - ret = new Plugin(this); - - ret->_name = getInterfaceName(); - ret->_required = 1; - ret->_version_major=1; - ret->_version_minor=0; - - *plugin = ret; - return 0; - } }; - -} -extern "C" ::sflphone::PluginInterface* create (void){ - return new ::sflphone::PluginTest("test"); } -extern "C" void* destroy( ::sflphone::PluginInterface *p ){ +extern "C" ::sflphone::Plugin* create (void){ + return new ::sflphone::PluginTest("mytest"); +} + +extern "C" void destroy (::sflphone::Plugin *p){ delete p; } diff --git a/test/pluginmanagerTest.cpp b/test/pluginmanagerTest.cpp index ed3f4d7e2..5a45ffabf 100644 --- a/test/pluginmanagerTest.cpp +++ b/test/pluginmanagerTest.cpp @@ -19,33 +19,67 @@ #include #include +#include #include "pluginmanagerTest.h" using std::cout; using std::endl; +#define PLUGIN_TEST_DIR "/usr/lib/sflphone/plugins/libplugintest.so" +#define PLUGIN_TEST_NAME "mytest" + + void PluginManagerTest::setUp(){ // Instanciate the plugin manager singleton _pm = ::sflphone::PluginManager::instance(); + handlePtr = NULL; + plugin = 0; } -void PluginManagerTest::testLoadPluginDirectory(){ - CPPUNIT_ASSERT(_pm->loadPlugins() == 0); +void PluginManagerTest::testLoadDynamicLibrary(){ + CPPUNIT_ASSERT(_pm->loadDynamicLibrary(PLUGIN_TEST_DIR) != NULL); } -void PluginManagerTest::testLoadPlugin(){ - CPPUNIT_ASSERT(_pm->loadPlugins() == 0); - //CPPUNIT_ASSERT( _pm->isPluginLoaded("test") == NULL ); +void PluginManagerTest::testUnloadDynamicLibrary(){ + + handlePtr = _pm->loadDynamicLibrary(PLUGIN_TEST_DIR); + CPPUNIT_ASSERT(handlePtr != 0); + CPPUNIT_ASSERT(_pm->unloadDynamicLibrary(handlePtr) == 0 ); +} + +void PluginManagerTest::testInstanciatePlugin(){ + + handlePtr = _pm->loadDynamicLibrary (PLUGIN_TEST_DIR); + CPPUNIT_ASSERT (handlePtr != 0); + CPPUNIT_ASSERT (_pm->instanciatePlugin (handlePtr, &plugin) == 0); + CPPUNIT_ASSERT (plugin!=NULL); +} + +void PluginManagerTest::testInitPlugin(){ + + handlePtr = _pm->loadDynamicLibrary (PLUGIN_TEST_DIR); + CPPUNIT_ASSERT (handlePtr != 0); + CPPUNIT_ASSERT (_pm->instanciatePlugin (handlePtr, &plugin) == 0); + CPPUNIT_ASSERT (plugin!=NULL); + CPPUNIT_ASSERT (plugin->initFunc(0) == 0); + CPPUNIT_ASSERT (plugin->getPluginName() == PLUGIN_TEST_NAME); } void PluginManagerTest::testRegisterPlugin(){ - // First load the default directory - _pm->loadPlugins(); - // Resolve the symbol + + handlePtr = _pm->loadDynamicLibrary (PLUGIN_TEST_DIR); + CPPUNIT_ASSERT (handlePtr != 0); + CPPUNIT_ASSERT (_pm->instanciatePlugin (handlePtr, &plugin) == 0); + CPPUNIT_ASSERT (_pm->isPluginLoaded (PLUGIN_TEST_NAME) == NULL); + CPPUNIT_ASSERT (_pm->registerPlugin (handlePtr, plugin) == 0); + CPPUNIT_ASSERT (_pm->isPluginLoaded (PLUGIN_TEST_NAME) == plugin); } void PluginManagerTest::tearDown(){ // Delete the plugin manager object delete _pm; _pm=0; + handlePtr = NULL; + if(plugin) + delete plugin; plugin = 0; } diff --git a/test/pluginmanagerTest.h b/test/pluginmanagerTest.h index 0cd92da42..857b265de 100644 --- a/test/pluginmanagerTest.h +++ b/test/pluginmanagerTest.h @@ -27,6 +27,7 @@ // Application import #include "plug-in/pluginmanager.h" +#include "plug-in/plugin.h" /* * @file pluginManagerTest.cpp @@ -38,12 +39,16 @@ class PluginManagerTest : public CppUnit::TestCase { + class Plugin; + /* * Use cppunit library macros to add unit test the factory */ CPPUNIT_TEST_SUITE( PluginManagerTest ); - CPPUNIT_TEST( testLoadPluginDirectory ); - CPPUNIT_TEST( testLoadPlugin ); + CPPUNIT_TEST( testLoadDynamicLibrary ); + CPPUNIT_TEST( testUnloadDynamicLibrary ); + CPPUNIT_TEST( testInstanciatePlugin ); + CPPUNIT_TEST( testInitPlugin ); CPPUNIT_TEST( testRegisterPlugin ); CPPUNIT_TEST_SUITE_END(); @@ -62,14 +67,20 @@ class PluginManagerTest : public CppUnit::TestCase { */ inline void tearDown(); - void testLoadPluginDirectory(); + void testLoadDynamicLibrary(); - void testLoadPlugin(); + void testUnloadDynamicLibrary(); + + void testInstanciatePlugin(); + + void testInitPlugin(); void testRegisterPlugin(); private: ::sflphone::PluginManager *_pm; + void *handlePtr; + ::sflphone::Plugin *plugin; }; /* Register our test module */ From 3cc24f262ae46681bffda6c68da3018ebac376fb Mon Sep 17 00:00:00 2001 From: Emmanuel Milou Date: Mon, 2 Feb 2009 23:46:00 -0500 Subject: [PATCH 13/14] Add a library manager + exception handling; Remove namespace --- src/plug-in/Makefile.am | 3 +- src/plug-in/librarymanager.cpp | 83 +++++++++++++++ src/plug-in/librarymanager.h | 51 ++++++++++ src/plug-in/plugin.h | 41 ++++---- src/plug-in/pluginmanager.cpp | 175 +++++++++++++++++++++----------- src/plug-in/pluginmanager.h | 55 ++++++---- src/plug-in/test/pluginTest.cpp | 36 ++++--- test/pluginmanagerTest.cpp | 60 ++++++----- test/pluginmanagerTest.h | 27 +++-- 9 files changed, 374 insertions(+), 157 deletions(-) create mode 100644 src/plug-in/librarymanager.cpp create mode 100644 src/plug-in/librarymanager.h diff --git a/src/plug-in/Makefile.am b/src/plug-in/Makefile.am index ae5675eef..f62b7c3de 100644 --- a/src/plug-in/Makefile.am +++ b/src/plug-in/Makefile.am @@ -5,5 +5,6 @@ noinst_LTLIBRARIES = libplugin.la SUBDIRS=test libplugin_la_SOURCES = \ - pluginmanager.cpp + pluginmanager.cpp \ + librarymanager.cpp diff --git a/src/plug-in/librarymanager.cpp b/src/plug-in/librarymanager.cpp new file mode 100644 index 000000000..0cc2dd546 --- /dev/null +++ b/src/plug-in/librarymanager.cpp @@ -0,0 +1,83 @@ +#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 000000000..5360047e7 --- /dev/null +++ b/src/plug-in/librarymanager.h @@ -0,0 +1,51 @@ +#ifndef LIBRARY_MANAGER_H +#define LIBRARY_MANAGER_H + +#include "dlfcn.h" +#include + +#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 index 6adac44f9..b020cf147 100644 --- a/src/plug-in/plugin.h +++ b/src/plug-in/plugin.h @@ -4,40 +4,39 @@ #include #include "global.h" +#include "pluginmanager.h" + /* * @file plugin.h * @brief Define a plugin object */ -namespace sflphone { +class Plugin { - class Plugin { + public: + Plugin( const std::string &name ){ + _name = name; + } - public: - Plugin( const std::string &name ){ - _name = name; - } + virtual ~Plugin() {} - virtual ~Plugin() {} + inline std::string getPluginName (void) { return _name; } - 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; - /** - * Return the minimal core version required so that the plugin could work - * @return int The version required - */ - virtual int initFunc (int i) = 0; - - private: - Plugin &operator =(const Plugin &plugin); + private: + Plugin &operator =(const Plugin &plugin); - std::string _name; - }; + std::string _name; +}; -} -typedef ::sflphone::Plugin* createFunc (void); +typedef Plugin* createFunc (void); -typedef void destroyFunc (::sflphone::Plugin*); +typedef void destroyFunc (Plugin*); #endif //PLUGIN_H diff --git a/src/plug-in/pluginmanager.cpp b/src/plug-in/pluginmanager.cpp index 7a259f7fc..5b5467569 100644 --- a/src/plug-in/pluginmanager.cpp +++ b/src/plug-in/pluginmanager.cpp @@ -3,10 +3,10 @@ #include "pluginmanager.h" -::sflphone::PluginManager* ::sflphone::PluginManager::_instance = 0; +PluginManager* PluginManager::_instance = 0; - ::sflphone::PluginManager* -::sflphone::PluginManager::instance() + PluginManager* +PluginManager::instance() { if(!_instance){ return new PluginManager(); @@ -14,28 +14,26 @@ return _instance; } -::sflphone::PluginManager::PluginManager() - :_loadedPlugins() + PluginManager::PluginManager() +:_loadedPlugins() { _instance = this; } -::sflphone::PluginManager::~PluginManager() +PluginManager::~PluginManager() { _instance = 0; } int -::sflphone::PluginManager::loadPlugins (const std::string &path) +PluginManager::loadPlugins (const std::string &path) { std::string pluginDir, current; - ::sflphone::Plugin *plugin; DIR *dir; dirent *dirStruct; - int result=0; - void *handle; - createFunc* createPlugin; - + LibraryManager *library; + Plugin *plugin; + const std::string pDir = ".."; const std::string cDir = "."; @@ -52,22 +50,25 @@ current = dirStruct->d_name; /* Test if the current item is not the parent or the current directory */ if( current != pDir && current != cDir ){ - handle = loadDynamicLibrary( pluginDir + current ); - - if(instanciatePlugin (handle, &plugin) != 0) + + /* 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; } - - /* - if(registerPlugin (handle, interface) != 0) + + /* Regitering the current plugin */ + if(registerPlugin (plugin, library) != 0) { _debug("Error registering the plugin ...\n"); return 1; - }*/ + } } - } + } } else return 1; @@ -78,84 +79,134 @@ return 0; } - ::sflphone::Plugin* -::sflphone::PluginManager::isPluginLoaded (const std::string &name) +int +PluginManager::unloadPlugins (void) { - if(_loadedPlugins.empty()) return NULL; + 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() ) { - if ( iter->first == name ) { - /* Return the associated plugin */ - return iter->second; + 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; +} - /* If we are here, it means that the plugin we were looking for has not been loaded */ - return NULL; + 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; } - void* -::sflphone::PluginManager::loadDynamicLibrary (const std::string& filename) + LibraryManager* +PluginManager::loadDynamicLibrary (const std::string& filename) { - - void *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; - + /* Load the library through the library manager */ + return new LibraryManager (filename); } int -::sflphone::PluginManager::instanciatePlugin (void *handlePtr, ::sflphone::Plugin **plugin) +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; - createPlugin = (createFunc*)dlsym(handlePtr, "create"); - if( dlerror() ) - { - _debug("Error creating the plugin: %s\n", dlerror()); + if (libraryPtr->resolveSymbol ("createPlugin", &symbol) != 0) return 1; - } + createPlugin = (createFunc*)symbol; *plugin = createPlugin(); return 0; } int -::sflphone::PluginManager::registerPlugin (void *handlePtr, Plugin *plugin) +PluginManager::deletePlugin (PluginInfo *plugin) { - std::string name; + destroyFunc *destroyPlugin; + LibraryManager::SymbolHandle symbol; - if( !(handlePtr && plugin!=0) ) + if (plugin->_libraryPtr->resolveSymbol ("destroyPlugin", &symbol) != 0) return 1; - - name = plugin->getPluginName(); - /* Add the data in the loaded plugin map */ - _loadedPlugins[ name ] = plugin; + destroyPlugin = (destroyFunc*)symbol; + /* Call it */ + destroyPlugin (plugin->_plugin); return 0; } int -::sflphone::PluginManager::unloadDynamicLibrary (void * pluginHandlePtr) +PluginManager::registerPlugin (Plugin *plugin, LibraryManager *library) { - dlclose( pluginHandlePtr ); - dlerror(); + 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 index f24b1779f..13db428d6 100644 --- a/src/plug-in/pluginmanager.h +++ b/src/plug-in/pluginmanager.h @@ -6,19 +6,27 @@ * @brief Base class of the plugin manager */ -#include "plugin.h" +#include "librarymanager.h" #include "global.h" #include #include +#include -namespace sflphone { +class Plugin; - class PluginManager { +typedef struct PluginInfo { + std::string _name; + LibraryManager *_libraryPtr; + Plugin *_plugin; + int _major_version; + int _minor_version; +} PluginInfo; +#include "plugin.h" - public: - +class PluginManager { + public: /** * Destructor */ @@ -34,46 +42,51 @@ namespace sflphone { * @param path The absolute path to the directory * @return int The number of items loaded */ - int loadPlugins( const std::string &path = "" ); + int loadPlugins (const std::string &path = ""); - int instanciatePlugin( void *handlePtr, Plugin** plugin ); + 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 Plugin* The pointer on the plugin or NULL if not found + * @return bool The pointer on the plugin or NULL if not found */ - Plugin* isPluginLoaded( const std::string &name ); + bool isPluginLoaded (const std::string &name); - int registerPlugin (void *handle, Plugin *plugin); + 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 void* A pointer on it + * @return LibraryManager* A pointer on the library */ - void * loadDynamicLibrary( const std::string &filename ); - + LibraryManager* loadDynamicLibrary (const std::string &filename); + /** * Unload a unix dynamic/shared library - * @param pluginHandleptr The pointer on the loaded plugin + * @param LibraryManager* The pointer on the loaded library */ - int unloadDynamicLibrary( void * pluginHandlePtr ); + int unloadDynamicLibrary (LibraryManager* libraryPtr); - - private: + private: /** * Default constructor */ PluginManager(); - + /* Map of plugins associated by their string name */ - typedef std::map pluginMap; + typedef std::map pluginMap; pluginMap _loadedPlugins; /* The unique static instance */ static PluginManager* _instance; - }; -} + +}; #endif //PLUGIN_MANAGER_H diff --git a/src/plug-in/test/pluginTest.cpp b/src/plug-in/test/pluginTest.cpp index 3aeb92707..20038527f 100644 --- a/src/plug-in/test/pluginTest.cpp +++ b/src/plug-in/test/pluginTest.cpp @@ -1,26 +1,30 @@ #include "../plugin.h" -namespace sflphone { +#define MAJOR_VERSION 1 +#define MINOR_VERSION 0 - class PluginTest : public Plugin { - - public: - PluginTest( const std::string &name ) - :Plugin( name ) { - } +class PluginTest : public Plugin { - virtual int initFunc (int i) - { - return i; + 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" ::sflphone::Plugin* create (void){ - return new ::sflphone::PluginTest("mytest"); -} - -extern "C" void destroy (::sflphone::Plugin *p){ +extern "C" void destroyPlugin (Plugin *p){ delete p; } diff --git a/test/pluginmanagerTest.cpp b/test/pluginmanagerTest.cpp index 5a45ffabf..96994b692 100644 --- a/test/pluginmanagerTest.cpp +++ b/test/pluginmanagerTest.cpp @@ -26,60 +26,70 @@ using std::cout; using std::endl; -#define PLUGIN_TEST_DIR "/usr/lib/sflphone/plugins/libplugintest.so" -#define PLUGIN_TEST_NAME "mytest" +#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 = ::sflphone::PluginManager::instance(); - handlePtr = NULL; + _pm = PluginManager::instance(); + library = 0; plugin = 0; } void PluginManagerTest::testLoadDynamicLibrary(){ - CPPUNIT_ASSERT(_pm->loadDynamicLibrary(PLUGIN_TEST_DIR) != NULL); + CPPUNIT_ASSERT(_pm->loadDynamicLibrary(PLUGIN_TEST_NAME) != NULL); } void PluginManagerTest::testUnloadDynamicLibrary(){ - - handlePtr = _pm->loadDynamicLibrary(PLUGIN_TEST_DIR); - CPPUNIT_ASSERT(handlePtr != 0); - CPPUNIT_ASSERT(_pm->unloadDynamicLibrary(handlePtr) == 0 ); + library = _pm->loadDynamicLibrary(PLUGIN_TEST_NAME); + CPPUNIT_ASSERT(library != NULL); + CPPUNIT_ASSERT(_pm->unloadDynamicLibrary(library) == 0 ); } void PluginManagerTest::testInstanciatePlugin(){ - - handlePtr = _pm->loadDynamicLibrary (PLUGIN_TEST_DIR); - CPPUNIT_ASSERT (handlePtr != 0); - CPPUNIT_ASSERT (_pm->instanciatePlugin (handlePtr, &plugin) == 0); + library = _pm->loadDynamicLibrary (PLUGIN_TEST_NAME); + CPPUNIT_ASSERT(library != NULL); + CPPUNIT_ASSERT (_pm->instanciatePlugin (library, &plugin) == 0); CPPUNIT_ASSERT (plugin!=NULL); } void PluginManagerTest::testInitPlugin(){ - handlePtr = _pm->loadDynamicLibrary (PLUGIN_TEST_DIR); - CPPUNIT_ASSERT (handlePtr != 0); - CPPUNIT_ASSERT (_pm->instanciatePlugin (handlePtr, &plugin) == 0); + library = _pm->loadDynamicLibrary (PLUGIN_TEST_NAME); + CPPUNIT_ASSERT(library != NULL); + CPPUNIT_ASSERT (_pm->instanciatePlugin (library, &plugin) == 0); CPPUNIT_ASSERT (plugin!=NULL); - CPPUNIT_ASSERT (plugin->initFunc(0) == 0); - CPPUNIT_ASSERT (plugin->getPluginName() == PLUGIN_TEST_NAME); + 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); +} - handlePtr = _pm->loadDynamicLibrary (PLUGIN_TEST_DIR); - CPPUNIT_ASSERT (handlePtr != 0); - CPPUNIT_ASSERT (_pm->instanciatePlugin (handlePtr, &plugin) == 0); - CPPUNIT_ASSERT (_pm->isPluginLoaded (PLUGIN_TEST_NAME) == NULL); - CPPUNIT_ASSERT (_pm->registerPlugin (handlePtr, plugin) == 0); - CPPUNIT_ASSERT (_pm->isPluginLoaded (PLUGIN_TEST_NAME) == plugin); +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; - handlePtr = NULL; if(plugin) delete plugin; plugin = 0; + if(library) + delete library; library = 0; } diff --git a/test/pluginmanagerTest.h b/test/pluginmanagerTest.h index 857b265de..2e4219584 100644 --- a/test/pluginmanagerTest.h +++ b/test/pluginmanagerTest.h @@ -27,6 +27,7 @@ // Application import #include "plug-in/pluginmanager.h" +#include "plug-in/librarymanager.h" #include "plug-in/plugin.h" /* @@ -39,8 +40,6 @@ class PluginManagerTest : public CppUnit::TestCase { - class Plugin; - /* * Use cppunit library macros to add unit test the factory */ @@ -50,6 +49,8 @@ class PluginManagerTest : public CppUnit::TestCase { CPPUNIT_TEST( testInstanciatePlugin ); CPPUNIT_TEST( testInitPlugin ); CPPUNIT_TEST( testRegisterPlugin ); + CPPUNIT_TEST( testLoadPlugins ); + CPPUNIT_TEST( testUnloadPlugins ); CPPUNIT_TEST_SUITE_END(); public: @@ -65,22 +66,26 @@ class PluginManagerTest : public CppUnit::TestCase { * Code factoring - Common resources can be released here. * This method is called by unitcpp after each test */ - inline void tearDown(); + inline void tearDown (); - void testLoadDynamicLibrary(); + void testLoadDynamicLibrary (); - void testUnloadDynamicLibrary(); + void testUnloadDynamicLibrary (); - void testInstanciatePlugin(); + void testInstanciatePlugin (); - void testInitPlugin(); + void testInitPlugin (); - void testRegisterPlugin(); + void testRegisterPlugin (); + + void testLoadPlugins (); + + void testUnloadPlugins (); private: - ::sflphone::PluginManager *_pm; - void *handlePtr; - ::sflphone::Plugin *plugin; + PluginManager *_pm; + LibraryManager *library; + Plugin *plugin; }; /* Register our test module */ From 5cec71539fdf4b9107b18c5d70d8b5d4232c7141 Mon Sep 17 00:00:00 2001 From: Emmanuel Milou Date: Wed, 4 Feb 2009 10:00:17 -0500 Subject: [PATCH 14/14] Add header files --- src/plug-in/Makefile.am | 2 +- src/plug-in/librarymanager.cpp | 103 +++++++++++++++++ src/plug-in/librarymanager.h | 70 ++++++++++++ src/plug-in/plugin.cpp | 15 --- src/plug-in/plugin.h | 69 +++++++---- src/plug-in/pluginmanager.cpp | 202 ++++++++++++++++++++++----------- src/plug-in/pluginmanager.h | 86 +++++++++----- test/pluginmanagerTest.h | 30 +++-- 8 files changed, 441 insertions(+), 136 deletions(-) create mode 100644 src/plug-in/librarymanager.cpp create mode 100644 src/plug-in/librarymanager.h delete mode 100644 src/plug-in/plugin.cpp diff --git a/src/plug-in/Makefile.am b/src/plug-in/Makefile.am index b69f39ca9..c97ccdc21 100644 --- a/src/plug-in/Makefile.am +++ b/src/plug-in/Makefile.am @@ -8,5 +8,5 @@ SUBDIRS=test libplugin_la_SOURCES = \ pluginmanager.cpp \ - plugin.cpp + librarymanager.cpp diff --git a/src/plug-in/librarymanager.cpp b/src/plug-in/librarymanager.cpp new file mode 100644 index 000000000..138b59f5f --- /dev/null +++ b/src/plug-in/librarymanager.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2009 Savoir-Faire Linux inc. + * Author: Emmanuel Milou + * + * 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 000000000..e244d448a --- /dev/null +++ b/src/plug-in/librarymanager.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2009 Savoir-Faire Linux inc. + * Author: Emmanuel Milou + * + * 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 + +#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.cpp b/src/plug-in/plugin.cpp deleted file mode 100644 index deaf1a481..000000000 --- a/src/plug-in/plugin.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "plugin.h" - -::sflphone::Plugin::Plugin (void *handle, PluginInterface *interface) - :_handlePtr(handle), _interface(interface) -{ -} - -::sflphone::Plugin::Plugin (PluginInterface *interface) - :_interface(interface) -{ -} - -::sflphone::Plugin::~Plugin () -{ -} diff --git a/src/plug-in/plugin.h b/src/plug-in/plugin.h index fe548361e..2769c56c3 100644 --- a/src/plug-in/plugin.h +++ b/src/plug-in/plugin.h @@ -1,32 +1,61 @@ +/* + * Copyright (C) 2009 Savoir-Faire Linux inc. + * Author: Emmanuel Milou + * + * 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 "plugininterface.h" +#include "global.h" -namespace sflphone { +#include "pluginmanager.h" - class PluginInterface; +/* + * @file plugin.h + * @brief Define a plugin object + */ - class Plugin { +class Plugin { - public: + public: + Plugin( const std::string &name ){ + _name = name; + } - Plugin (void*, PluginInterface *interface); - Plugin (PluginInterface *interface); + virtual ~Plugin() {} - ~Plugin (); + inline std::string getPluginName (void) { return _name; } - void setName (std::string name); - private: - std::string _name; - int _version_major; - int _version_minor; - int _required; - void *_handlePtr; - PluginInterface *_interface; + /** + * 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*); - friend class PluginTest; - friend class PluginManager; - }; -} #endif //PLUGIN_H + diff --git a/src/plug-in/pluginmanager.cpp b/src/plug-in/pluginmanager.cpp index f8135f578..8d391f6ae 100644 --- a/src/plug-in/pluginmanager.cpp +++ b/src/plug-in/pluginmanager.cpp @@ -1,12 +1,31 @@ +/* + * Copyright (C) 2009 Savoir-Faire Linux inc. + * Author: Emmanuel Milou + * + * 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 #include #include "pluginmanager.h" -::sflphone::PluginManager* ::sflphone::PluginManager::_instance = 0; +PluginManager* PluginManager::_instance = 0; - ::sflphone::PluginManager* -::sflphone::PluginManager::instance() + PluginManager* +PluginManager::instance() { if(!_instance){ return new PluginManager(); @@ -14,28 +33,26 @@ return _instance; } -::sflphone::PluginManager::PluginManager() - :_loadedPlugins() + PluginManager::PluginManager() +:_loadedPlugins() { _instance = this; } -::sflphone::PluginManager::~PluginManager() +PluginManager::~PluginManager() { _instance = 0; } int -::sflphone::PluginManager::loadPlugins (const std::string &path) +PluginManager::loadPlugins (const std::string &path) { std::string pluginDir, current; - ::sflphone::PluginInterface *interface; DIR *dir; dirent *dirStruct; - int result=0; - void *handle; - createFunc* createPlugin; - + LibraryManager *library; + Plugin *plugin; + const std::string pDir = ".."; const std::string cDir = "."; @@ -52,19 +69,25 @@ current = dirStruct->d_name; /* Test if the current item is not the parent or the current directory */ if( current != pDir && current != cDir ){ - handle = loadDynamicLibrary( pluginDir + current ); - - if(instanciatePlugin (handle, &interface) != 0) + + /* 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; } - - if(registerPlugin (handle, interface) != 0) + + /* Regitering the current plugin */ + if(registerPlugin (plugin, library) != 0) + { _debug("Error registering the plugin ...\n"); return 1; + } } - } + } } else return 1; @@ -75,89 +98,134 @@ return 0; } - ::sflphone::Plugin* -::sflphone::PluginManager::isPluginLoaded (const std::string &name) +int +PluginManager::unloadPlugins (void) { - if(_loadedPlugins.empty()) return NULL; + 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() ) { - if ( iter->first == name ) { - /* Return the associated plugin */ - return iter->second; + 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; +} - /* If we are here, it means that the plugin we were looking for has not been loaded */ - return NULL; + 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; } - void* -::sflphone::PluginManager::loadDynamicLibrary (const std::string& filename) + LibraryManager* +PluginManager::loadDynamicLibrary (const std::string& filename) { - - void *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; - + /* Load the library through the library manager */ + return new LibraryManager (filename); } int -::sflphone::PluginManager::instanciatePlugin (void *handlePtr, ::sflphone::PluginInterface **plugin) +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; - createPlugin = (createFunc*)dlsym(handlePtr, "create"); - if( dlerror() ) - { - _debug("Error creating the plugin: %s\n", dlerror()); + if (libraryPtr->resolveSymbol ("createPlugin", &symbol) != 0) return 1; - } + createPlugin = (createFunc*)symbol; *plugin = createPlugin(); return 0; } int -::sflphone::PluginManager::registerPlugin (void *handlePtr, PluginInterface *interface) +PluginManager::deletePlugin (PluginInfo *plugin) { - Plugin *myplugin; - std::string name; + destroyFunc *destroyPlugin; + LibraryManager::SymbolHandle symbol; - if( !( handlePtr && interface!=0 ) ) + if (plugin->_libraryPtr->resolveSymbol ("destroyPlugin", &symbol) != 0) return 1; - - /* Fetch information from the loaded plugin interface */ - if(interface->registerFunc (&myplugin) != 0) - return 1; - /* Creation of the plugin wrapper */ - myplugin = new Plugin (handlePtr, interface); - - /* Add the data in the loaded plugin map */ - _loadedPlugins[ myplugin->_name ] = myplugin; + destroyPlugin = (destroyFunc*)symbol; + /* Call it */ + destroyPlugin (plugin->_plugin); return 0; } - void -::sflphone::PluginManager::unloadDynamicLibrary (void * pluginHandlePtr) + int +PluginManager::registerPlugin (Plugin *plugin, LibraryManager *library) { - dlclose( pluginHandlePtr ); - dlerror(); + 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 index 671834369..4b3a18692 100644 --- a/src/plug-in/pluginmanager.h +++ b/src/plug-in/pluginmanager.h @@ -1,3 +1,22 @@ +/* + * Copyright (C) 2009 Savoir-Faire Linux inc. + * Author: Emmanuel Milou + * + * 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 @@ -6,18 +25,27 @@ * @brief Base class of the plugin manager */ -#include "plugininterface.h" +#include "librarymanager.h" #include "global.h" #include #include +#include -namespace sflphone { +class Plugin; - class PluginManager { +typedef struct PluginInfo { + std::string _name; + LibraryManager *_libraryPtr; + Plugin *_plugin; + int _major_version; + int _minor_version; +} PluginInfo; +#include "plugin.h" - public: +class PluginManager { + public: /** * Destructor */ @@ -33,45 +61,51 @@ namespace sflphone { * @param path The absolute path to the directory * @return int The number of items loaded */ - int loadPlugins( const std::string &path = "" ); + int loadPlugins (const std::string &path = ""); - int instanciatePlugin( void *handlePtr, PluginInterface** plugin ); + 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 Plugin* The pointer on the plugin or NULL if not found + * @return bool The pointer on the plugin or NULL if not found */ - Plugin* isPluginLoaded( const std::string &name ); + bool isPluginLoaded (const std::string &name); - int registerPlugin (void *handle, PluginInterface *interface); + int registerPlugin (Plugin *plugin, LibraryManager *library); + + int unregisterPlugin (PluginInfo *plugin); - private: + 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(); - /** - * Load a unix dynamic/shared library - * @param filename The path to the dynamic/shared library - * @return void* A pointer on it - */ - void * loadDynamicLibrary( const std::string &filename ); - - /** - * Unload a unix dynamic/shared library - * @param pluginHandleptr The pointer on the loaded plugin - */ - void unloadDynamicLibrary( void * pluginHandlePtr ); - /* Map of plugins associated by their string name */ - typedef std::map pluginMap; + typedef std::map pluginMap; pluginMap _loadedPlugins; /* The unique static instance */ static PluginManager* _instance; - }; -} + +}; #endif //PLUGIN_MANAGER_H diff --git a/test/pluginmanagerTest.h b/test/pluginmanagerTest.h index 0cd92da42..2e4219584 100644 --- a/test/pluginmanagerTest.h +++ b/test/pluginmanagerTest.h @@ -27,6 +27,8 @@ // Application import #include "plug-in/pluginmanager.h" +#include "plug-in/librarymanager.h" +#include "plug-in/plugin.h" /* * @file pluginManagerTest.cpp @@ -42,9 +44,13 @@ class PluginManagerTest : public CppUnit::TestCase { * Use cppunit library macros to add unit test the factory */ CPPUNIT_TEST_SUITE( PluginManagerTest ); - CPPUNIT_TEST( testLoadPluginDirectory ); - CPPUNIT_TEST( testLoadPlugin ); + 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: @@ -60,16 +66,26 @@ class PluginManagerTest : public CppUnit::TestCase { * Code factoring - Common resources can be released here. * This method is called by unitcpp after each test */ - inline void tearDown(); + inline void tearDown (); - void testLoadPluginDirectory(); + void testLoadDynamicLibrary (); - void testLoadPlugin(); + void testUnloadDynamicLibrary (); - void testRegisterPlugin(); + void testInstanciatePlugin (); + + void testInitPlugin (); + + void testRegisterPlugin (); + + void testLoadPlugins (); + + void testUnloadPlugins (); private: - ::sflphone::PluginManager *_pm; + PluginManager *_pm; + LibraryManager *library; + Plugin *plugin; }; /* Register our test module */