From 9152aad8ffb672acdced9a5153e9923a4462fcab Mon Sep 17 00:00:00 2001 From: Stefan Sayer Date: Wed, 19 Mar 2008 13:39:00 +0000 Subject: [PATCH] precoded file support and sample announcement application git-svn-id: http://svn.berlios.de/svnroot/repos/sems/trunk@820 8eb893ce-cfd4-0310-b710-fb5ebe64c474 --- apps/precoded_announce/Makefile | 7 + apps/precoded_announce/PrecodedAnnounce.cpp | 94 ++++++++ apps/precoded_announce/PrecodedAnnounce.h | 64 ++++++ apps/precoded_announce/etc/precoded.conf | 4 + apps/precoded_announce/wav/test.predef | 11 + core/AmPrecodedFile.cpp | 229 ++++++++++++++++++++ core/AmPrecodedFile.h | 115 ++++++++++ 7 files changed, 524 insertions(+) create mode 100644 apps/precoded_announce/Makefile create mode 100644 apps/precoded_announce/PrecodedAnnounce.cpp create mode 100644 apps/precoded_announce/PrecodedAnnounce.h create mode 100644 apps/precoded_announce/etc/precoded.conf create mode 100644 apps/precoded_announce/wav/test.predef create mode 100644 core/AmPrecodedFile.cpp create mode 100644 core/AmPrecodedFile.h diff --git a/apps/precoded_announce/Makefile b/apps/precoded_announce/Makefile new file mode 100644 index 00000000..b5176b74 --- /dev/null +++ b/apps/precoded_announce/Makefile @@ -0,0 +1,7 @@ +plug_in_name = precoded_announce + +module_ldflags = +module_cflags = -DMOD_NAME=\"$(plug_in_name)\" + +COREPATH ?=../../core +include $(COREPATH)/plug-in/Makefile.app_module diff --git a/apps/precoded_announce/PrecodedAnnounce.cpp b/apps/precoded_announce/PrecodedAnnounce.cpp new file mode 100644 index 00000000..ee2c4f3d --- /dev/null +++ b/apps/precoded_announce/PrecodedAnnounce.cpp @@ -0,0 +1,94 @@ +/* + * $Id: AmUtils.h 744 2008-02-21 18:40:01Z sayer $ + * + * Copyright (C) 2008 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 ser 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 "PrecodedAnnounce.h" + +#include "log.h" +#include "AmConfigReader.h" +#include "AmUtils.h" + +EXPORT_SESSION_FACTORY(PrecodedFactory,MOD_NAME); + +PrecodedFactory::PrecodedFactory(const string& _app_name) + : AmSessionFactory(_app_name) +{ +} + +int PrecodedFactory::onLoad() +{ + AmConfigReader cfg; + if(cfg.loadFile(AmConfig::ModConfigPath + string(MOD_NAME ".conf"))) + return -1; + + if (precoded_file.open(cfg.getParameter("announcement_file")) < 0) { + ERROR("loading precoded file"); + return -1; + } + + AmPrecodedFile::initPrecodedCodec(); + + return 0; +} + +AmSession* PrecodedFactory::onInvite(const AmSipRequest& req) +{ + return new PrecodedDialog(&precoded_file); +} + +PrecodedDialog::PrecodedDialog(AmPrecodedFile* file_def) + : file_def(file_def) +{ +} + +PrecodedDialog::~PrecodedDialog() +{ +} + +AmPayloadProviderInterface* PrecodedDialog::getPayloadProvider() { + return file_def; +} + +void PrecodedDialog::onSessionStart(const AmSipRequest& req) +{ + + AmPrecodedFileInstance* file = file_def->getFileInstance(rtp_str.getCurrentPayload(), + m_payloads); + if (!file || file->open()) + throw string("PrecodedDialog::onSessionStart: Cannot open file\n"); + + rtp_str.setFormat(file->getRtpFormat()); + + setOutput(file); + setReceiving(false); +} + +void PrecodedDialog::onBye(const AmSipRequest& req) +{ + DBG("onBye: stopSession\n"); + setStopped(); +} + diff --git a/apps/precoded_announce/PrecodedAnnounce.h b/apps/precoded_announce/PrecodedAnnounce.h new file mode 100644 index 00000000..46d7cc11 --- /dev/null +++ b/apps/precoded_announce/PrecodedAnnounce.h @@ -0,0 +1,64 @@ +/* + * $Id: AmUtils.h 744 2008-02-21 18:40:01Z sayer $ + * + * Copyright (C) 2008 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 ser 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 _PRECODEDANNOUNCEAPP_H_ +#define _PRECODEDANNOUNCEAPP_H_ + +#include "AmSession.h" +#include "AmPrecodedFile.h" + +#include +using std::string; + +class PrecodedFactory: public AmSessionFactory +{ +public: + AmPrecodedFile precoded_file; + + PrecodedFactory(const string& _app_name); + + int onLoad(); + AmSession* onInvite(const AmSipRequest& req); +}; + +class PrecodedDialog : public AmSession +{ + + AmPrecodedFile* file_def; + + public: + PrecodedDialog(AmPrecodedFile* file_def); + ~PrecodedDialog(); + + void onSessionStart(const AmSipRequest& req); + void onBye(const AmSipRequest& req); + + AmPayloadProviderInterface* getPayloadProvider(); +}; + +#endif + diff --git a/apps/precoded_announce/etc/precoded.conf b/apps/precoded_announce/etc/precoded.conf new file mode 100644 index 00000000..7b72d7c4 --- /dev/null +++ b/apps/precoded_announce/etc/precoded.conf @@ -0,0 +1,4 @@ +# file played (predef definition file only, which references +# the actual audio files for the payloads) +# +announcement_file=/usr/local/lib/sems/audio/precoded_announce/test.predef diff --git a/apps/precoded_announce/wav/test.predef b/apps/precoded_announce/wav/test.predef new file mode 100644 index 00000000..c119db09 --- /dev/null +++ b/apps/precoded_announce/wav/test.predef @@ -0,0 +1,11 @@ +# format: +# codec id;payload name;samplerate;channels;format parameters;frame milliseconds;frame bytes;filename (full path) +# +# +0;PCMU;8000;1;;20;160;test8k.pcmu; +8;PCMA;8000;1;;20;160;test8k.pcma; +96;iLBC;8000;1;;30;50;test8k.ilbc30; +97;iLBC;8000;1;mode=30;30;50;test8k.ilbc30; +98;iLBC;8000;1;mode=20;20;33;test8k.ilbc20; + + diff --git a/core/AmPrecodedFile.cpp b/core/AmPrecodedFile.cpp new file mode 100644 index 00000000..835b33e7 --- /dev/null +++ b/core/AmPrecodedFile.cpp @@ -0,0 +1,229 @@ +/* + * $Id: AmUtils.h 744 2008-02-21 18:40:01Z sayer $ + * + * Copyright (C) 2008 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 ser 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 "AmPrecodedFile.h" +#include "AmUtils.h" +#include "log.h" +#include + +unsigned int precoded_bytes2samples(long h_codec, unsigned int num_bytes) { + return num_bytes; +} + +unsigned int precoded_samples2bytes(long h_codec, unsigned int num_samples) { + return num_samples; +} + +amci_codec_t _codec_precoded = { + PRECODED_CODEC_ID, + NULL, + NULL, + NULL, + NULL, + NULL, + precoded_bytes2samples, + precoded_samples2bytes +}; + + +void AmPrecodedFile::initPrecodedCodec() { + AmPlugIn::instance()->addCodec(&_codec_precoded); +} + +AmPrecodedRtpFormat::AmPrecodedRtpFormat(precoded_payload_t& precoded_payload, + const vector& payloads) + : AmAudioRtpFormat(payloads), precoded_payload(precoded_payload) +{ + channels = precoded_payload.channels; + rate = precoded_payload.sample_rate; + // frame_size is in samples, precoded_payload.frame_size in millisec + frame_size = precoded_payload.frame_ms * precoded_payload.sample_rate / 1000; + // fill unused stuff + frame_length = precoded_payload.frame_ms; + frame_encoded_size = precoded_payload.frame_bytes; +} + +AmPrecodedRtpFormat::~AmPrecodedRtpFormat() { +} + +int AmPrecodedRtpFormat::getCodecId() { + return PRECODED_CODEC_ID; +} + + +AmPrecodedFileFormat::AmPrecodedFileFormat(precoded_payload_t& precoded_payload) + : AmAudioFileFormat(""), precoded_payload(precoded_payload) { + subtype.type = 0; + subtype.name = precoded_payload.name; + subtype.sample_rate = precoded_payload.sample_rate; + subtype.channels = precoded_payload.channels; + subtype.codec_id = PRECODED_CODEC_ID; + + channels = precoded_payload.channels; + rate = precoded_payload.sample_rate; + codec = getCodec(); +} + +AmPrecodedFileFormat::~AmPrecodedFileFormat() { +} + +int AmPrecodedFileFormat::getCodecId() { + return PRECODED_CODEC_ID; +} + +int precoded_file_open(FILE* fp, struct amci_file_desc_t* fmt_desc, int options, long h_codec) +{ + fseek (fp, 0, SEEK_END); + fmt_desc->data_size=ftell (fp); + rewind(fp); + DBG("file opened, size = %d\n", fmt_desc->data_size); + return 0; +} + +int precoded_file_close(FILE* fp, struct amci_file_desc_t* fmt_desc, int options, + long h_codec, struct amci_codec_t *codec) +{ + DBG("file closed\n"); + return 0; +} + +AmPrecodedFileInstance::AmPrecodedFileInstance(precoded_payload_t& precoded_payload, + const vector& payloads) + : precoded_payload(precoded_payload), payloads(payloads) +{ + memset(&m_iofmt, 0, sizeof(amci_inoutfmt_t)); + m_iofmt.open = &precoded_file_open; + m_iofmt.on_close = &precoded_file_close; + iofmt = &m_iofmt; +} + +AmPrecodedFileInstance::~AmPrecodedFileInstance(){ +} + +AmAudioFileFormat* AmPrecodedFileInstance::fileName2Fmt(const string& name) { + return new AmPrecodedFileFormat(precoded_payload); +} + +int AmPrecodedFileInstance::open() { + return AmAudioFile::open(precoded_payload.filename, AmAudioFile::Read); +} + +AmPrecodedRtpFormat* AmPrecodedFileInstance::getRtpFormat() { + return new AmPrecodedRtpFormat(precoded_payload, payloads); +} + +AmPrecodedFile::AmPrecodedFile() +{ +} + +AmPrecodedFile::~AmPrecodedFile() { +} + +int AmPrecodedFile::open(std::string filename) { + std::ifstream ifs(filename.c_str()); + if (!ifs.good()) { + return -1; + } + + while (ifs.good() && !ifs.eof()) { + string codec_line; + getline(ifs, codec_line); + if (!codec_line.length() || codec_line[0]=='#') + continue; + + vector codec_def = explode(codec_line, ";"); + if (codec_def.size() != 8) { + ERROR("unable to decipher codec line '%s'\n", + codec_line.c_str()); + continue; + } + + precoded_payload_t pl; + +#define get_uint_item(name, index, description) \ + unsigned int name; \ + if (str2i(codec_def[index], name)) { \ + ERROR("decoding " description " in codec line '%s'\n", \ + codec_line.c_str()); \ + continue; \ + } \ + pl.name = name; + + get_uint_item(payload_id, 0, "payload_id"); + pl.c_name = codec_def[1]; + pl.name = pl.c_name.c_str(); + get_uint_item(sample_rate, 2, "sample_rate"); + get_uint_item(channels, 3, "channels"); + pl.format_parameters = codec_def[4]; + get_uint_item(frame_ms, 5, "frame ms"); + get_uint_item(frame_bytes, 6, "frame bytes"); + pl.filename=codec_def[7]; +#undef get_uint_item + + DBG("inserting codec '%s' file '%s' and id %d\n", + pl.name, pl.filename.c_str(), pl.payload_id); + payloads[pl.payload_id]=pl; + } + + return 0; // OK +} + +amci_payload_t* AmPrecodedFile::payload(int payload_id) { + std::map::iterator it = + payloads.find(payload_id); + + if(it != payloads.end()) + return &it->second; + + return NULL; +} + +int AmPrecodedFile::getDynPayload(const string& name, int rate, int encoding_param) { + // find a dynamic payload by name/rate and encoding_param (channels, if > 0) + for(std::map::const_iterator pl_it = payloads.begin(); + pl_it != payloads.end(); ++pl_it) + if( (name == pl_it->second.name) + && (rate == pl_it->second.sample_rate) ) { + if ((encoding_param > 0) && (pl_it->second.channels > 0) && + (encoding_param != pl_it->second.channels)) + continue; + + return pl_it->first; + } + + // not found + return -1; +} + +AmPrecodedFileInstance* AmPrecodedFile::getFileInstance(int payload_id, + const vector& m_payloads) { + std::map::iterator it=payloads.find(payload_id); + if (it != payloads.end()) + return new AmPrecodedFileInstance(it->second, m_payloads); + + return NULL; +} diff --git a/core/AmPrecodedFile.h b/core/AmPrecodedFile.h new file mode 100644 index 00000000..13e7b71c --- /dev/null +++ b/core/AmPrecodedFile.h @@ -0,0 +1,115 @@ +/* + * $Id: AmUtils.h 744 2008-02-21 18:40:01Z sayer $ + * + * Copyright (C) 2008 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 ser 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 _AmPrecodedFile_H +#define _AmPrecodedFile_H + +#include "AmPlugIn.h" +#include "AmSdp.h" +#include "amci/amci.h" +#include "AmAudioFile.h" +#include "AmAudio.h" + +#include +#include + +#define PRECODED_CODEC_ID 100 // could go into amci/codecs.h + +struct precoded_payload_t : public amci_payload_t { + public: + string c_name; + string format_parameters; + unsigned int frame_ms; + unsigned int frame_bytes; + string filename; +}; + +class AmPrecodedFileFormat : public AmAudioFileFormat { + + precoded_payload_t& precoded_payload; + amci_subtype_t subtype; + + public: + AmPrecodedFileFormat(precoded_payload_t& precoded_payload); + ~AmPrecodedFileFormat(); + amci_subtype_t* getSubtype() { return &subtype; } + + protected: + virtual int getCodecId(); +}; + +class AmPrecodedRtpFormat : public AmAudioRtpFormat { + precoded_payload_t& precoded_payload; + + public: + AmPrecodedRtpFormat(precoded_payload_t& precoded_payload, + const vector& payloads); + ~AmPrecodedRtpFormat(); + + protected: + int getCodecId(); +}; + +class AmPrecodedFileInstance +: public AmAudioFile { + + precoded_payload_t& precoded_payload; + const vector& payloads; + amci_inoutfmt_t m_iofmt; + + public: + AmPrecodedFileInstance(precoded_payload_t& precoded_payload, + const vector& payloads); + ~AmPrecodedFileInstance(); + + AmPrecodedRtpFormat* getRtpFormat(); + + int open(); + + protected: + AmAudioFileFormat* fileName2Fmt(const string& name); +}; + +class AmPrecodedFile +: public AmPayloadProviderInterface { + + std::map payloads; + + public: + AmPrecodedFile(); + ~AmPrecodedFile(); + static void initPrecodedCodec(); + + int open(std::string filename); + + amci_payload_t* payload(int payload_id); + int getDynPayload(const string& name, int rate, int encoding_param); + + AmPrecodedFileInstance* getFileInstance(int payload_id, const vector& m_payloads); +}; + +#endif