Re: [GnomeMeeting-devel-list] [BETA7] the "I'm in a real hurry" release
- From: PUYDT Julien <julien puydt laposte net>
- To: GnomeMeeting Devel Liste <gnomemeeting-devel-list gnome org>
- Subject: Re: [GnomeMeeting-devel-list] [BETA7] the "I'm in a real hurry" release
- Date: 11 Aug 2003 20:36:21 +0200
Le lun 11/08/2003 à 17:52, PUYDT Julien a écrit :
> * INPUT->Input & OUTPUT->Output;
Oh, well... I tested the new manager, and didn't see I had forgotten one
such in the dlopen one...
Snark
/* This is an implementation of the PDeviceManager class,
that should work on any OS providing the dlopen&dlsym calls.
It stores the list in a custom one-linked list of plugins, that
is almost read-only: only one function writes to it, LoadPlugin,
and it only adds plugins at the beginning of the list.
Once a plugin is loaded, it is for the life of the program: the list
is never, ever, explicitly freed.
A plugin for this manager comes in the form of (those are AND):
* shared lib;
* the implementation of a class derived from PVideoInputDevice and/or
PVideoOutputDevice and/or PSoundChannel (depending on the type of plugin);
* some extern "C"-defined functions;
To get more specific, a typical plugin comes a a .h, declaring some classes
as public PVideoInputDevice/PVideoOutputDevice/PSoundChannel, and a .cxx,
that defines the classes, and uses the following macros:
* DECLARE_PLUGIN(NAME, TYPE): with the name of the plugin (example: "V4L"),
and its type (example: PDeviceManager::VIDEOIN) (mandatory);
* DECLARE_PLUGIN_VIDEOINPUT(CLASS): the name of the class inheriting from
PVideoInputDevice (optional);
* DECLARE_PLUGIN_VIDEOOUTPUT(CLASS): the name of the class inheriting from
PVideoOutputDevice (optional);
* DECLARE_PLUGIN_SOUNDINPUT(CLASS): the name of the class inheriting from
PSoundChannel, that handles sound input (optional);
* DECLARE_PLUGIN_SOUNDOUTPUT(CLASS): the name of the class inheriting from
PSoundChannel, that handles sound output (optional);
*/
// system includes
#include <dlfcn.h>
// PWLib includes
#include <ptlib.h>
#include <ptlib/videoio.h>
#include <ptlib/vconvert.h>
#include <ptlib/pdirect.h>
#include <ptlib/plugins.h>
#include <ptbuildopts.h>
#define DRIVERNAMELEN 11 // FIXME! Only ten chars for the driver name...
struct device_plugin {
// common to all types
const char *name;
int type;
void *handle;
struct device_plugin *next;
// video input
PVideoInputDevice *(*create_vidin)(void);
PStringList (*devnames_vidin)(void);
// video output
PVideoOutputDevice *(*create_vidout)(void);
PStringList (*devnames_vidout)(void);
// sound input
PSoundChannel *(*create_sndin)(void);
PStringArray (*devnames_sndin)(void);
// sound output
PSoundChannel *(*create_sndout)(void);
PStringArray (*devnames_sndout)(void);
};
// helper functions
static void LoadAllPlugins();
static PSoundChannel::Directions to_pscdir(PDeviceManager::Direction);
// plugin list variables
static struct device_plugin *plugins_list;
static PMutex mutex;
PDeviceManager::PDeviceManager()
{
PTRACE(3, "PDeviceManager::PDeviceManager called: useless...");
mutex.Wait();
if(plugins_list == NULL)
{
mutex.Signal();
LoadAllPlugins();
}
else
mutex.Signal();
}
PDeviceManager::~PDeviceManager()
{
// well, you're not really supposed to create one anyway...
}
void
LoadAllPlugins()
{
PTRACE(3, "Loading plugins...");
if(PDeviceManager::LoadPluginDirectory((PString)SYSPLUGINDIR) == FALSE)
{
PTRACE(2, "Couldn't load any system plugin!");
}
}
BOOL
PDeviceManager::LoadPluginDirectory(PDirectory plugdir)
{
BOOL Result = FALSE;
PTRACE(4, "Considering loading plugins in " << plugdir);
if(!plugdir.Open())
{
PTRACE(4, "the dir isn't accessible");
return Result; // no love, no hope
}
do
{
PString entry = plugdir+plugdir.GetEntryName();
if(plugdir.IsSubDir())
Result = LoadPluginDirectory(entry) || Result; // BEWARE of the...
else
Result = LoadPlugin(entry) || Result; // lazy evaluation!!!
}
while(plugdir.Next());
return Result;
}
BOOL
PDeviceManager::LoadPlugin(PString filename)
{
void *handle = NULL;
struct device_plugin *plugin = NULL;
ostream & s = PTrace::Begin(0, "Plugin manager: ", 0);
plugin = (struct device_plugin *)malloc(sizeof(struct device_plugin));
if(plugin == NULL)
{
s << "PDeviceManager::LoadPlugin: ENOMEM\n" << PTrace::End(s);
return FALSE;
}
s << "trying to load " << filename << '\n';
// first, we try to get a handle on the plugin
handle=dlopen(filename, RTLD_NOW);
if(handle == NULL)
{
s << "dlerror=" << dlerror() << "\n" << PTrace::End(s);
free(plugin);
return FALSE;
}
plugin->handle = handle;
// second, we try to get its name
char *(*getname)(void);
getname = (char *(*)())dlsym(handle, "plugin_getname");
if(getname == NULL)
{
s << "dlerror=" << dlerror() << "\n";
goto wrong;
}
plugin->name = (*getname)();
// third, we try to get its type
int (*gettype)(void);
gettype = (int (*)())dlsym(handle, "plugin_gettype");
if(gettype == NULL)
{
s << "dlerror=" << dlerror() << "\n";
goto wrong;
}
plugin->type = (*gettype)();
// the rest depends on the type of plugin, so we do it step-by-step:
// does it provide a video input?
if(plugin->type & VIDIN)
{
PVideoInputDevice *(*create)();
PStringList (*devnames)();
create = (PVideoInputDevice *(*)())dlsym(handle,
"plugin_create_vidin");
devnames = (PStringList (*)())dlsym(handle,
"plugin_getdevices_vidin");
if((create == NULL)
|| (devnames == NULL))
{
s << "dlerror=" << dlerror() << "\n";
goto wrong;
}
plugin->create_vidin = create;
plugin->devnames_vidin = devnames;
}
else
{
plugin->create_vidin = NULL;
plugin->devnames_vidin = NULL;
}
// does it provide a video output?
if(plugin->type & VIDOUT)
{
PVideoOutputDevice *(*create)();
PStringList (*devnames)();
create = (PVideoOutputDevice *(*)())dlsym(handle,
"plugin_create_vidout");
devnames = (PStringList (*)())dlsym(handle,
"plugin_getdevices_vidout");
if((create == NULL)
|| (devnames == NULL))
{
s << "dlerror=" << dlerror() << "\n";
goto wrong;
}
plugin->create_vidout = create;
plugin->devnames_vidout = devnames;
}
else
{
plugin->create_vidout = NULL;
plugin->devnames_vidout = NULL;
}
// does it provide a sound input?
if(plugin->type & SNDIN)
{
PSoundChannel *(*create)();
PStringArray (*devnames)();
create = (PSoundChannel *(*)())dlsym(handle,
"plugin_create_sndin");
devnames = (PStringArray (*)())dlsym(handle,
"plugin_getdevices_sndin");
if((create == NULL)
|| (devnames == NULL))
{
s << "dlerror=" << dlerror() << "\n";
goto wrong;
}
plugin->create_sndin = create;
plugin->devnames_sndin = devnames;
}
else
{
plugin->create_sndin = NULL;
plugin->devnames_sndin = NULL;
}
// does it provide a sound output?
if(plugin->type & SNDOUT)
{
PSoundChannel *(*create)();
PStringArray (*devnames)();
create = (PSoundChannel *(*)())dlsym(handle,
"plugin_create_sndout");
devnames = (PStringArray (*)())dlsym(handle,
"plugin_getdevices_sndout");
if((create == NULL)
|| (devnames == NULL))
{
s << "dlerror=" << dlerror() << "\n";
goto wrong;
}
plugin->create_sndout = create;
plugin->devnames_sndout = devnames;
}
else
{
plugin->create_sndout = NULL;
plugin->devnames_sndout = NULL;
}
// finally, since we got all we wanted, we just add it to the list!
mutex.Wait();
plugin->next = plugins_list;
plugins_list = plugin;
mutex.Signal();
s << "success";
PTrace::End(s);
return TRUE;
wrong:
free(plugin);
(void)dlclose(handle);
s << PTrace::End(s);
return FALSE;
}
PVideoInputDevice*
PDeviceManager::GetVideoInputDevice(PString name)
{
mutex.Wait();
struct device_plugin *ptr=plugins_list;
mutex.Signal();
for(;
ptr != NULL;
ptr = ptr->next)
{
if((ptr->type & VIDIN) && strcmp(name, ptr->name) == 0)
return ptr->create_vidin();
}
return NULL;
}
PVideoOutputDevice*
PDeviceManager::GetVideoOutputDevice(PString name)
{
mutex.Wait();
struct device_plugin *ptr=plugins_list;
mutex.Signal();
for(;
ptr != NULL;
ptr = ptr->next)
{
if((ptr->type & VIDOUT) && strcmp(name, ptr->name) == 0)
return ptr->create_vidout();
}
return NULL;
}
PVideoInputDevice*
PDeviceManager::GetOpenedVideoInputDevice(PString devName, BOOL flag)
{
char driver[DRIVERNAMELEN];
mutex.Wait();
if(plugins_list == NULL)
{
mutex.Signal();
LoadAllPlugins();
}
else
mutex.Signal();
if(sscanf(devName, "%s", driver) == 1)
{ // looks like a nice devName
PString filename = devName.Right(strlen(devName)-strlen(driver)-1);
// FIXME! this computation is awful!
PVideoInputDevice *dev = GetVideoInputDevice(driver);
if(dev != NULL && dev->Open(filename, flag))
return dev;
if(dev != NULL)
delete dev;
return NULL;
}
// doesn't look like a nice devName
// (that can be a user on CLI, who wants us to open /dev/video3.14)
// FIXME: there is a nicer solution to implement that,
// but my pattern-matching abilities are quite small,
// as the previous fixme must have proven: search through the list of
// devices names we get from GetInputDeviceNames, and only ask to those
// drivers that claimed they could handle devName.
mutex.Wait();
struct device_plugin *ptr=plugins_list;
mutex.Signal();
for(;
ptr != NULL;
ptr = ptr->next)
{
if(ptr->type & VIDIN)
{
PVideoInputDevice *dev=ptr->create_vidin();
if(dev != NULL && dev->Open(devName, flag))
return dev;
if(dev != NULL)
delete dev;
}
}
return NULL;
}
PVideoOutputDevice*
PDeviceManager::GetOpenedVideoOutputDevice(PString devName, BOOL flag)
{
char driver[DRIVERNAMELEN];
mutex.Wait();
if(plugins_list == NULL)
{
mutex.Signal();
LoadAllPlugins();
}
else
mutex.Signal();
if(sscanf(devName, "%s", driver) == 1)
{ // looks like a nice devName
PString filename = devName.Right(strlen(devName)-strlen(driver)-1);
// FIXME! this computation is awful!
PVideoOutputDevice *dev = GetVideoOutputDevice(driver);
if(dev != NULL && dev->Open(filename, flag))
return dev;
if(dev != NULL)
delete dev;
}
// doesn't look like a nice devName
// (that can be a user on CLI, who wants us to open /dev/video3.14)
// FIXME: there is a nicer solution to implement that,
// but my pattern-matching abilities are quite small,
// as the previous fixme must have proven: search through the list of
// devices names we get from GetInputDeviceNames, and only ask to those
// drivers that claimed they could handle devName.
mutex.Wait();
struct device_plugin *ptr=plugins_list;
mutex.Signal();
for(;
ptr != NULL;
ptr = ptr->next)
{
if(ptr->type & VIDOUT)
{
PVideoOutputDevice *dev=ptr->create_vidout();
if(dev != NULL && dev->Open(devName, flag))
return dev;
if(dev != NULL)
delete dev;
}
}
return NULL;
}
PSoundChannel*
PDeviceManager::GetSoundDevice(PString name, Direction dir)
{
mutex.Wait();
struct device_plugin *ptr=plugins_list;
mutex.Signal();
for(;
ptr != NULL;
ptr = ptr->next)
{
if(dir == Input && ptr->type & SNDIN && strcmp(name, ptr->name) == 0)
return ptr->create_sndin();
if(dir == Output && ptr->type & SNDOUT && strcmp(name, ptr->name) == 0)
return ptr->create_sndout();
}
return NULL;
}
PSoundChannel*
PDeviceManager::GetOpenedSoundDevice(PString devName,
Direction dir,
unsigned numChannels,
unsigned sampleRate,
unsigned bitsPerSample)
{
char driver[DRIVERNAMELEN];
mutex.Wait();
if(plugins_list == NULL)
{
mutex.Signal();
LoadAllPlugins();
}
else
mutex.Signal();
ostream & s = PTrace::Begin(0, "GetOpenedSoundDevice: ", 0);
s << "Opening: " << devName << "\n";
if(sscanf(devName, "%s", driver) == 1)
{ // looks like a nice devName
PString filename = devName.Right(strlen(devName)-strlen(driver)-1);
// FIXME! this computation is awful!
s << "Driver: " << driver << " File: " << filename << '\n';
PSoundChannel *dev = GetSoundDevice(driver, dir);
if(dev != NULL && dev->Open(filename, to_pscdir(dir), numChannels,
sampleRate, bitsPerSample))
{
s << "success!\n";
PTrace::End(s);
return dev;
}
if(dev != NULL)
delete dev;
}
// doesn't look like a nice devName
// (that can be a user on CLI, who wants us to open /dev/video3.14)
// FIXME: there is a nicer solution to implement that,
// but my pattern-matching abilities are quite small,
// as the previous fixme must have proven: search through the list of
// devices names we get from GetInputDeviceNames, and only ask to those
// drivers that claimed they could handle devName.
s << "fallback\n";
mutex.Wait();
struct device_plugin *ptr=plugins_list;
mutex.Signal();
for(;
ptr != NULL;
ptr = ptr->next)
{
PSoundChannel *dev;
if(dir == Input && ptr->type & SNDIN)
dev = ptr->create_sndin();
else if(dir == Output && ptr->type & SNDOUT)
dev = ptr->create_sndout();
else
dev = NULL;
if(dev != NULL && dev->Open(devName, to_pscdir(dir), numChannels,
sampleRate, bitsPerSample))
return dev;
if(dev != NULL)
delete dev;
}
return NULL;
}
PStringList
PDeviceManager::GetVideoDeviceNames(Direction dir)
{
mutex.Wait();
if(plugins_list == NULL)
{
mutex.Signal();
LoadAllPlugins();
}
else
mutex.Signal();
// we get through all the plugin lists, and add the name as a prefix,
// to be able to track down which takes care of what
PStringList Result;
mutex.Wait();
struct device_plugin *ptr = plugins_list;
mutex.Signal();
for(;
ptr != NULL;
ptr=ptr->next)
{
PStringList tmplist;
if(dir == Input && ptr->type & VIDIN)
tmplist = ptr->devnames_vidin();
else if(dir == Output && ptr->type & VIDOUT)
tmplist = ptr->devnames_vidout();
for (PINDEX i = 0; i < tmplist.GetSize(); i++)
{
Result.AppendString((PString)ptr->name+" "+tmplist[i]);
}
}
return Result;
}
PStringArray
PDeviceManager::GetSoundDeviceNames(Direction dir)
{
mutex.Wait();
if(plugins_list == NULL)
{
mutex.Signal();
LoadAllPlugins();
}
else
mutex.Signal();
// we get through all the plugin lists, and add the name as a prefix,
// to be able to track down which takes care of what
PStringList Result;
mutex.Wait();
struct device_plugin *ptr = plugins_list;
mutex.Signal();
for(;
ptr != NULL;
ptr=ptr->next)
{
PStringList tmplist;
if(dir == Input && ptr->type & SNDIN)
tmplist = PStringList::PStringList(ptr->devnames_sndin());
else if(dir == Output && ptr->type & SNDOUT)
tmplist = PStringList::PStringList(ptr->devnames_sndout());
for (PINDEX i = 0; i < tmplist.GetSize(); i++)
{
Result.AppendString((PString)ptr->name+" "+tmplist[i]);
}
}
return PStringArray::PStringArray(Result);
}
PSoundChannel::Directions
to_pscdir(PDeviceManager::Direction dir)
{
if(dir == PDeviceManager::Output)
return PSoundChannel::Player;
else
return PSoundChannel::Recorder;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]