1 /*
2 * Copyright (C) 2002-2003 Fhg Fokus
3 * Copyright (C) 2006 iptego GmbH
4 *
5 * This file is part of SEMS, a free SIP media server.
6 *
7 * SEMS is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version. This program is released under
11 * the GPL with the additional exemption that compiling, linking,
12 * and/or using OpenSSL is allowed.
13 *
14 * For a license to use the SEMS software under conditions
15 * other than those described here, or to purchase support for this
16 * software, please contact iptel.org by e-mail at the following addresses:
17 * info@iptel.org
18 *
19 * SEMS is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 */
28
29 #include "AmPlugIn.h"
30 #include "AmConfig.h"
31 #include "AmApi.h"
32 #include "AmUtils.h"
33 //#include "AmSdp.h"
34 #include "AmSipDispatcher.h"
35 //#include "AmServer.h"
36
37 #include "amci/amci.h"
38 #include "amci/codecs.h"
39 #include "log.h"
40
41 #include <sys/types.h>
42 #include <dirent.h>
43 #include <dlfcn.h>
44 #include <string.h>
45 #include <errno.h>
46 #include <libgen.h>
47
48 #include <set>
49 #include <vector>
50 #include <algorithm>
51 using std::set;
52
pcm16_bytes2samples(long h_codec,unsigned int num_bytes)53 static unsigned int pcm16_bytes2samples(long h_codec, unsigned int num_bytes)
54 {
55 return num_bytes / 2;
56 }
57
pcm16_samples2bytes(long h_codec,unsigned int num_samples)58 static unsigned int pcm16_samples2bytes(long h_codec, unsigned int num_samples)
59 {
60 return num_samples * 2;
61 }
62
tevent_bytes2samples(long h_codec,unsigned int num_bytes)63 static unsigned int tevent_bytes2samples(long h_codec, unsigned int num_bytes)
64 {
65 return num_bytes;
66 }
67
tevent_samples2bytes(long h_codec,unsigned int num_samples)68 static unsigned int tevent_samples2bytes(long h_codec, unsigned int num_samples)
69 {
70 return num_samples;
71 }
72
73 amci_codec_t _codec_pcm16 = {
74 CODEC_PCM16,
75 NULL,
76 NULL,
77 NULL,
78 NULL,
79 NULL,
80 pcm16_bytes2samples,
81 pcm16_samples2bytes,
82 NULL
83 };
84
85 amci_codec_t _codec_tevent = {
86 CODEC_TELEPHONE_EVENT,
87 NULL,
88 NULL,
89 NULL,
90 NULL,
91 NULL,
92 tevent_bytes2samples,
93 tevent_samples2bytes,
94 NULL
95 };
96
97 amci_payload_t _payload_tevent = {
98 -1,
99 "telephone-event",
100 8000, // telephone-event has always SR 8000
101 8000,
102 -1,
103 CODEC_TELEPHONE_EVENT,
104 -1
105 };
106
107 AmPlugIn* AmPlugIn::_instance=0;
108
AmPlugIn()109 AmPlugIn::AmPlugIn()
110 : dynamic_pl(DYNAMIC_PAYLOAD_TYPE_START)
111 //ctrlIface(NULL)
112 {
113 }
114
115
delete_plugin_factory(std::pair<string,AmPluginFactory * > pf)116 static void delete_plugin_factory(std::pair<string, AmPluginFactory*> pf)
117 {
118 DBG("decreasing reference to plug-in factory: %s\n", pf.first.c_str());
119 dec_ref(pf.second);
120
121 }
122
~AmPlugIn()123 AmPlugIn::~AmPlugIn()
124 {
125 std::for_each(module_objects.begin(), module_objects.end(), delete_plugin_factory);
126 std::for_each(name2seh.begin(), name2seh.end(), delete_plugin_factory);
127 std::for_each(name2base.begin(), name2base.end(), delete_plugin_factory);
128 std::for_each(name2di.begin(), name2di.end(), delete_plugin_factory);
129 std::for_each(name2logfac.begin(), name2logfac.end(), delete_plugin_factory);
130
131 // if _DEBUG is set do not unload shared libs to allow better debugging
132 #ifndef _DEBUG
133 for(vector<void*>::iterator it=dlls.begin();it!=dlls.end();++it)
134 dlclose(*it);
135 #endif
136 }
137
dispose()138 void AmPlugIn::dispose()
139 {
140 if (_instance) {
141 delete _instance;
142 }
143 }
144
instance()145 AmPlugIn* AmPlugIn::instance()
146 {
147 if(!_instance)
148 _instance = new AmPlugIn();
149
150 return _instance;
151 }
152
init()153 void AmPlugIn::init() {
154 vector<string> excluded_payloads_v =
155 explode(AmConfig::ExcludePayloads, ";");
156 for (vector<string>::iterator it =
157 excluded_payloads_v.begin();
158 it != excluded_payloads_v.end();it++)
159 excluded_payloads.insert(*it);
160
161 DBG("adding built-in codecs...\n");
162 addCodec(&_codec_pcm16);
163 addCodec(&_codec_tevent);
164 addPayload(&_payload_tevent);
165 }
166
load(const string & directory,const string & plugins)167 int AmPlugIn::load(const string& directory, const string& plugins)
168 {
169 int err=0;
170
171 vector<AmPluginFactory*> loaded_plugins;
172
173 if (!plugins.length()) {
174 INFO("AmPlugIn: loading modules in directory '%s':\n", directory.c_str());
175
176 DIR* dir = opendir(directory.c_str());
177 if (!dir){
178 ERROR("while opening plug-in directory (%s): %s\n",
179 directory.c_str(), strerror(errno));
180 return -1;
181 }
182
183 vector<string> excluded_plugins = explode(AmConfig::ExcludePlugins, ";");
184 set<string> excluded_plugins_s;
185 for (vector<string>::iterator it = excluded_plugins.begin();
186 it != excluded_plugins.end();it++)
187 excluded_plugins_s.insert(*it);
188
189 struct dirent* entry;
190
191 while( ((entry = readdir(dir)) != NULL) && (err == 0) ){
192 string plugin_name = string(entry->d_name);
193
194 if(plugin_name.find(".so",plugin_name.length()-3) == string::npos ){
195 continue;
196 }
197
198 if (excluded_plugins_s.find(plugin_name.substr(0, plugin_name.length()-3))
199 != excluded_plugins_s.end()) {
200 DBG("skipping excluded plugin %s\n", plugin_name.c_str());
201 continue;
202 }
203
204 string plugin_file = directory + "/" + plugin_name;
205
206 DBG("loading %s ...\n",plugin_file.c_str());
207 if( (err = loadPlugIn(plugin_file, plugin_name, loaded_plugins)) < 0 ) {
208 ERROR("while loading plug-in '%s'\n",plugin_file.c_str());
209 return -1;
210 }
211 }
212
213 closedir(dir);
214 }
215 else {
216 INFO("AmPlugIn: loading modules: '%s'\n", plugins.c_str());
217
218 vector<string> plugins_list = explode(plugins, ";");
219 for (vector<string>::iterator it = plugins_list.begin();
220 it != plugins_list.end(); it++) {
221 string plugin_file = *it;
222 if (plugin_file == "sipctrl") {
223 WARN("sipctrl is integrated into the core, loading sipctrl "
224 "module is not necessary any more\n");
225 WARN("please update your configuration to not load sipctrl module\n");
226 continue;
227 }
228
229 if(plugin_file.find(".so",plugin_file.length()-3) == string::npos )
230 plugin_file+=".so";
231
232 plugin_file = directory + "/" + plugin_file;
233 DBG("loading %s...\n",plugin_file.c_str());
234 if( (err = loadPlugIn(plugin_file, plugin_file, loaded_plugins)) < 0 ) {
235 ERROR("while loading plug-in '%s'\n",plugin_file.c_str());
236 // be strict here: if plugin not loaded, stop!
237 return err;
238 }
239 }
240 }
241
242 DBG("AmPlugIn: modules loaded.\n");
243 DBG("Initializing %zd plugins...\n", loaded_plugins.size());
244 for (vector<AmPluginFactory*>::iterator it =
245 loaded_plugins.begin(); it != loaded_plugins.end(); it++) {
246 int err = (*it)->onLoad();
247 if(err)
248 return err;
249 }
250
251 return 0;
252 }
253
registerLoggingPlugins()254 void AmPlugIn::registerLoggingPlugins() {
255 // init logging facilities
256 for(std::map<std::string,AmLoggingFacility*>::iterator it = name2logfac.begin();
257 it != name2logfac.end(); it++){
258 // register for receiving logging messages
259 register_log_hook(it->second);
260 }
261 }
262
set_load_rtld_global(const string & plugin_name)263 void AmPlugIn::set_load_rtld_global(const string& plugin_name) {
264 rtld_global_plugins.insert(plugin_name);
265 }
266
loadPlugIn(const string & file,const string & plugin_name,vector<AmPluginFactory * > & plugins)267 int AmPlugIn::loadPlugIn(const string& file, const string& plugin_name,
268 vector<AmPluginFactory*>& plugins)
269 {
270 AmPluginFactory* plugin = NULL; // default: not loaded
271 int dlopen_flags = RTLD_NOW;
272
273 char* pname = strdup(plugin_name.c_str());
274 char* bname = basename(pname);
275
276 // dsm, ivr and py_sems need RTLD_GLOBAL
277 if (!strcmp(bname, "dsm.so") || !strcmp(bname, "ivr.so") ||
278 !strcmp(bname, "py_sems.so") || !strcmp(bname, "sbc.so") ||
279 !strcmp(bname, "diameter_client.so") || !strcmp(bname, "registrar_client.so") ||
280 !strcmp(bname, "uac_auth.so") || !strcmp(bname, "msg_storage.so")
281 ) {
282 dlopen_flags = RTLD_NOW | RTLD_GLOBAL;
283 DBG("using RTLD_NOW | RTLD_GLOBAL to dlopen '%s'\n", file.c_str());
284 }
285
286 // possibly others
287 for (std::set<string>::iterator it=rtld_global_plugins.begin();
288 it!=rtld_global_plugins.end();it++) {
289 if (!strcmp(bname, it->c_str())) {
290 dlopen_flags = RTLD_NOW | RTLD_GLOBAL;
291 DBG("using RTLD_NOW | RTLD_GLOBAL to dlopen '%s'\n", file.c_str());
292 break;
293 }
294 }
295 free(pname);
296
297 void* h_dl = dlopen(file.c_str(),dlopen_flags);
298
299 if(!h_dl){
300 ERROR("AmPlugIn::loadPlugIn: %s: %s\n",file.c_str(),dlerror());
301 return -1;
302 }
303
304 FactoryCreate fc = NULL;
305 amci_exports_t* exports = (amci_exports_t*)dlsym(h_dl,"amci_exports");
306
307 bool has_sym=false;
308 if(exports){
309 if(loadAudioPlugIn(exports))
310 goto error;
311 goto end;
312 }
313
314 if((fc = (FactoryCreate)dlsym(h_dl,FACTORY_SESSION_EXPORT_STR)) != NULL){
315 plugin = (AmPluginFactory*)fc();
316 if(loadAppPlugIn(plugin))
317 goto error;
318 has_sym=true;
319 if (NULL != plugin) plugins.push_back(plugin);
320 }
321 if((fc = (FactoryCreate)dlsym(h_dl,FACTORY_SESSION_EVENT_HANDLER_EXPORT_STR)) != NULL){
322 plugin = (AmPluginFactory*)fc();
323 if(loadSehPlugIn(plugin))
324 goto error;
325 has_sym=true;
326 if (NULL != plugin) plugins.push_back(plugin);
327 }
328 if((fc = (FactoryCreate)dlsym(h_dl,FACTORY_PLUGIN_EXPORT_STR)) != NULL){
329 plugin = (AmPluginFactory*)fc();
330 if(loadBasePlugIn(plugin))
331 goto error;
332 has_sym=true;
333 if (NULL != plugin) plugins.push_back(plugin);
334 }
335 if((fc = (FactoryCreate)dlsym(h_dl,FACTORY_PLUGIN_CLASS_EXPORT_STR)) != NULL){
336 plugin = (AmPluginFactory*)fc();
337 if(loadDiPlugIn(plugin))
338 goto error;
339 has_sym=true;
340 if (NULL != plugin) plugins.push_back(plugin);
341 }
342
343 if((fc = (FactoryCreate)dlsym(h_dl,FACTORY_LOG_FACILITY_EXPORT_STR)) != NULL){
344 plugin = (AmPluginFactory*)fc();
345 if(loadLogFacPlugIn(plugin))
346 goto error;
347 has_sym=true;
348 if (NULL != plugin) plugins.push_back(plugin);
349 }
350
351 if(!has_sym){
352 ERROR("Plugin type could not be detected (%s)(%s)\n",file.c_str(),dlerror());
353 goto error;
354 }
355
356 end:
357 dlls.push_back(h_dl);
358 return 0;
359
360 error:
361 dlclose(h_dl);
362 return -1;
363 }
364
365
fileFormat(const string & fmt_name,const string & ext)366 amci_inoutfmt_t* AmPlugIn::fileFormat(const string& fmt_name, const string& ext)
367 {
368 if(!fmt_name.empty()){
369
370 std::map<std::string,amci_inoutfmt_t*>::iterator it = file_formats.find(fmt_name);
371 if ((it != file_formats.end()) &&
372 (ext.empty() || (ext == it->second->ext)))
373 return it->second;
374 }
375 else if(!ext.empty()){
376
377 std::map<std::string,amci_inoutfmt_t*>::iterator it = file_formats.begin();
378 for(;it != file_formats.end();++it){
379 if(ext == it->second->ext)
380 return it->second;
381 }
382 }
383
384 return 0;
385 }
386
codec(int id)387 amci_codec_t* AmPlugIn::codec(int id)
388 {
389 std::map<int,amci_codec_t*>::const_iterator it = codecs.find(id);
390 if(it != codecs.end())
391 return it->second;
392
393 return 0;
394 }
395
payload(int payload_id) const396 amci_payload_t* AmPlugIn::payload(int payload_id) const
397 {
398 std::map<int,amci_payload_t*>::const_iterator it = payloads.find(payload_id);
399 if(it != payloads.end())
400 return it->second;
401
402 return 0;
403 }
404
getSdpFormatParameters(int codec_id,bool is_offer,const string & fmt_params_in)405 string AmPlugIn::getSdpFormatParameters(int codec_id, bool is_offer, const string& fmt_params_in) {
406 amci_codec_t* c = codec(codec_id);
407 if (NULL == c)
408 return ""; // empty for unsupported codec
409
410 if (NULL == c->negotiate_fmt)
411 return ""; // empty if codec doesn't know either
412
413 char out_fmt[256] = { '\0' };
414 if ((c->negotiate_fmt)(is_offer ? 1:0, fmt_params_in.c_str(), out_fmt, 256) >=0 )
415 return string(out_fmt);
416
417 return "";
418 }
419
getDynPayload(const string & name,int rate,int encoding_param) const420 int AmPlugIn::getDynPayload(const string& name, int rate, int encoding_param) const {
421 // find a dynamic payload by name/rate and encoding_param (channels, if > 0)
422 for(std::map<int, amci_payload_t*>::const_iterator pl_it = payloads.begin();
423 pl_it != payloads.end(); ++pl_it)
424 if( (!strcasecmp(name.c_str(),pl_it->second->name)
425 && (rate == pl_it->second->advertised_sample_rate)) ) {
426 if ((encoding_param > 0) && (pl_it->second->channels > 0) &&
427 (encoding_param != pl_it->second->channels))
428 continue;
429
430 return pl_it->first;
431 }
432 // not found
433 return -1;
434 }
435
436 /** return 0, or -1 in case of error. */
getPayloads(vector<SdpPayload> & pl_vec) const437 void AmPlugIn::getPayloads(vector<SdpPayload>& pl_vec) const
438 {
439 for (std::map<int,int>::const_iterator it = payload_order.begin(); it != payload_order.end(); ++it) {
440 std::map<int,amci_payload_t*>::const_iterator pl_it = payloads.find(it->second);
441 if(pl_it != payloads.end()){
442 // if channels==2 use that value; otherwise don't add channels param
443 pl_vec.push_back(SdpPayload(pl_it->first, pl_it->second->name, pl_it->second->advertised_sample_rate, pl_it->second->channels==2?2:0));
444 } else {
445 ERROR("Payload %d (from the payload_order map) was not found in payloads map!\n", it->second);
446 }
447 }
448 }
449
subtype(amci_inoutfmt_t * iofmt,int subtype)450 amci_subtype_t* AmPlugIn::subtype(amci_inoutfmt_t* iofmt, int subtype)
451 {
452 if(!iofmt)
453 return 0;
454
455 amci_subtype_t* st = iofmt->subtypes;
456 if(subtype<0) // default subtype wanted
457 return st;
458
459 for(;;st++){
460 if(!st || st->type<0) break;
461 if(st->type == subtype)
462 return st;
463 }
464
465 return 0;
466 }
467
subtype(amci_inoutfmt_t * iofmt,const string & subtype_name)468 amci_subtype_t* AmPlugIn::subtype(amci_inoutfmt_t* iofmt, const string& subtype_name) {
469 if(!iofmt)
470 return NULL;
471
472 DBG("looking for subtype '%s'\n", subtype_name.c_str());
473 amci_subtype_t* st = iofmt->subtypes;
474 if(subtype_name.empty()) // default subtype wanted
475 return st;
476
477 for(;;st++){
478 if(!st || st->type<0) break;
479 if(st->name == subtype_name) {
480 return st;
481 }
482 }
483 return NULL;
484 }
485
getFactory4App(const string & app_name)486 AmSessionFactory* AmPlugIn::getFactory4App(const string& app_name)
487 {
488 AmSessionFactory* res = NULL;
489
490 name2app_mut.lock();
491 std::map<std::string,AmSessionFactory*>::iterator it = name2app.find(app_name);
492 if(it != name2app.end())
493 res = it->second;
494 name2app_mut.unlock();
495
496 return res;
497 }
498
getFactory4Seh(const string & name)499 AmSessionEventHandlerFactory* AmPlugIn::getFactory4Seh(const string& name)
500 {
501 std::map<std::string,AmSessionEventHandlerFactory*>::iterator it = name2seh.find(name);
502 if(it != name2seh.end())
503 return it->second;
504 return 0;
505 }
506
getFactory4Di(const string & name)507 AmDynInvokeFactory* AmPlugIn::getFactory4Di(const string& name)
508 {
509 std::map<std::string,AmDynInvokeFactory*>::iterator it = name2di.find(name);
510 if(it != name2di.end())
511 return it->second;
512 return 0;
513 }
514
getFactory4LogFaclty(const string & name)515 AmLoggingFacility* AmPlugIn::getFactory4LogFaclty(const string& name)
516 {
517 std::map<std::string,AmLoggingFacility*>::iterator it = name2logfac.find(name);
518 if(it != name2logfac.end())
519 return it->second;
520 return 0;
521 }
522
loadAudioPlugIn(amci_exports_t * exports)523 int AmPlugIn::loadAudioPlugIn(amci_exports_t* exports)
524 {
525 if(!exports){
526 ERROR("audio plug-in doesn't contain any exports !\n");
527 return -1;
528 }
529
530 if (exports->module_load) {
531 if (exports->module_load(AmConfig::ModConfigPath.c_str()) < 0) {
532 ERROR("initializing audio plug-in!\n");
533 return -1;
534 }
535 }
536
537 for( amci_codec_t* c=exports->codecs;
538 c->id>=0; c++ ){
539
540 if(addCodec(c))
541 goto error;
542 }
543
544 for( amci_payload_t* p=exports->payloads;
545 p->name; p++ ){
546
547 if(addPayload(p))
548 goto error;
549 }
550
551 for(amci_inoutfmt_t* f = exports->file_formats;
552 f->name; f++ ){
553
554 if(addFileFormat(f))
555 goto error;
556 }
557
558 return 0;
559
560 error:
561 return -1;
562 }
563
564
loadAppPlugIn(AmPluginFactory * f)565 int AmPlugIn::loadAppPlugIn(AmPluginFactory* f)
566 {
567 AmSessionFactory* sf = dynamic_cast<AmSessionFactory*>(f);
568 if(!sf){
569 ERROR("invalid application plug-in!\n");
570 return -1;
571 }
572
573 name2app_mut.lock();
574
575 if(name2app.find(sf->getName()) != name2app.end()){
576 ERROR("application '%s' already loaded !\n",sf->getName().c_str());
577 name2app_mut.unlock();
578 return -1;
579 }
580
581 name2app.insert(std::make_pair(sf->getName(),sf));
582 DBG("application '%s' loaded.\n",sf->getName().c_str());
583
584 inc_ref(sf);
585 if(!module_objects.insert(std::make_pair(sf->getName(),sf)).second){
586 // insertion failed
587 dec_ref(sf);
588 }
589 name2app_mut.unlock();
590
591 return 0;
592
593 }
594
loadSehPlugIn(AmPluginFactory * f)595 int AmPlugIn::loadSehPlugIn(AmPluginFactory* f)
596 {
597 AmSessionEventHandlerFactory* sf = dynamic_cast<AmSessionEventHandlerFactory*>(f);
598 if(!sf){
599 ERROR("invalid session component plug-in!\n");
600 goto error;
601 }
602
603 if(name2seh.find(sf->getName()) != name2seh.end()){
604 ERROR("session component '%s' already loaded !\n",sf->getName().c_str());
605 goto error;
606 }
607
608 inc_ref(sf);
609 name2seh.insert(std::make_pair(sf->getName(),sf));
610 DBG("session component '%s' loaded.\n",sf->getName().c_str());
611
612 return 0;
613
614 error:
615 return -1;
616 }
617
loadBasePlugIn(AmPluginFactory * f)618 int AmPlugIn::loadBasePlugIn(AmPluginFactory* f)
619 {
620 inc_ref(f);
621 if(!name2base.insert(std::make_pair(f->getName(),f)).second){
622 // insertion failed
623 dec_ref(f);
624 }
625 return 0;
626 }
627
loadDiPlugIn(AmPluginFactory * f)628 int AmPlugIn::loadDiPlugIn(AmPluginFactory* f)
629 {
630 AmDynInvokeFactory* sf = dynamic_cast<AmDynInvokeFactory*>(f);
631 if(!sf){
632 ERROR("invalid component plug-in!\n");
633 goto error;
634 }
635
636 if(name2di.find(sf->getName()) != name2di.end()){
637 ERROR("component '%s' already loaded !\n",sf->getName().c_str());
638 goto error;
639 }
640
641 name2di.insert(std::make_pair(sf->getName(),sf));
642 DBG("component '%s' loaded.\n",sf->getName().c_str());
643
644 return 0;
645
646 error:
647 return -1;
648 }
649
loadLogFacPlugIn(AmPluginFactory * f)650 int AmPlugIn::loadLogFacPlugIn(AmPluginFactory* f)
651 {
652 AmLoggingFacility* sf = dynamic_cast<AmLoggingFacility*>(f);
653 if(!sf){
654 ERROR("invalid logging facility plug-in!\n");
655 goto error;
656 }
657
658 if(name2logfac.find(sf->getName()) != name2logfac.end()){
659 ERROR("logging facility '%s' already loaded !\n",
660 sf->getName().c_str());
661 goto error;
662 }
663
664 name2logfac.insert(std::make_pair(sf->getName(),sf));
665 DBG("logging facility component '%s' loaded.\n",sf->getName().c_str());
666
667 return 0;
668
669 error:
670 return -1;
671 }
672
addCodec(amci_codec_t * c)673 int AmPlugIn::addCodec(amci_codec_t* c)
674 {
675 if(codecs.find(c->id) != codecs.end()){
676 ERROR("codec id (%i) already supported\n",c->id);
677 return -1;
678 }
679 codecs.insert(std::make_pair(c->id,c));
680 DBG("codec id %i inserted\n",c->id);
681 return 0;
682 }
683
addPayload(amci_payload_t * p)684 int AmPlugIn::addPayload(amci_payload_t* p)
685 {
686 if (excluded_payloads.find(p->name) !=
687 excluded_payloads.end()) {
688 DBG("Not enabling excluded payload '%s'\n",
689 p->name);
690 return 0;
691 }
692
693 amci_codec_t* c;
694 unsigned int i, id;
695 if( !(c = codec(p->codec_id)) ){
696 ERROR("in payload '%s': codec id (%i) not supported\n",
697 p->name, p->codec_id);
698 return -1;
699 }
700 if(p->payload_id != -1){
701 if(payloads.find(p->payload_id) != payloads.end()){
702 ERROR("payload id (%i) already supported\n",p->payload_id);
703 return -1;
704 }
705 }
706 else {
707 p->payload_id = dynamic_pl;
708 dynamic_pl++;
709 }
710
711 payloads.insert(std::make_pair(p->payload_id,p));
712 id = p->payload_id;
713
714 for (i = 0; i < AmConfig::CodecOrder.size(); i++) {
715 if (p->name == AmConfig::CodecOrder[i]) break;
716 }
717 if (i >= AmConfig::CodecOrder.size()) {
718 payload_order.insert(std::make_pair(id + 100, id));
719 DBG("payload '%s/%i' inserted with id %i and order %i\n",
720 p->name, p->sample_rate, id, id + 100);
721 } else {
722 payload_order.insert(std::make_pair(i, id));
723 DBG("payload '%s/%i' inserted with id %i and order %i\n",
724 p->name, p->sample_rate, id, i);
725 }
726
727 return 0;
728 }
729
addFileFormat(amci_inoutfmt_t * f)730 int AmPlugIn::addFileFormat(amci_inoutfmt_t* f)
731 {
732 if(file_formats.find(f->name) != file_formats.end()){
733 ERROR("file format '%s' already supported\n",f->name);
734 return -1;
735 }
736
737 amci_subtype_t* st = f->subtypes;
738 for(; st->type >= 0; st++ ){
739
740 if( !codec(st->codec_id) ){
741 ERROR("in '%s' subtype %i: codec id (%i) not supported\n",
742 f->name,st->type,st->codec_id);
743 return -1;
744 }
745
746 if (st->sample_rate < 0) {
747 ERROR("in '%s' subtype %i: rate must be specified!"
748 " (ubr no longer supported)\n", f->name,st->type);
749 return -1;
750 }
751 if (st->channels < 0) {
752 ERROR("in '%s' subtype %i: channels must be specified!"
753 "(unspecified channel count no longer supported)\n", f->name,st->type);
754 return -1;
755 }
756
757 }
758 DBG("file format %s inserted\n",f->name);
759 file_formats.insert(std::make_pair(f->name,f));
760
761 return 0;
762 }
763
registerFactory4App(const string & app_name,AmSessionFactory * f)764 bool AmPlugIn::registerFactory4App(const string& app_name, AmSessionFactory* f)
765 {
766 bool res;
767
768 name2app_mut.lock();
769 std::map<std::string,AmSessionFactory*>::iterator it = name2app.find(app_name);
770 if(it != name2app.end()){
771 WARN("Application '%s' has already been registered and cannot be "
772 "registered a second time\n",
773 app_name.c_str());
774 res = false;
775 } else {
776 name2app.insert(make_pair(app_name,f));
777 res = true;
778 }
779 name2app_mut.unlock();
780
781 return res;
782 }
783
784 // static alias to registerFactory4App
registerApplication(const string & app_name,AmSessionFactory * f)785 bool AmPlugIn::registerApplication(const string& app_name, AmSessionFactory* f) {
786 bool res = instance()->registerFactory4App(app_name, f);
787 if (res) {
788 DBG("Application '%s' registered.\n", app_name.c_str());
789 }
790 return res;
791 }
792
findSessionFactory(const AmSipRequest & req,string & app_name)793 AmSessionFactory* AmPlugIn::findSessionFactory(const AmSipRequest& req, string& app_name)
794 {
795 string m_app_name;
796
797 switch (AmConfig::AppSelect) {
798
799 case AmConfig::App_RURIUSER:
800 m_app_name = req.user;
801 break;
802 case AmConfig::App_APPHDR:
803 m_app_name = getHeader(req.hdrs, APPNAME_HDR, true);
804 break;
805 case AmConfig::App_RURIPARAM:
806 m_app_name = get_header_param(req.r_uri, "app");
807 break;
808 case AmConfig::App_MAPPING:
809 m_app_name = ""; // no match if not found
810 run_regex_mapping(AmConfig::AppMapping, req.r_uri.c_str(), m_app_name);
811 break;
812 case AmConfig::App_SPECIFIED:
813 m_app_name = AmConfig::Application;
814 break;
815 }
816
817 if (m_app_name.empty()) {
818 INFO("could not find any application matching configured criteria\n");
819 return NULL;
820 }
821
822 AmSessionFactory* session_factory = getFactory4App(m_app_name);
823 if(!session_factory) {
824 ERROR("AmPlugIn::findSessionFactory: application '%s' not found !\n", m_app_name.c_str());
825 }
826
827 app_name = m_app_name;
828 return session_factory;
829 }
830
831 #define REGISTER_STUFF(comp_name, map_name, param_name) \
832 if(instance()->map_name.find(param_name) != instance()->map_name.end()){ \
833 ERROR(comp_name "'%s' already registered !\n", param_name.c_str()); \
834 return false; \
835 } \
836 inc_ref(f); \
837 instance()->map_name.insert(std::make_pair(param_name,f)); \
838 DBG(comp_name " '%s' registered.\n",param_name.c_str()); \
839 return true;
840
registerSIPEventHandler(const string & seh_name,AmSessionEventHandlerFactory * f)841 bool AmPlugIn::registerSIPEventHandler(const string& seh_name,
842 AmSessionEventHandlerFactory* f) {
843 REGISTER_STUFF("SIP Event handler", name2seh, seh_name);
844 }
845
registerDIInterface(const string & di_name,AmDynInvokeFactory * f)846 bool AmPlugIn::registerDIInterface(const string& di_name, AmDynInvokeFactory* f) {
847 REGISTER_STUFF("DI Interface", name2di, di_name);
848 }
849
registerLoggingFacility(const string & lf_name,AmLoggingFacility * f)850 bool AmPlugIn::registerLoggingFacility(const string& lf_name, AmLoggingFacility* f) {
851 REGISTER_STUFF("Logging Facility", name2logfac, lf_name);
852 }
853
854 #undef REGISTER_STUFF
855