From a15202f0d216f959e463386a2b7e130c5244465f Mon Sep 17 00:00:00 2001 From: Juha Heinanen Date: Tue, 12 Feb 2008 02:59:53 +0000 Subject: [PATCH] * Added MYSQL support to early announce application. git-svn-id: http://svn.berlios.de/svnroot/repos/sems/trunk@719 8eb893ce-cfd4-0310-b710-fb5ebe64c474 --- apps/early_announce/EarlyAnnounce.cpp | 186 +++++++++++++++++++++++++- apps/early_announce/EarlyAnnounce.h | 14 +- doc/Readme.early_announce | 81 ++++++++++- 3 files changed, 271 insertions(+), 10 deletions(-) diff --git a/apps/early_announce/EarlyAnnounce.cpp b/apps/early_announce/EarlyAnnounce.cpp index 0820a1b3..387be796 100644 --- a/apps/early_announce/EarlyAnnounce.cpp +++ b/apps/early_announce/EarlyAnnounce.cpp @@ -2,6 +2,7 @@ * $Id$ * * Copyright (C) 2002-2003 Fhg Fokus + * Copyright (C) 2008 Juha Heinanen (USE_MYSQL parts) * * This file is part of sems, a free SIP media server. * @@ -34,16 +35,100 @@ #define MOD_NAME "early_announce" +#ifdef USE_MYSQL +#include +#include +#define DEFAULT_AUDIO_TABLE "default_audio" +#define DOMAIN_AUDIO_TABLE "domain_audio" +#define USER_AUDIO_TABLE "user_audio" +#endif + EXPORT_SESSION_FACTORY(EarlyAnnounceFactory,MOD_NAME); +#ifdef USE_MYSQL +string EarlyAnnounceFactory::AnnounceApplication; +string EarlyAnnounceFactory::AnnounceMessage; +string EarlyAnnounceFactory::DefaultLanguage; +#else string EarlyAnnounceFactory::AnnouncePath; string EarlyAnnounceFactory::AnnounceFile; +#endif EarlyAnnounceFactory::EarlyAnnounceFactory(const string& _app_name) : AmSessionFactory(_app_name) { } +#ifdef USE_MYSQL +mysqlpp::Connection EarlyAnnounceFactory::Connection(mysqlpp::use_exceptions); + +int get_announce_msg(string application, string message, string user, + string domain, string language, string *audio_file) +{ + string query_string; + + if (!user.empty()) { + *audio_file = string("/tmp/") + application + "_" + + message + "_" + domain + "_" + user + ".wav"; + query_string = "select audio from " + string(USER_AUDIO_TABLE) + + " where application='" + application + "' and message='" + + message + "' and userid='" + user + "' and domain='" + + domain + "'"; + } else if (!domain.empty()) { + *audio_file = string("/tmp/") + application + "_" + + message + "_" + domain + "_" + language + ".wav"; + query_string = "select audio from " + string(DOMAIN_AUDIO_TABLE) + + " where application='" + application + "' and message='" + + message + "' and domain='" + domain + "' and language='" + + language + "'"; + } else { + *audio_file = string("/tmp/") + application + "_" + + message + "_" + language + ".wav"; + query_string = "select audio from " + string(DEFAULT_AUDIO_TABLE) + + " where application='" + application + "' and message='" + + message + "' and language='" + language + "'"; + } + + try { + + mysqlpp::Query query = EarlyAnnounceFactory::Connection.query(); + + DBG("Query string <%s>\n", query_string.c_str()); + + query << query_string; + mysqlpp::Result res = query.store(); + + mysqlpp::Row row; + + if (res) { + if ((res.num_rows() > 0) && (row = res.at(0))) { + FILE *file; + unsigned long length = row.raw_string(0).size(); + file = fopen((*audio_file).c_str(), "wb"); + fwrite(row.at(0).data(), 1, length, file); + fclose(file); + return 1; + } else { + *audio_file = ""; + return 1; + } + } else { + ERROR("Database query error\n"); + *audio_file = ""; + return 0; + } + } + + catch (const mysqlpp::Exception& er) { + // Catch-all for any MySQL++ exceptions + ERROR("MySQL++ error: %s\n", er.what()); + *audio_file = ""; + return 0; + } +} + +#endif + int EarlyAnnounceFactory::onLoad() { AmConfigReader cfg; @@ -53,6 +138,79 @@ int EarlyAnnounceFactory::onLoad() // get application specific global parameters configureModule(cfg); +#ifdef USE_MYSQL + + /* Get default audio from MySQL */ + + string mysql_server, mysql_user, mysql_passwd, mysql_db; + + mysql_server = cfg.getParameter("mysql_server"); + if (mysql_server.empty()) { + mysql_server = "localhost"; + } + + mysql_user = cfg.getParameter("mysql_user"); + if (mysql_user.empty()) { + ERROR("conference.conf paramater 'mysql_user' is missing.\n"); + return -1; + } + + mysql_passwd = cfg.getParameter("mysql_passwd"); + if (mysql_passwd.empty()) { + ERROR("conference.conf paramater 'mysql_passwd' is missing.\n"); + return -1; + } + + mysql_db = cfg.getParameter("mysql_db"); + if (mysql_db.empty()) { + mysql_db = "sems"; + } + + AnnounceApplication = cfg.getParameter("application"); + if (AnnounceApplication.empty()) { + AnnounceApplication = MOD_NAME; + } + + AnnounceMessage = cfg.getParameter("message"); + if (AnnounceMessage.empty()) { + AnnounceMessage = "greeting_msg"; + } + + DefaultLanguage = cfg.getParameter("default_language"); + if (DefaultLanguage.empty()) { + DefaultLanguage = "en"; + } + + try { + + Connection.connect(mysql_db.c_str(), mysql_server.c_str(), + mysql_user.c_str(), mysql_passwd.c_str()); + if (!Connection) { + ERROR("Database connection failed: %s\n", Connection.error()); + return -1; + } + } + + catch (const mysqlpp::Exception& er) { + // Catch-all for any MySQL++ exceptions + ERROR("MySQL++ error: %s\n", er.what()); + return -1; + } + + string announce_file; + if (!get_announce_msg(AnnounceApplication, AnnounceMessage, "", "", + DefaultLanguage, &announce_file)) { + return -1; + } + if (announce_file.empty()) { + ERROR("default announce for " MOD_NAME " module does not exist.\n"); + return -1; + } + +#else + + /* Get default audio from file system */ + AnnouncePath = cfg.getParameter("announce_path",ANNOUNCE_PATH); if( !AnnouncePath.empty() && AnnouncePath[AnnouncePath.length()-1] != '/' ) @@ -67,6 +225,8 @@ int EarlyAnnounceFactory::onLoad() return -1; } +#endif + return 0; } @@ -99,6 +259,26 @@ void EarlyAnnounceDialog::onInvite(const AmSipRequest& req) AmSession* EarlyAnnounceFactory::onInvite(const AmSipRequest& req) { + +#ifdef USE_MYSQL + + string iptel_app_param = getHeader(req.hdrs, PARAM_HDR); + string language = get_header_keyvalue(iptel_app_param,"Language"); + string announce_file = ""; + + if (language.empty()) language = DefaultLanguage; + + get_announce_msg(AnnounceApplication, AnnounceMessage, req.user, + req.domain, "", &announce_file); + if (!announce_file.empty()) goto end; + get_announce_msg(AnnounceApplication, AnnounceMessage, "", req.domain, + language, &announce_file); + if (!announce_file.empty()) goto end; + get_announce_msg(AnnounceApplication, AnnounceMessage, "", "", language, + &announce_file); + +#else + string announce_path = AnnouncePath; string announce_file = announce_path + req.domain + "/" + req.user + ".wav"; @@ -113,7 +293,9 @@ AmSession* EarlyAnnounceFactory::onInvite(const AmSipRequest& req) goto end; announce_file = AnnouncePath + AnnounceFile; - + +#endif + end: return new EarlyAnnounceDialog(announce_file); } @@ -175,7 +357,6 @@ void EarlyAnnounceDialog::process(AmEvent* event) if (code.length() && str2i(code, code_i)) { ERROR("while parsing P-Final-Reply-Code\n"); } - string h_reason = getHeader(localreq.hdrs,"P-Final-Reply-Reason"); if (h_reason.length()) { INFO("Use of P-Final-Reply-Code/P-Final-Reply-Reason is deprecated. "); @@ -195,4 +376,3 @@ void EarlyAnnounceDialog::process(AmEvent* event) AmSession::process(event); } - diff --git a/apps/early_announce/EarlyAnnounce.h b/apps/early_announce/EarlyAnnounce.h index 1f97e0aa..40756e70 100644 --- a/apps/early_announce/EarlyAnnounce.h +++ b/apps/early_announce/EarlyAnnounce.h @@ -28,8 +28,11 @@ #ifndef _EarlyAnnounce_h_ #define _EarlyAnnounce_h_ +#ifdef USE_MYSQL +#include +#endif + #include "AmSession.h" -#include "AmAudioFile.h" #include "AmConfigReader.h" #include @@ -39,8 +42,16 @@ using std::string; class EarlyAnnounceFactory: public AmSessionFactory { public: + +#ifdef USE_MYSQL + static mysqlpp::Connection Connection; + static string AnnounceApplication; + static string AnnounceMessage; + static string DefaultLanguage; +#else static string AnnouncePath; static string AnnounceFile; +#endif EarlyAnnounceFactory(const string& _app_name); @@ -66,6 +77,7 @@ public: void onDtmf(int event, int duration_msec) {} void process(AmEvent* event); + }; #endif diff --git a/doc/Readme.early_announce b/doc/Readme.early_announce index 8a3944d8..bb072610 100644 --- a/doc/Readme.early_announce +++ b/doc/Readme.early_announce @@ -15,20 +15,89 @@ Session Parameters: Final-Reply-Code integer (e.g. Final-Reply-Code=405 ) Final-Reply-Reason string (e.g. Final-Reply-Reason=Prohibited) - - -It searches for files to play following these rules: +If early_announce application was compiled WITHOUT -DUSE_MYSQL option, +it searches for files to play following these rules: 1) [AnnouncePath]/[Domain]/[User].wav 2) [AnnouncePath]/[User].wav -example sems (early_announce.conf) configuration: +Example sems (early_announce.conf) configuration for file system audio: announce_path=wav/ default_announce=default_en.wav - -example ser configuration: +If early_announce application was compiled with -DUSE_MYSQL option, it +support third Session Parameter + + Language two letter string or empty string (e.g. en) + +It searches files to play first from user_audio, then from domain_audio, +and finally from default_audio tables (described below). When an audio +file is fetched from database, it is stored in /tmp directory. + +Example sems (early_announce.conf) configuration for MySQL audio: + +# Host where MySQL server is running (optional, defaults to 'localhost') +mysql_host=localhost + +# MySQL username (mandatory, no default) +mysql_user=sems + +# MySQL password (mandatory, no default) +mysql_passwd=secret + +# Database where audio is stored (optional, defaults to 'sems') +mysql_db=sems + +# Value of 'application' field in early_announce audio records (optional, +# defaults to 'early_announce') +application=early_announce + +# Value of 'message' field in early_announce audio records (optional, +# defaults to 'greeting_msg') +message=greeting_msg + +# Default language if Language Session Parameter does not exist +# (optional, defaults to 'en') +default_language=en + +Database tables: + +CREATE TABLE default_audio ( + id int(10) unsigned NOT NULL auto_increment, + application varchar(32) NOT NULL, + message varchar(32) NOT NULL, + `language` char(2) NOT NULL default 'en', + audio mediumblob NOT NULL, + PRIMARY KEY (id), + UNIQUE KEY application (application,message,`language`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +CREATE TABLE domain_audio ( + id int(10) unsigned NOT NULL auto_increment, + application varchar(32) NOT NULL, + message varchar(32) NOT NULL, + domain varchar(128) NOT NULL, + `language` char(2) NOT NULL default 'en', + audio mediumblob NOT NULL, + PRIMARY KEY (id), + UNIQUE KEY application (application,message,domain,`language`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +CREATE TABLE user_audio ( + id int(10) unsigned NOT NULL auto_increment, + application varchar(32) NOT NULL, + message varchar(32) NOT NULL, + domain varchar(128) NOT NULL, + userid varchar(64) NOT NULL, + audio mediumblob NOT NULL, + PRIMARY KEY (id), + UNIQUE KEY application (application,message,domain,userid) +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + + +Example ser configuration: +------------------------- # # simple single instance Ser config script with early media