mirror of https://github.com/sipwise/sems.git
git-svn-id: http://svn.berlios.de/svnroot/repos/sems/trunk@962 8eb893ce-cfd4-0310-b710-fb5ebe64c474sayer/1.4-spce2.6
parent
5c6d4fd1f8
commit
7ba7e5fcbb
@ -0,0 +1,524 @@
|
||||
/*
|
||||
* $Id: AnnRecorder.cpp 722 2008-02-12 12:52:31Z sayer $
|
||||
*
|
||||
* Copyright (C) 2002-2003 Fhg Fokus
|
||||
*
|
||||
* 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 "AnnRecorder.h"
|
||||
#include "AmConfig.h"
|
||||
#include "AmUtils.h"
|
||||
#include "AmPlugIn.h"
|
||||
#include "AmPromptCollection.h"
|
||||
#include "../msg_storage/MsgStorageAPI.h"
|
||||
#include "sems.h"
|
||||
#include "log.h"
|
||||
|
||||
using std::map;
|
||||
|
||||
#define MOD_NAME "annrecorder"
|
||||
|
||||
#define DEFAULT_TYPE "aa"
|
||||
#define DOMAIN_PROMPT_SUFFIX "-prompt"
|
||||
|
||||
#define TIMERID_START_TIMER 1
|
||||
#define TIMERID_CONFIRM_TIMER 2
|
||||
|
||||
#define START_RECORDING_TIMEOUT 20
|
||||
#define CONFIRM_RECORDING_TIMEOUT 20
|
||||
|
||||
#define SEP_CONFIRM_BEGIN 1
|
||||
#define SEP_MSG_BEGIN 2
|
||||
|
||||
#define MAX_MESSAGE_TIME 120
|
||||
|
||||
EXPORT_SESSION_FACTORY(AnnRecorderFactory,MOD_NAME);
|
||||
|
||||
string AnnRecorderFactory::AnnouncePath;
|
||||
string AnnRecorderFactory::DefaultAnnounce;
|
||||
AmDynInvokeFactory* AnnRecorderFactory::user_timer_fact = NULL;
|
||||
AmDynInvokeFactory* AnnRecorderFactory::message_storage_fact = NULL;
|
||||
|
||||
const char* MsgStrError(int e) {
|
||||
switch (e) {
|
||||
case MSG_OK: return "MSG_OK"; break;
|
||||
case MSG_EMSGEXISTS: return "MSG_EMSGEXISTS"; break;
|
||||
case MSG_EUSRNOTFOUND: return "MSG_EUSRNOTFOUND"; break;
|
||||
case MSG_EMSGNOTFOUND: return "MSG_EMSGNOTFOUND"; break;
|
||||
case MSG_EALREADYCLOSED: return "MSG_EALREADYCLOSED"; break;
|
||||
case MSG_EREADERROR: return "MSG_EREADERROR"; break;
|
||||
case MSG_ENOSPC: return "MSG_ENOSPC"; break;
|
||||
case MSG_ESTORAGE: return "MSG_ESTORAGE"; break;
|
||||
default: return "Unknown Error";
|
||||
}
|
||||
}
|
||||
|
||||
AnnRecorderFactory::AnnRecorderFactory(const string& _app_name)
|
||||
: AmSessionFactory(_app_name)
|
||||
{
|
||||
}
|
||||
|
||||
int AnnRecorderFactory::onLoad()
|
||||
{
|
||||
AmConfigReader cfg;
|
||||
if(cfg.loadFile(AmConfig::ModConfigPath + string(MOD_NAME ".conf")))
|
||||
return -1;
|
||||
|
||||
// get application specific global parameters
|
||||
configureModule(cfg);
|
||||
|
||||
AnnouncePath = cfg.getParameter("announce_path",ANNOUNCE_PATH);
|
||||
if( !AnnouncePath.empty()
|
||||
&& AnnouncePath[AnnouncePath.length()-1] != '/' )
|
||||
AnnouncePath += "/";
|
||||
DefaultAnnounce = cfg.getParameter("default_announce");
|
||||
|
||||
AM_PROMPT_START;
|
||||
AM_PROMPT_ADD(WELCOME, ANNREC_ANNOUNCE_PATH WELCOME".wav");
|
||||
AM_PROMPT_ADD(YOUR_PROMPT, ANNREC_ANNOUNCE_PATH YOUR_PROMPT".wav");
|
||||
AM_PROMPT_ADD(TO_RECORD, ANNREC_ANNOUNCE_PATH TO_RECORD".wav");
|
||||
AM_PROMPT_ADD(CONFIRM, ANNREC_ANNOUNCE_PATH CONFIRM".wav");
|
||||
AM_PROMPT_ADD(GREETING_SET, ANNREC_ANNOUNCE_PATH GREETING_SET".wav");
|
||||
AM_PROMPT_ADD(BYE, ANNREC_ANNOUNCE_PATH BYE".wav");
|
||||
AM_PROMPT_ADD(BEEP, ANNREC_ANNOUNCE_PATH BEEP".wav");
|
||||
AM_PROMPT_END(prompts, cfg, MOD_NAME);
|
||||
|
||||
|
||||
user_timer_fact = AmPlugIn::instance()->getFactory4Di("user_timer");
|
||||
if(!user_timer_fact) {
|
||||
ERROR("sorry, could not load user_timer from session_timer plug-in\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
message_storage_fact= AmPlugIn::instance()->getFactory4Di("msg_storage");
|
||||
if(!user_timer_fact) {
|
||||
ERROR("sorry, could not get msg_storage, please load a suitable plug-in\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AnnRecorderFactory::getAppParams(const AmSipRequest& req, map<string, string>& params) {
|
||||
string language;
|
||||
string domain;
|
||||
string user;
|
||||
string typ;
|
||||
|
||||
string iptel_app_param = getHeader(req.hdrs, PARAM_HDR);
|
||||
|
||||
if (!iptel_app_param.length()) {
|
||||
throw AmSession::Exception(500, MOD_NAME ": parameters not found");
|
||||
}
|
||||
|
||||
language = get_header_keyvalue(iptel_app_param, "lng", "Language");
|
||||
|
||||
user = get_header_keyvalue(iptel_app_param,"usr", "User");
|
||||
if (!user.length())
|
||||
user = req.user;
|
||||
|
||||
domain = get_header_keyvalue(iptel_app_param, "dom", "Domain");
|
||||
if (!domain.length())
|
||||
domain = req.domain;
|
||||
|
||||
|
||||
typ = get_header_keyvalue(iptel_app_param, "typ", "Type");
|
||||
if (!typ.length())
|
||||
typ = DEFAULT_TYPE;
|
||||
|
||||
// checks
|
||||
if (user.empty())
|
||||
throw AmSession::Exception(500, MOD_NAME ": user missing");
|
||||
|
||||
string announce_file = add2path(AnnouncePath,2, domain.c_str(), (user + ".wav").c_str());
|
||||
if (file_exists(announce_file)) goto announce_found;
|
||||
|
||||
if (!language.empty()) {
|
||||
announce_file = add2path(AnnouncePath,3, domain.c_str(), language.c_str(), DefaultAnnounce.c_str());
|
||||
if (file_exists(announce_file)) goto announce_found;
|
||||
}
|
||||
|
||||
announce_file = add2path(AnnouncePath,2, domain.c_str(), DefaultAnnounce.c_str());
|
||||
if (file_exists(announce_file)) goto announce_found;
|
||||
|
||||
if (!language.empty()) {
|
||||
announce_file = add2path(AnnouncePath,2, language.c_str(), DefaultAnnounce.c_str());
|
||||
if (file_exists(announce_file)) goto announce_found;
|
||||
}
|
||||
|
||||
announce_file = add2path(AnnouncePath,1, DefaultAnnounce.c_str());
|
||||
if (!file_exists(announce_file))
|
||||
announce_file = "";
|
||||
|
||||
announce_found:
|
||||
|
||||
DBG(MOD_NAME " invocation parameters: \n");
|
||||
DBG(" User: <%s> \n", user.c_str());
|
||||
DBG(" Domain: <%s> \n", domain.c_str());
|
||||
DBG(" Language: <%s> \n", language.c_str());
|
||||
DBG(" Type: <%s> \n", typ.c_str());
|
||||
DBG(" Def. File:<%s> \n", announce_file.c_str());
|
||||
|
||||
params["domain"] = domain;
|
||||
params["user"] = user;
|
||||
params["defaultfile"] = announce_file;
|
||||
params["type"] = typ;
|
||||
}
|
||||
|
||||
AmSession* AnnRecorderFactory::onInvite(const AmSipRequest& req)
|
||||
{
|
||||
map<string, string> params;
|
||||
getAppParams(req, params);
|
||||
return new AnnRecorderDialog(params, prompts, NULL);
|
||||
}
|
||||
|
||||
AmSession* AnnRecorderFactory::onInvite(const AmSipRequest& req,
|
||||
AmArg& session_params)
|
||||
{
|
||||
UACAuthCred* cred = NULL;
|
||||
if (session_params.getType() == AmArg::AObject) {
|
||||
ArgObject* cred_obj = session_params.asObject();
|
||||
if (cred_obj)
|
||||
cred = dynamic_cast<UACAuthCred*>(cred_obj);
|
||||
}
|
||||
|
||||
map<string, string> params;
|
||||
getAppParams(req, params);
|
||||
AmSession* s = new AnnRecorderDialog(params, prompts, cred);
|
||||
|
||||
if (NULL == cred) {
|
||||
WARN("discarding unknown session parameters.\n");
|
||||
} else {
|
||||
AmSessionEventHandlerFactory* uac_auth_f =
|
||||
AmPlugIn::instance()->getFactory4Seh("uac_auth");
|
||||
if (uac_auth_f != NULL) {
|
||||
DBG("UAC Auth enabled for new announcement session.\n");
|
||||
AmSessionEventHandler* h = uac_auth_f->getHandler(s);
|
||||
if (h != NULL )
|
||||
s->addHandler(h);
|
||||
} else {
|
||||
ERROR("uac_auth interface not accessible. "
|
||||
"Load uac_auth for authenticated dialout.\n");
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
AnnRecorderDialog::AnnRecorderDialog(const map<string, string>& params,
|
||||
AmPromptCollection& prompts,
|
||||
UACAuthCred* credentials)
|
||||
: params(params),
|
||||
prompts(prompts), cred(credentials),
|
||||
playlist(this)
|
||||
{
|
||||
user_timer = AnnRecorderFactory::user_timer_fact->getInstance();
|
||||
if(!user_timer) {
|
||||
ERROR("could not get a user timer reference\n");
|
||||
throw AmSession::Exception(500,"could not get a timer");
|
||||
}
|
||||
|
||||
msg_storage = AnnRecorderFactory::message_storage_fact->getInstance();
|
||||
if(!msg_storage){
|
||||
ERROR("could not get a message storage reference\n");
|
||||
throw AmSession::Exception(500,"could not get a message storage reference");
|
||||
}
|
||||
}
|
||||
|
||||
AnnRecorderDialog::~AnnRecorderDialog()
|
||||
{
|
||||
prompts.cleanup((long)this);
|
||||
if (msg_filename.length())
|
||||
unlink(msg_filename.c_str());
|
||||
}
|
||||
|
||||
void AnnRecorderDialog::onSessionStart(const AmSipRequest& req)
|
||||
{
|
||||
DBG("AnnRecorderDialog::onSessionStart\n");
|
||||
startSession();
|
||||
}
|
||||
|
||||
void AnnRecorderDialog::onSessionStart(const AmSipReply& rep)
|
||||
{
|
||||
DBG("AnnRecorderDialog::onSessionStart (SEMS originator mode)\n");
|
||||
startSession();
|
||||
}
|
||||
|
||||
void AnnRecorderDialog::startSession(){
|
||||
prompts.addToPlaylist(WELCOME, (long)this, playlist);
|
||||
prompts.addToPlaylist(YOUR_PROMPT, (long)this, playlist);
|
||||
enqueueCurrent();
|
||||
prompts.addToPlaylist(TO_RECORD, (long)this, playlist);
|
||||
enqueueSeparator(SEP_MSG_BEGIN);
|
||||
|
||||
// set the playlist as input and output
|
||||
setInOut(&playlist,&playlist);
|
||||
state = S_WAIT_START;
|
||||
}
|
||||
|
||||
void AnnRecorderDialog::enqueueCurrent() {
|
||||
wav_file.close();
|
||||
FILE* fp = getCurrentMessage();
|
||||
if (!fp) {
|
||||
DBG("no recorded msg available, using default\n");
|
||||
if (wav_file.open(params["defaultfile"], AmAudioFile::Read)) {
|
||||
ERROR("opening default greeting file '%s'!\n", params["defaultfile"].c_str());
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (wav_file.fpopen("aa.wav", AmAudioFile::Read, fp)) {
|
||||
ERROR("fpopen message file!\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
playlist.addToPlaylist(new AmPlaylistItem(&wav_file, NULL));
|
||||
}
|
||||
|
||||
void AnnRecorderDialog::onDtmf(int event, int duration_msec) {
|
||||
DBG("DTMF %d, %d\n", event, duration_msec);
|
||||
// remove timer
|
||||
try {
|
||||
AmArg di_args,ret;
|
||||
di_args.push(getLocalTag().c_str());
|
||||
user_timer->invoke("removeUserTimers", di_args, ret);
|
||||
} catch(...) {
|
||||
ERROR("Exception caught calling mod api\n");
|
||||
}
|
||||
|
||||
switch (state) {
|
||||
case S_WAIT_START: {
|
||||
DBG("received key %d in state S_WAIT_START: start recording\n", event);
|
||||
playlist.close(false);
|
||||
|
||||
wav_file.close();
|
||||
msg_filename = "/tmp/" + getLocalTag() + ".wav";
|
||||
if(wav_file.open(msg_filename,AmAudioFile::Write,false)) {
|
||||
ERROR("AnnRecorder: couldn't open %s for writing\n",
|
||||
msg_filename.c_str());
|
||||
dlg.bye();
|
||||
setStopped();
|
||||
}
|
||||
wav_file.setRecordTime(MAX_MESSAGE_TIME*1000);
|
||||
prompts.addToPlaylist(BEEP, (long)this, playlist);
|
||||
playlist.addToPlaylist(new AmPlaylistItem(NULL,&wav_file));
|
||||
|
||||
state = S_RECORDING;
|
||||
} break;
|
||||
|
||||
case S_RECORDING: {
|
||||
DBG("received key %d in state S_RECORDING: replay recording\n", event);
|
||||
prompts.addToPlaylist(BEEP, (long)this, playlist);
|
||||
playlist.close(false);
|
||||
replayRecording();
|
||||
|
||||
} break;
|
||||
|
||||
case S_CONFIRM: {
|
||||
DBG("received key %d in state S_CONFIRM save or redo\n", event);
|
||||
playlist.close(false);
|
||||
|
||||
wav_file.close();
|
||||
if (event == 1) {
|
||||
// save msg
|
||||
saveAndConfirm();
|
||||
} else {
|
||||
prompts.addToPlaylist(TO_RECORD, (long)this, playlist);
|
||||
state = S_WAIT_START;
|
||||
}
|
||||
} break;
|
||||
|
||||
default: {
|
||||
DBG("ignoring key %d in state %d\n",
|
||||
event, state);
|
||||
}break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void AnnRecorderDialog::saveAndConfirm() {
|
||||
// wav_file.setCloseOnDestroy(false);
|
||||
// wav_file.on_close();
|
||||
saveMessage(wav_file.getfp());
|
||||
prompts.addToPlaylist(GREETING_SET, (long)this, playlist);
|
||||
prompts.addToPlaylist(BYE, (long)this, playlist);
|
||||
state = S_BYE;
|
||||
}
|
||||
|
||||
void AnnRecorderDialog::onBye(const AmSipRequest& req)
|
||||
{
|
||||
DBG("onBye: stopSession\n");
|
||||
setStopped();
|
||||
}
|
||||
|
||||
void AnnRecorderDialog::process(AmEvent* event)
|
||||
{
|
||||
|
||||
AmPluginEvent* plugin_event = dynamic_cast<AmPluginEvent*>(event);
|
||||
if(plugin_event && plugin_event->name == "timer_timeout") {
|
||||
event->processed = true;
|
||||
int timer_id = plugin_event->data.get(0).asInt();
|
||||
if (timer_id == TIMERID_START_TIMER) {
|
||||
if (S_WAIT_START == state) {
|
||||
prompts.addToPlaylist(BYE, (long)this, playlist);
|
||||
state = S_BYE;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (timer_id == TIMERID_CONFIRM_TIMER) {
|
||||
saveAndConfirm();
|
||||
return;
|
||||
}
|
||||
ERROR("unknown timer id!\n");
|
||||
}
|
||||
|
||||
AmAudioEvent* audio_event = dynamic_cast<AmAudioEvent*>(event);
|
||||
if(audio_event && (audio_event->event_id == AmAudioEvent::noAudio)){
|
||||
|
||||
if (S_BYE == state) {
|
||||
dlg.bye();
|
||||
setStopped();
|
||||
return;
|
||||
}
|
||||
|
||||
if (S_RECORDING == state) {
|
||||
replayRecording();
|
||||
}
|
||||
}
|
||||
|
||||
AmPlaylistSeparatorEvent* pl_ev = dynamic_cast<AmPlaylistSeparatorEvent*>(event);
|
||||
if (pl_ev) {
|
||||
if ((pl_ev->event_id == SEP_MSG_BEGIN) &&
|
||||
(S_WAIT_START == state)) {
|
||||
// start timer
|
||||
AmArg di_args,ret;
|
||||
di_args.push(TIMERID_START_TIMER);
|
||||
di_args.push(START_RECORDING_TIMEOUT); // in seconds
|
||||
di_args.push(getLocalTag().c_str());
|
||||
user_timer->invoke("setTimer", di_args, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((pl_ev->event_id == SEP_CONFIRM_BEGIN) &&
|
||||
(S_CONFIRM == state)) {
|
||||
// start timer
|
||||
AmArg di_args,ret;
|
||||
di_args.push(TIMERID_CONFIRM_TIMER);
|
||||
di_args.push(CONFIRM_RECORDING_TIMEOUT); // in seconds
|
||||
di_args.push(getLocalTag().c_str());
|
||||
user_timer->invoke("setTimer", di_args, ret);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
AmSession::process(event);
|
||||
}
|
||||
|
||||
void AnnRecorderDialog::replayRecording() {
|
||||
prompts.addToPlaylist(YOUR_PROMPT, (long)this, playlist);
|
||||
DBG("msg_filename = '%s'\n", msg_filename.c_str());
|
||||
if (!wav_file.open(msg_filename, AmAudioFile::Read))
|
||||
playlist.addToPlaylist(new AmPlaylistItem(&wav_file, NULL));
|
||||
prompts.addToPlaylist(CONFIRM, (long)this, playlist);
|
||||
enqueueSeparator(SEP_CONFIRM_BEGIN);
|
||||
state = S_CONFIRM;
|
||||
}
|
||||
|
||||
inline UACAuthCred* AnnRecorderDialog::getCredentials() {
|
||||
return cred.get();
|
||||
}
|
||||
|
||||
void AnnRecorderDialog::saveMessage(FILE* fp) {
|
||||
string msg_name = params["type"]+".wav";
|
||||
DBG("message name is '%s'\n", msg_name.c_str());
|
||||
|
||||
AmArg di_args,ret;
|
||||
di_args.push((params["domain"]+DOMAIN_PROMPT_SUFFIX).c_str()); // domain
|
||||
di_args.push(params["user"].c_str()); // user
|
||||
di_args.push(msg_name.c_str()); // message name
|
||||
AmArg df;
|
||||
MessageDataFile df_arg(fp);
|
||||
df.setBorrowedPointer(&df_arg);
|
||||
di_args.push(df);
|
||||
try {
|
||||
msg_storage->invoke("msg_new",di_args,ret);
|
||||
} catch(string& s) {
|
||||
ERROR("invoking msg_new: '%s'\n", s.c_str());
|
||||
} catch(...) {
|
||||
ERROR("invoking msg_new.\n");
|
||||
}
|
||||
// TODO: evaluate ret return value
|
||||
}
|
||||
|
||||
FILE* AnnRecorderDialog::getCurrentMessage() {
|
||||
string msgname = params["type"]+".wav";
|
||||
string& user = params["user"];
|
||||
string domain = params["domain"]+DOMAIN_PROMPT_SUFFIX;
|
||||
|
||||
DBG("trying to get message '%s' for user '%s' domain '%s'\n",
|
||||
msgname.c_str(), user.c_str(), domain.c_str());
|
||||
AmArg di_args,ret;
|
||||
di_args.push(domain.c_str()); // domain
|
||||
di_args.push(user.c_str()); // user
|
||||
di_args.push(msgname.c_str()); // msg name
|
||||
|
||||
msg_storage->invoke("msg_get",di_args,ret);
|
||||
if (!ret.size()
|
||||
|| !isArgInt(ret.get(0))) {
|
||||
ERROR("msg_get for user '%s' domain '%s' msg '%s'"
|
||||
" returned no (valid) result.\n",
|
||||
user.c_str(), domain.c_str(),
|
||||
msgname.c_str()
|
||||
);
|
||||
return NULL;
|
||||
}
|
||||
int ecode = ret.get(0).asInt();
|
||||
if (MSG_OK != ecode) {
|
||||
DBG("msg_get for user '%s' domain '%s' message '%s': %s\n",
|
||||
user.c_str(), domain.c_str(),
|
||||
msgname.c_str(),
|
||||
MsgStrError(ret.get(0).asInt()));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((ret.size() < 2) ||
|
||||
(!isArgAObject(ret.get(1)))) {
|
||||
ERROR("msg_get for user '%s' domain '%s' message '%s': "
|
||||
"invalid return value\n",
|
||||
user.c_str(), domain.c_str(),
|
||||
msgname.c_str());
|
||||
return NULL;
|
||||
}
|
||||
MessageDataFile* f =
|
||||
dynamic_cast<MessageDataFile*>(ret.get(1).asObject());
|
||||
if (NULL == f)
|
||||
return NULL;
|
||||
|
||||
FILE* fp = f->fp;
|
||||
delete f;
|
||||
return fp;
|
||||
}
|
||||
|
||||
void AnnRecorderDialog::enqueueSeparator(int id) {
|
||||
playlist_separator.reset(new AmPlaylistSeparator(this, id));
|
||||
playlist.addToPlaylist(new AmPlaylistItem(playlist_separator.get(), NULL));
|
||||
}
|
||||
@ -0,0 +1,141 @@
|
||||
/*
|
||||
* $Id: AnnRecorder.h 711 2008-02-10 18:52:44Z sayer $
|
||||
*
|
||||
* Copyright (C) 2002-2003 Fhg Fokus
|
||||
*
|
||||
* 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 _ANNRECORDER_H_
|
||||
#define _ANNRECORDER_H_
|
||||
|
||||
#include "AmSession.h"
|
||||
#include "AmAudioFile.h"
|
||||
#include "AmConfigReader.h"
|
||||
|
||||
#include "ampi/UACAuthAPI.h"
|
||||
|
||||
#include "AmPromptCollection.h"
|
||||
|
||||
#include <string>
|
||||
using std::string;
|
||||
#include <map>
|
||||
|
||||
#include <memory>
|
||||
|
||||
// prompts used
|
||||
|
||||
//"Welcome to iptel dot org voip service."
|
||||
#define WELCOME "welcome"
|
||||
// "Your auto attendant greeting sounds like this: -"
|
||||
#define YOUR_PROMPT "your_prompt"
|
||||
// "To record a new auto attendant greeting, press any key. End recording with any key. -"
|
||||
#define TO_RECORD "to_record"
|
||||
//"Press one to keep the new greeting, or two to record a new one. -"
|
||||
#define CONFIRM "confirm"
|
||||
// "Your new auto attendant greeting has been set."
|
||||
#define GREETING_SET "greeting_set"
|
||||
// "Thank you for using the iptel dot org service. Good Bye. - "
|
||||
#define BYE "bye"
|
||||
#define BEEP "beep"
|
||||
|
||||
#define ANNREC_ANNOUNCE_PATH "/usr/local/lib/sems/audio/annrecorder/"
|
||||
|
||||
/** \brief Factory for announcement sessions */
|
||||
class AnnRecorderFactory: public AmSessionFactory
|
||||
{
|
||||
void getAppParams(const AmSipRequest& req, std::map<string, string>& params);
|
||||
AmPromptCollection prompts;
|
||||
|
||||
public:
|
||||
static AmDynInvokeFactory* user_timer_fact;
|
||||
static AmDynInvokeFactory* message_storage_fact;
|
||||
|
||||
static string AnnouncePath;
|
||||
static string DefaultAnnounce;
|
||||
|
||||
AnnRecorderFactory(const string& _app_name);
|
||||
|
||||
int onLoad();
|
||||
AmSession* onInvite(const AmSipRequest& req);
|
||||
AmSession* onInvite(const AmSipRequest& req,
|
||||
AmArg& session_params);
|
||||
|
||||
};
|
||||
|
||||
/**\brief announcement session logic implementation */
|
||||
class AnnRecorderDialog : public AmSession,
|
||||
public CredentialHolder
|
||||
{
|
||||
AmPromptCollection& prompts;
|
||||
AmPlaylist playlist;
|
||||
// we need only one separator in queue
|
||||
auto_ptr<AmPlaylistSeparator> playlist_separator;
|
||||
|
||||
AmAudioFile wav_file;
|
||||
std::map<string, string> params;
|
||||
|
||||
string msg_filename; // recorded file
|
||||
|
||||
AmDynInvoke* user_timer;
|
||||
AmDynInvoke* msg_storage;
|
||||
|
||||
std::auto_ptr<UACAuthCred> cred;
|
||||
|
||||
enum AnnRecorderState {
|
||||
S_WAIT_START,
|
||||
S_BYE,
|
||||
S_RECORDING,
|
||||
S_CONFIRM
|
||||
};
|
||||
|
||||
AnnRecorderState state;
|
||||
void enqueueCurrent();
|
||||
void saveAndConfirm();
|
||||
void replayRecording();
|
||||
void enqueueSeparator(int id);
|
||||
|
||||
FILE* getCurrentMessage();
|
||||
void saveMessage(FILE* fp);
|
||||
|
||||
public:
|
||||
AnnRecorderDialog(const std::map<string, string>& params,
|
||||
AmPromptCollection& prompts,
|
||||
UACAuthCred* credentials = NULL);
|
||||
~AnnRecorderDialog();
|
||||
|
||||
void onSessionStart(const AmSipRequest& req);
|
||||
void onSessionStart(const AmSipReply& rep);
|
||||
void startSession();
|
||||
void onBye(const AmSipRequest& req);
|
||||
void onDtmf(int event, int duration_msec);
|
||||
|
||||
void process(AmEvent* event);
|
||||
|
||||
UACAuthCred* getCredentials();
|
||||
};
|
||||
|
||||
#endif
|
||||
// Local Variables:
|
||||
// mode:C++
|
||||
// End:
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
plug_in_name = annrecorder
|
||||
|
||||
module_ldflags =
|
||||
module_cflags =
|
||||
|
||||
extra_install = $(plug_in_name)_audio
|
||||
|
||||
COREPATH ?=../../core
|
||||
include $(COREPATH)/plug-in/Makefile.app_module
|
||||
@ -0,0 +1,25 @@
|
||||
announce_path=/usr/local/lib/sems/audio/
|
||||
default_announce=default_en.wav
|
||||
beep=/usr/local/lib/sems/audio/beep.wav
|
||||
|
||||
# prompts
|
||||
|
||||
#"Welcome to iptel dot org voip service."
|
||||
welcome=/usr/local/lib/sems/audio/annrecorder/welcome.wav
|
||||
|
||||
# "Your auto attendant greeting sounds like this: -"
|
||||
your_prompt=/usr/local/lib/sems/audio/annrecorder/your_prompt.wav
|
||||
|
||||
# "To record a new auto attendant greeting, press any key.
|
||||
# End recording with any key. -"
|
||||
to_record=/usr/local/lib/sems/audio/annrecorder/to_record.wav
|
||||
|
||||
# "Press one to keep the new greeting, or two to record a new one. -"
|
||||
confirm=/usr/local/lib/sems/audio/annrecorder/confirm.wav
|
||||
|
||||
# "Your new auto attendant greeting has been set."
|
||||
greeting_set=/usr/local/lib/sems/audio/annrecorder/greeting_set.wav
|
||||
|
||||
# "Thank you for using the iptel dot org service. Good Bye. - "
|
||||
bye=/usr/local/lib/sems/audio/annrecorder/bye.wav
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in new issue