From f5d9f0cfe52f5c55b19c445c349c668ee728b72c Mon Sep 17 00:00:00 2001 From: Stefan Sayer Date: Fri, 21 Sep 2007 00:29:24 +0000 Subject: [PATCH] serviceline application - ivr, then auth'ed b2b call with media relay git-svn-id: http://svn.berlios.de/svnroot/repos/sems/trunk@447 8eb893ce-cfd4-0310-b710-fb5ebe64c474 --- apps/examples/serviceline/Makefile | 10 + apps/examples/serviceline/Readme.serviceline | 19 ++ apps/examples/serviceline/ServiceLine.cpp | 205 ++++++++++++++++++ apps/examples/serviceline/ServiceLine.h | 99 +++++++++ .../examples/serviceline/etc/serviceline.conf | 21 ++ 5 files changed, 354 insertions(+) create mode 100644 apps/examples/serviceline/Makefile create mode 100644 apps/examples/serviceline/Readme.serviceline create mode 100644 apps/examples/serviceline/ServiceLine.cpp create mode 100644 apps/examples/serviceline/ServiceLine.h create mode 100644 apps/examples/serviceline/etc/serviceline.conf diff --git a/apps/examples/serviceline/Makefile b/apps/examples/serviceline/Makefile new file mode 100644 index 00000000..102672d2 --- /dev/null +++ b/apps/examples/serviceline/Makefile @@ -0,0 +1,10 @@ +plug_in_name = serviceline + +module_ldflags = +module_cflags = + +extra_install = $(plug_in_name)_audio + +COREPATH ?=../../../core +include $(COREPATH)/plug-in/Makefile.app_module + diff --git a/apps/examples/serviceline/Readme.serviceline b/apps/examples/serviceline/Readme.serviceline new file mode 100644 index 00000000..64035baf --- /dev/null +++ b/apps/examples/serviceline/Readme.serviceline @@ -0,0 +1,19 @@ +serviceline application + +This application could serve for something like a service line: +The caller calls the service number, and gets an ivr menu, from where +she can be connected to various numbers - by pressing 0 she is connected +to one number, by pressing 1 to another number etc. + +The outgoing call is connected in B2BUA mode with media relay ('b2abua'), +so technically the two legs are independent sip dialogs and media sessions. + +The outgoing calls (B leg) are optionally SIP authenticated, so for example, +normal gateways can be used. The uac_auth module must be loaded for this +to work. If the uac_auth module is not loaded, the outgoing calls are not +authenticated. + +To extend this module with so useful things like prompt on failed call, +leave message fwdd via email on failed call etc is left as an exercise +to the reader. Improvements are of course welcome as svn diff to the +semsdev mailing list. \ No newline at end of file diff --git a/apps/examples/serviceline/ServiceLine.cpp b/apps/examples/serviceline/ServiceLine.cpp new file mode 100644 index 00000000..098accc9 --- /dev/null +++ b/apps/examples/serviceline/ServiceLine.cpp @@ -0,0 +1,205 @@ +/* + * $Id: ServiceLine.cpp 433 2007-08-29 20:17:38Z sayer $ + * + * Copyright (C) 2007 iptego GmbH + * + * This file is part of SEMS, a free SIP media server. + * + * SEMS 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 2 of the License, or + * (at your option) any later version. + * + * For a license to use the SEMS software under conditions + * other than those described here, or to purchase support for this + * software, please contact iptel.org by e-mail at the following addresses: + * info@iptel.org + * + * SEMS 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ServiceLine.h" +#include "AmSessionContainer.h" +#include "AmConfig.h" +#include "AmUtils.h" +#include "AmApi.h" +#include "AmPlugIn.h" + +#include "AmMediaProcessor.h" + +#include "sems.h" +#include "log.h" + +#define MOD_NAME "serviceline" + +EXPORT_SESSION_FACTORY(ServiceLineFactory,MOD_NAME); + +string ServiceLineFactory::AnnouncePath; +string ServiceLineFactory::AnnounceFile; + +string ServiceLineFactory::callee_numbers[10]; + +string ServiceLineFactory::GWDomain; +string ServiceLineFactory::GWUser; +string ServiceLineFactory::GWDisplayname; + +string ServiceLineFactory::GWAuthuser; +string ServiceLineFactory::GWAuthrealm; +string ServiceLineFactory::GWAuthpwd; + +ServiceLineFactory::ServiceLineFactory(const string& _app_name) + : AmSessionFactory(_app_name) +{ +} + +int ServiceLineFactory::onLoad() +{ + AmConfigReader cfg; + if(cfg.loadFile(AmConfig::ModConfigPath + string(MOD_NAME ".conf"))) + return -1; + + // get application specific global parameters + configureModule(cfg); + + AnnounceFile = cfg.getParameter("prompt",ANNOUNCE_FILE); + DBG("Prompt = %s\n",AnnounceFile.c_str()); + + string announce_file = AnnounceFile; + if(!file_exists(announce_file)){ + ERROR("prompt file for serviceline module does not exist ('%s').\n", + announce_file.c_str()); + return -1; + } + + DBG("ServiceLine Connect DTMF Key Mapping:\n"); + for (unsigned int i=0;i<10;i++) { + callee_numbers[i] = cfg.getParameter("callee_number"+int2str(i)); + DBG("Key %u -> Extension __%s__\n", + i, callee_numbers[i].empty()? + "none":callee_numbers[i].c_str()); + } + + GWDomain= cfg.getParameter("gw_domain", "");; + GWUser= cfg.getParameter("gw_user", "");; + GWDisplayname= cfg.getParameter("gw_displayname", "");; + + GWAuthuser= cfg.getParameter("gw_authuser", ""); + GWAuthrealm=cfg.getParameter("gw_authrealm", ""); // actually unused + GWAuthpwd=cfg.getParameter("gw_authpwd", ""); + + return 0; +} + +AmSession* ServiceLineFactory::onInvite(const AmSipRequest& req) +{ + string announce_path = AnnouncePath; + string announce_file = announce_path + req.domain + + "/" + req.user + ".wav"; + + DBG("trying '%s'\n",announce_file.c_str()); + if(file_exists(announce_file)) + new ServiceLineCallerDialog(announce_file); + + announce_file = announce_path + req.user + ".wav"; + DBG("trying '%s'\n",announce_file.c_str()); + if(file_exists(announce_file)) + new ServiceLineCallerDialog(announce_file); + + announce_file = AnnouncePath + AnnounceFile; + return new ServiceLineCallerDialog(announce_file); +} + +ServiceLineCallerDialog::ServiceLineCallerDialog(const string& filename) + : filename(filename), + playlist(this), + AmB2ABCallerSession() +{ +} + +void ServiceLineCallerDialog::onSessionStart(const AmSipRequest& req) +{ + + AmB2ABCallerSession::onSessionStart(req); + + if(wav_file.open(filename,AmAudioFile::Read)) + throw string("AnnouncementDialog::onSessionStart: Cannot open file\n"); + + setInOut(&playlist, &playlist); + playlist.addToPlaylist(new AmPlaylistItem(&wav_file, NULL)); +} + +void ServiceLineCallerDialog::process(AmEvent* event) +{ + + AmAudioEvent* audio_event = dynamic_cast(event); + + if(audio_event && (audio_event->event_id == AmAudioEvent::cleared)){ + DBG("ignoring end of prompt.\n"); + return; + } + + AmB2ABCallerSession::process(event); +} + +void ServiceLineCallerDialog::onDtmf(int event, int duration) +{ + DBG("DTMF event %d duration %d\n", event, duration); + if (getCalleeStatus() != None) + return; + + if ((event < 10) && (event >= 0) && + (!ServiceLineFactory::callee_numbers[event].empty())) { + connectCallee("sip:"+ServiceLineFactory::callee_numbers[event]+"@"+ServiceLineFactory::GWDomain, + "sip:"+ServiceLineFactory::callee_numbers[event]+"@"+ServiceLineFactory::GWDomain, + "sip:"+ServiceLineFactory::GWUser+"@"+ServiceLineFactory::GWDomain, + "sip:"+ServiceLineFactory::GWUser+"@"+ServiceLineFactory::GWDomain); + } + + return; + +} + +AmB2ABCalleeSession* ServiceLineCallerDialog::createCalleeSession() { + ServiceLineCalleeDialog* sess = new ServiceLineCalleeDialog(getLocalTag()); + + AmSessionEventHandlerFactory* uac_auth_f = + AmPlugIn::instance()->getFactory4Seh("uac_auth"); + + if (NULL != uac_auth_f) { + DBG("UAC Auth enabled for new serviceline session.\n"); + AmSessionEventHandler* h = uac_auth_f->getHandler(sess); + if (h != NULL ) + sess->addHandler(h); + else { + ERROR("unable to set SIP UAC auth for new session."); + } + } else { + ERROR("unable to get SIP UAC auth." + "(uac_auth module loaded?)\n"); + } + return sess; +} + +ServiceLineCalleeDialog::~ServiceLineCalleeDialog() { +} + +ServiceLineCalleeDialog::ServiceLineCalleeDialog(const string& other_tag) + : AmB2ABCalleeSession(other_tag), + cred(ServiceLineFactory::GWAuthrealm, + ServiceLineFactory::GWAuthuser, + ServiceLineFactory::GWAuthpwd) +{ + rtp_str.setPlayoutType(ADAPTIVE_PLAYOUT); + setDtmfDetectionEnabled(false); +} + +UACAuthCred* ServiceLineCalleeDialog::getCredentials() { + return &cred; +} diff --git a/apps/examples/serviceline/ServiceLine.h b/apps/examples/serviceline/ServiceLine.h new file mode 100644 index 00000000..088f92f0 --- /dev/null +++ b/apps/examples/serviceline/ServiceLine.h @@ -0,0 +1,99 @@ +/* + * $Id: ServiceLine.h 433 2007-08-29 20:17:38Z sayer $ + * + * Copyright (C) 2007 iptego GmbH + * + * This file is part of SEMS, a free SIP media server. + * + * SEMS 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 2 of the License, or + * (at your option) any later version. + * + * For a license to use the SEMS software under conditions + * other than those described here, or to purchase support for this + * software, please contact iptel.org by e-mail at the following addresses: + * info@iptel.org + * + * SEMS 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _SERVICELINE_H_ +#define _SERVICELINE_H_ + +#include "AmApi.h" +#include "AmConfigReader.h" +#include "AmAudio.h" +#include "AmB2ABSession.h" +#include "ampi/UACAuthAPI.h" + +#include +using std::string; + +class ServiceLineFactory: public AmSessionFactory +{ +public: + static string AnnouncePath; + static string AnnounceFile; + + static string callee_numbers[10]; + + static string GWDomain; + static string GWUser; + static string GWDisplayname; + + static string GWAuthuser; + static string GWAuthrealm; + static string GWAuthpwd; + + ServiceLineFactory(const string& _app_name); + + int onLoad(); + AmSession* onInvite(const AmSipRequest& req); +}; + +class ServiceLineCallerDialog: public AmB2ABCallerSession +{ + AmAudioFile wav_file; + // we use a playlist to keep media processing, RTP + // sending & DTMF detection after prompt has finished + AmPlaylist playlist; + string filename; + + string callee_addr; + string callee_uri; + +public: + ServiceLineCallerDialog(const string& filename); + + void process(AmEvent* event); + void onDtmf(int event, int duration); + void onSessionStart(const AmSipRequest& req); + + virtual AmB2ABCalleeSession* createCalleeSession(); +}; + +// need this for auth +class ServiceLineCalleeDialog + : public AmB2ABCalleeSession, + public CredentialHolder { + UACAuthCred cred; + +public: + ServiceLineCalleeDialog(const string& other_tag); + ~ServiceLineCalleeDialog(); + UACAuthCred* getCredentials(); +}; + +#endif +// Local Variables: +// mode:C++ +// End: + diff --git a/apps/examples/serviceline/etc/serviceline.conf b/apps/examples/serviceline/etc/serviceline.conf new file mode 100644 index 00000000..bbc1a31c --- /dev/null +++ b/apps/examples/serviceline/etc/serviceline.conf @@ -0,0 +1,21 @@ +# the prompt that is played at the beginning +# ("press one to connect to x, two for y, ..." +prompt=/usr/local/lib/sems/audio/default_en.wav + +# 0 pressed -> call callee_number0@gw_domain +# 1 pressed -> call callee_number1@gw_domain +# etc. +callee_number0=+49123456789 +callee_number1=+34222222222 + +# domain/gateway used for outgoing calls (B leg) +# +gw_domain=myprovider.com +gw_user=myuser +gw_displayname=myuser + +# authentication (if needed) +gw_authuser=my_auth_user +gw_authrealm=myprovider.com +gw_authpwd=verysecret +