Commit c35159a6 authored by Emmanuel Milou's avatar Emmanuel Milou

Codecs dynamic loadind improvment

At startup, the installation directory is scanned and the available shared library
(codecs) are loaded in memory.
parent aee25941
......@@ -30,40 +30,21 @@
AudioFile::AudioFile()
: AudioLoop()
{
// could vary later...
// could vary later ...
_start = false;
using std::cout;
using std::cerr;
void* codec = dlopen( CODECS_DIR "/libcodec_ulaw.so", RTLD_LAZY);
if(!codec){
cerr<<"cannot load library: "<< dlerror() <<'\n';
}
dlerror();
create_t* create_codec = (create_t*)dlsym(codec, "create");
const char* dlsym_error = dlerror();
if(dlsym_error){
cerr << "Cannot load symbol create: " << dlsym_error << '\n';
}
destroy_t* destroy_codec = (destroy_t*) dlsym(codec, "destroy");
dlsym_error = dlerror();
if(dlsym_error){
cerr << "Cannot load symbol destroy" << dlsym_error << '\n';
}
_ulaw = create_codec();
}
AudioFile::~AudioFile()
{
delete _ulaw;
delete _codec;
}
// load file in mono format
bool
AudioFile::loadFile(const std::string& filename, unsigned int sampleRate=8000)
AudioFile::loadFile(const std::string& filename, AudioCodec* codec , unsigned int sampleRate=8000)
{
_codec = codec;
// if the filename was already load, with the same samplerate
// we do nothing
if (_filename == filename && _sampleRate == sampleRate) {
......@@ -106,7 +87,7 @@ AudioFile::loadFile(const std::string& filename, unsigned int sampleRate=8000)
// expandedsize is the number of bytes, not the number of int
// expandedsize should be exactly two time more, else failed
int16 monoBuffer[length];
unsigned int expandedsize = _ulaw->codecDecode (monoBuffer, (unsigned char *) fileBuffer, length);
unsigned int expandedsize = _codec->codecDecode (monoBuffer, (unsigned char *) fileBuffer, length);
if (expandedsize != length*2) {
_debug("Audio file error on loading audio file!");
return false;
......
......@@ -25,6 +25,7 @@
#include "audioloop.h"
#include "codecs/audiocodec.h"
#include "codecDescriptor.h"
/**
@author Yan Morin <yan.morin@savoirfairelinux.com>
......@@ -35,14 +36,14 @@ public:
AudioFile();
~AudioFile();
bool loadFile(const std::string& filename, unsigned int sampleRate/*=8000*/);
bool loadFile(const std::string& filename, AudioCodec *codec , unsigned int sampleRate/*=8000*/);
void start() { _start = true; }
void stop() { _start = false; }
bool isStarted() { return _start; }
private:
std::string _filename;
AudioCodec* _ulaw;
AudioCodec* _codec;
bool _start;
};
......
......@@ -43,6 +43,8 @@ public:
void reset() { _pos = 0; }
unsigned int getMonoSize() { return _size; }
unsigned int getSize() { return _size; }
protected:
SFLDataFormat* _buffer;
......
This diff is collapsed.
......@@ -122,23 +122,22 @@ class AudioRtpRTX : public ost::Thread, public ost::TimerPort {
int downSampleData(int, int);
/** Pointer on function to handle codecs **/
void* handle_codec;
//void* handle_codec;
AudioCodec* _audiocodec;
CodecDescriptor _codecDesc;
/**
* Load dynamically a codec (.so library)
* @param payload The payload of the codec you want to load
* @return AudioCodec* A pointer on a audio codec object
*/
void loadCodec(int payload);
//void loadCodec(int payload);
/**
* Destroy and close dynamically a codec (.so library)
* @param audiocodec The audio codec you want to unload
*/
void unloadCodec(void);
//void unloadCodec(void);
};
///////////////////////////////////////////////////////////////////////////////
......
......@@ -26,44 +26,80 @@
CodecDescriptor::CodecDescriptor()
{
init();
//#ifdef HAVE_SPEEX
//init();
//#ifdef HAVE_SPEEX
//_codecMap[PAYLOAD_CODEC_SPEEX] = new CodecSpeex(PAYLOAD_CODEC_SPEEX); // TODO: this is a variable payload!
//#endif
//#endif
}
void
CodecDescriptor::~CodecDescriptor()
{
}
void
CodecDescriptor::deleteHandlePointer( void )
{
_debug("Destroy codecs handles\n");
int i;
for( i = 0 ; i < _CodecInMemory.size() ; i++)
{
unloadCodec( _CodecInMemory[i] );
}
}
void
CodecDescriptor::init()
{
// init list of all codecs supported codecs
_codecMap[PAYLOAD_CODEC_ULAW] = "PCMU";
_codecMap[PAYLOAD_CODEC_GSM] = "GSM";
_codecMap[PAYLOAD_CODEC_ALAW] = "PCMA";
//_codecMap[PAYLOAD_CODEC_ILBC_20] = "iLBC";
_codecMap[PAYLOAD_CODEC_SPEEX_8000] = "speex";;
_debug("Scanning %s to find audio codecs....\n", CODECS_DIR);
std::vector<AudioCodec*> CodecDynamicList = scanCodecDirectory();
_nbCodecs = CodecDynamicList.size();
if( _nbCodecs <= 0 ){
_debug("Error - No codecs available in directory %s\n", CODECS_DIR);
exit(0);
}
int i;
for( i = 0 ; i < _nbCodecs ; i++ ) {
_CodecsMap[(CodecType)CodecDynamicList[i]->getPayload()] = CodecDynamicList[i];
_debug("Dynamic codec = %s\n" , CodecDynamicList[i]->getCodecName().c_str());
}
}
void
void
CodecDescriptor::setDefaultOrder()
{
_codecOrder.clear();
_codecOrder.push_back(PAYLOAD_CODEC_ULAW);
_codecOrder.push_back(PAYLOAD_CODEC_ALAW);
_codecOrder.push_back(PAYLOAD_CODEC_GSM);
CodecsMap::iterator iter = _CodecsMap.begin();
while( iter != _CodecsMap.end())
{
_codecOrder.push_back(iter->first);
iter->second->setState( true );
}
}
std::string&
std::string
CodecDescriptor::getCodecName(CodecType payload)
{
CodecMap::iterator iter = _codecMap.find(payload);
if (iter!=_codecMap.end()) {
std::string resNull = "";
CodecsMap::iterator iter = _CodecsMap.find(payload);
if (iter!=_CodecsMap.end()) {
return (iter->second->getCodecName());
}
return resNull;
}
AudioCodec*
CodecDescriptor::getCodec(CodecType payload)
{
CodecsMap::iterator iter = _CodecsMap.find(payload);
if (iter!=_CodecsMap.end()) {
return (iter->second);
}
//return std::string("");
return NULL;
}
bool
bool
CodecDescriptor::isActive(CodecType payload)
{
int i;
......@@ -75,94 +111,67 @@ CodecDescriptor::isActive(CodecType payload)
return false;
}
void
void
CodecDescriptor::removeCodec(CodecType payload)
{
CodecMap::iterator iter = _codecMap.begin();
while(iter!=_codecMap.end()) {
if (iter->first == payload) {
_debug("Codec %s removed from the list", getCodecName(payload).data());
_codecMap.erase(iter);
break;
}
if (iter->first == payload) {
_debug("Codec %s removed from the list", getCodecName(payload).data());
_codecMap.erase(iter);
break;
}
iter++;
}
}
void
void
CodecDescriptor::addCodec(CodecType payload)
{
}
double
double
CodecDescriptor::getBitRate(CodecType payload)
{
switch(payload){
case PAYLOAD_CODEC_ULAW:
return 64;
case PAYLOAD_CODEC_ALAW:
return 64;
case PAYLOAD_CODEC_GSM:
return 13.3;
case PAYLOAD_CODEC_ILBC_20:
return 15.2;
case PAYLOAD_CODEC_ILBC_30:
return 13.3;
}
return 0.0;
CodecsMap::iterator iter = _CodecsMap.find(payload);
if (iter!=_CodecsMap.end())
return (iter->second->getBitRate());
else
return 0.0;
}
double
double
CodecDescriptor::getBandwidthPerCall(CodecType payload)
{
switch(payload){
case PAYLOAD_CODEC_ULAW:
return 80;
case PAYLOAD_CODEC_ALAW:
return 80;
case PAYLOAD_CODEC_GSM:
return 28.6;
case PAYLOAD_CODEC_ILBC_20:
return 30.8;
}
return 0.0;
CodecsMap::iterator iter = _CodecsMap.find(payload);
if (iter!=_CodecsMap.end())
return (iter->second->getBandwidth());
else
return 0.0;
}
int
int
CodecDescriptor::getSampleRate(CodecType payload)
{
switch(payload){
case PAYLOAD_CODEC_ULAW:
printf("PAYLOAD = %i\n", payload);
return 8000;
case PAYLOAD_CODEC_ALAW:
printf("PAYLOAD = %i\n", payload);
return 8000;
case PAYLOAD_CODEC_GSM:
printf("PAYLOAD = %i\n", payload);
return 8000;
case PAYLOAD_CODEC_ILBC_20:
printf("PAYLOAD = %i\n", payload);
return 8000;
case PAYLOAD_CODEC_SPEEX_8000:
printf("PAYLOAD = %i\n", payload);
return 8000;
case PAYLOAD_CODEC_SPEEX_16000:
printf("PAYLOAD = %i\n", payload);
return 16000;
case PAYLOAD_CODEC_SPEEX_32000:
printf("PAYLOAD = %i\n", payload);
return 32000;
default:
return -1;
}
return -1;
CodecsMap::iterator iter = _CodecsMap.find(payload);
if (iter!=_CodecsMap.end())
return (iter->second->getClockRate());
else
return 0;
}
int
CodecDescriptor::getChannel(CodecType payload)
{
CodecsMap::iterator iter = _CodecsMap.find(payload);
if (iter!=_CodecsMap.end())
return (iter->second->getChannel());
else
return 0;
}
void
void
CodecDescriptor::saveActiveCodecs(const std::vector<std::string>& list)
{
_codecOrder.clear();
......@@ -171,12 +180,92 @@ CodecDescriptor::saveActiveCodecs(const std::vector<std::string>& list)
int i=0;
int payload;
size_t size = list.size();
while(i<size)
while( i < size )
{
payload = std::atoi(list[i].data());
_codecOrder.push_back((CodecType)payload);
_CodecsMap.find((CodecType)payload)->second->setState( true );
i++;
}
}
std::vector<AudioCodec*>
CodecDescriptor::scanCodecDirectory( void )
{
std::vector<AudioCodec*> codecs;
std::string tmp;
std::string codecDir = CODECS_DIR;
codecDir.append("/");
std::string current = ".";
std::string previous = "..";
DIR *dir = opendir( codecDir.c_str() );
AudioCodec* audioCodec;
if( dir ){
dirent *dirStruct;
while( dirStruct = readdir( dir )) {
tmp = dirStruct -> d_name ;
if( tmp == current || tmp == previous){}
else{
_debug("Codec : %s\n", tmp.c_str());
audioCodec = loadCodec( codecDir.append(tmp) );
codecs.push_back( audioCodec );
codecDir = CODECS_DIR;
codecDir.append("/");
}
}
}
closedir( dir );
return codecs;
}
/*CodecDescriptor::getDescription( std::string fileName )
{
int pos = fileName.length() - 12 ;
return fileName.substr(9, pos);
}
*/
AudioCodec*
CodecDescriptor::loadCodec( std::string path )
{
_debug("Load path %s\n", path.c_str());
CodecHandlePointer p;
using std::cerr;
void * codecHandle = dlopen( path.c_str() , RTLD_LAZY );
if( !codecHandle )
cerr << dlerror() << '\n';
dlerror();
create_t* createCodec = (create_t*)dlsym( codecHandle , "create" );
if( dlerror() )
cerr << dlerror() << '\n';
AudioCodec* a = createCodec();
p = CodecHandlePointer( a, codecHandle );
//_debug("Add %s in the list.\n" , a->getCodecName().c_str());
_CodecInMemory.push_back(p);
return a;
}
void
CodecDescriptor::unloadCodec( CodecHandlePointer p )
{
// _debug("Unload codec %s\n", p.first->getCodecName().c_str());
using std::cerr;
int i;
destroy_t* destroyCodec = (destroy_t*)dlsym( p.second , "destroy");
if(dlerror())
cerr << dlerror() << '\n';
destroyCodec(p.first);
dlclose(p.second);
}
AudioCodec*
CodecDescriptor::getFirstCodecAvailable( void )
{
CodecsMap::iterator iter = _CodecsMap.begin();
if( iter != _CodecsMap.end())
return iter->second;
else
return NULL;
}
......@@ -26,8 +26,12 @@
#include <string>
#include <map>
#include <vector>
// To read directories content
#include <dirent.h>
#include "../global.h"
#include "codecs/audiocodec.h"
typedef enum {
// http://www.iana.org/assignments/rtp-parameters
// http://www.gnu.org/software/ccrtp/doc/refman/html/formats_8h.html#a0
......@@ -57,23 +61,38 @@ typedef std::map<CodecType, std::string> CodecMap;
/* The struct to reflect the order the user wants to use the codecs */
typedef std::vector<CodecType> CodecOrder;
typedef std::pair<AudioCodec* , void*> CodecHandlePointer;
typedef std::map<CodecType , AudioCodec*> CodecsMap;
class CodecDescriptor {
public:
/**
* Initialize all codec
*/
CodecDescriptor();
~CodecDescriptor() {};
~CodecDescriptor();
/*
* Accessor to data structures
*/
CodecMap& getCodecMap() { return _codecMap; }
CodecsMap& getCodecsMap() { return _CodecsMap; }
CodecOrder& getActiveCodecs() { return _codecOrder; }
/**
* Get codec with is associated payload
* @param payload the payload associated with the payload
* Get codec name by its payload
* @param payload the payload looked for
* same as getPayload()
* @return the name of the codec
*/
std::string& getCodecName(CodecType payload);
std::string getCodecName(CodecType payload);
/*
* Get the codec object associated with the payload
* @param payload The payload looked for
* @return AudioCodec* A pointer on a AudioCodec object
*/
AudioCodec* getCodec( CodecType payload );
/**
* Initialiaze the map with all the supported codecs, even those inactive
......@@ -129,15 +148,85 @@ public:
*/
int getSampleRate(CodecType payload);
/*
* Get the number of channels
* @param payload The payload of the codec
* @return int Number of channels
*/
int getChannel(CodecType payload);
/**
* Set the order of codecs by their payload
* @param list The ordered list sent by DBus
*/
void saveActiveCodecs(const std::vector<std::string>& list);
void saveActiveCodecs(const std::vector<std::string>& list);
std::string getDescription( std::string );
/*
* Get the number of codecs loaded in dynamic memory
*/
int getCodecsNumber( void ) { return _nbCodecs; }
/*
* Unreferences the codecs loaded in memory
*/
void deleteHandlePointer( void );
/*
* Get the first element of the CodecsMap struct.
* i.e the one with the lowest payload
* @return AudioCodec The pointer on the codec object
*/
AudioCodec* getFirstCodecAvailable( void );
private:
/*
* Scan the installation directory ( --prefix configure option )
* And load the dynamic library
* @return std::vector<AudioCodec*> The list of the codec object successfully loaded in memory
*/
std::vector<AudioCodec *> scanCodecDirectory( void );
/*
* Load a codec
* @param std::string The path of the shared ( dynamic ) library.
* @return AudioCodec* the pointer of the object loaded.
*/
AudioCodec* loadCodec( std::string );
/*
* Unload a codec
* @param CodecHandlePointer The map containing the pointer on the object and the pointer on the handle function
*/
void unloadCodec( CodecHandlePointer );
/*
* Map the payload of a codec and its name
*/
CodecMap _codecMap;
/*
* Map the payload of a codec and the object associated
*/
CodecsMap _CodecsMap;
/*
* Vector containing the order of the codecs
*/
CodecOrder _codecOrder;
/*
* Number of codecs loaded
*/
int _nbCodecs;
/*
* Vector containing pairs
* Pair between pointer on function handle and pointer on audiocodec object
*/
std::vector< CodecHandlePointer > _CodecInMemory;
};
#endif // __CODEC_DESCRIPTOR_H__
......@@ -19,6 +19,9 @@ protected:
private:
int _payload;
bool _hasDynamicPayload;
bool _state;
double _bitrate;
double _bandwidth;
public:
AudioCodec(int payload, const std::string &codecName)
......@@ -28,7 +31,7 @@ public:
_channel = 1; // default
_hasDynamicPayload = (_payload >= 96 && _payload <= 127) ? true : false;
_state = true;
}
virtual ~AudioCodec() {
......@@ -41,12 +44,15 @@ public:
/** Value used for SDP negotiation */
std::string getCodecName() { return _codecName; }
int getPayload() { return _payload; }
bool hasDynamicPayload() { return _hasDynamicPayload; }
unsigned int getClockRate() { return _clockRate; }
unsigned int getChannel() { return _channel; }
std::string getCodecName( void ) { return _codecName; }
int getPayload( void ) { return _payload; }
bool hasDynamicPayload( void ) { return _hasDynamicPayload; }
unsigned int getClockRate( void ) { return _clockRate; }
unsigned int getChannel( void ) { return _channel; }
bool getState( void ) { return _state; }
void setState(bool b) { _state = b; }