From f8a1595b61f23e7cfce3addab7cb563ec776feee Mon Sep 17 00:00:00 2001 From: paulc Date: Tue, 21 Dec 2004 04:16:09 +0000 Subject: [PATCH] Added final parameter to disconnect. Renamed most messages. Version header file is generated at configure time. Added soname in library. Proper handling of DTMF in IAX, H.323 and Zap. git-svn-id: http://yate.null.ro/svn/yate/trunk@133 acf43c95-373e-0410-b603-e72c3f656dc1 --- .cvsignore | 1 + Makefile.in | 15 +++-- clients/main-gtk.cpp | 6 +- configure.in | 11 +++- engine/DataBlock.cpp | 8 +-- engine/Engine.cpp | 2 +- modules/Makefile.in | 4 +- modules/cdrbuild.cpp | 75 ++++++++++++++--------- modules/cdrfile.cpp | 6 +- modules/cdrpgsql.cpp | 8 ++- modules/extmodule.cpp | 8 +-- modules/faxchan.cpp | 12 ++-- modules/h323chan.cpp | 133 ++++++++++++++++++++++++++++++++--------- modules/iaxchan.cpp | 96 ++++++++++++++--------------- modules/osschan.cpp | 19 +++--- modules/pgsqlroute.cpp | 6 +- modules/regexroute.cpp | 4 +- modules/regfile.cpp | 28 ++++++--- modules/register.cpp | 10 ++-- modules/rmanager.cpp | 10 ++-- modules/tonegen.cpp | 18 +++--- modules/wavefile.cpp | 95 ++++++++++++++++++++++------- modules/zapchan.cpp | 110 +++++++++++++++++++++++++++------- scripts/dtmf1.pl | 4 +- scripts/noroute.pl | 2 +- scripts/route.php | 6 +- yatengine.h | 7 +++ yatephone.h | 7 ++- yateversn.h.in | 15 +++++ 29 files changed, 501 insertions(+), 225 deletions(-) create mode 100644 yateversn.h.in diff --git a/.cvsignore b/.cvsignore index 22e3019c..ef049d01 100644 --- a/.cvsignore +++ b/.cvsignore @@ -3,6 +3,7 @@ Makefile configure config.* yatepaths.h +yateversn.h run yate.spec yate diff --git a/Makefile.in b/Makefile.in index ed64dfba..494be152 100644 --- a/Makefile.in +++ b/Makefile.in @@ -12,7 +12,7 @@ SED := sed DEFS := LIBAUX:= -ldl LIBTHR:= -lpthread -INCLUDES := -I@srcdir@ +INCLUDES := -I. -I@srcdir@ CFLAGS := -O2 @MODULE_CFLAGS@ @INLINE_FLAGS@ LDFLAGS:= LDCONFIG:=true @@ -20,7 +20,8 @@ LDCONFIG:=true MKDEPS := ./config.status PROGS:= yate SLIBS:= libyate.so -INCS := telengine.h telephony.h yateversn.h +INCS := telengine.h telephony.h +GENS := yateversn.h LIBS := MAN8 := yate.8 DOCS := README COPYING ChangeLog @@ -126,6 +127,9 @@ install install-root: all apidocs for i in $(INCS) ; do \ install -m 0644 @srcdir@/$$i "$(DESTDIR)$(incdir)/" ; \ done + for i in $(GENS) ; do \ + install -m 0644 $$i "$(DESTDIR)$(incdir)/" ; \ + done @mkdir -p "$(DESTDIR)$(docdir)/api/" && \ for i in $(DOCS) ; do \ install -m 0644 @srcdir@/$$i "$(DESTDIR)$(docdir)/" ; \ @@ -144,7 +148,7 @@ uninstall uninstall-root: done @-rm "$(DESTDIR)$(libdir)/pkgconfig/yate.pc" && \ rmdir $(DESTDIR)$(libdir)/pkgconfig - @-for i in $(INCS) ; do \ + @-for i in $(INCS) $(GENS) ; do \ rm "$(DESTDIR)$(incdir)/$$i" ; \ done; \ rmdir "$(DESTDIR)$(incdir)" @@ -183,6 +187,7 @@ snapshot tarball: check-topdir clean tables apidocs --exclude $$wd/yate-config \ --exclude $$wd/yate.pc \ --exclude $$wd/yatepaths.h \ + --exclude $$wd/yateversn.h \ -X $$wd/tar-exclude \ $$wd; \ rm $$wd/tar-exclude @@ -191,7 +196,7 @@ snapshot tarball: check-topdir clean tables apidocs check-topdir: @test -f configure || (echo "Must make this target in the top source directory"; exit 1) -Engine.o: @srcdir@/Engine.cpp $(MKDEPS) @srcdir@/telengine.h @srcdir@/yateversn.h yatepaths.h +Engine.o: @srcdir@/Engine.cpp $(MKDEPS) @srcdir@/telengine.h yateversn.h yatepaths.h $(COMPILE) -c $< DataBlock.o: @srcdir@/DataBlock.cpp $(MKDEPS) @srcdir@/telengine.h @srcdir@/telephony.h @@ -213,7 +218,7 @@ yate: $(OBJS) libyate.so $(LIBS) $(LINK) -o $@ $(LIBTHR) $^ libyate.so: $(ENGOBJS) $(LIBS) - $(LINK) -shared -o $@ $(LIBTHR) $^ $(LIBAUX) + $(LINK) -shared -o $@ -Wl,--soname=$@ $(LIBTHR) $^ $(LIBAUX) .PHONY: help help: diff --git a/clients/main-gtk.cpp b/clients/main-gtk.cpp index 1637a230..40bf503f 100644 --- a/clients/main-gtk.cpp +++ b/clients/main-gtk.cpp @@ -445,7 +445,7 @@ void GtkClient::gtk_call (GtkWidget *button, gpointer data) { case STATUS_IDLE: { - Message m("call"); + Message m("call.execute"); gchar *address = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(s_client->m_address)->entry)); if (::strchr(address,'/')) m.addParam("direct",address); @@ -475,7 +475,7 @@ void GtkClient::gtk_hangup (GtkWidget *button, gpointer data) break; case STATUS_RINGOUT: case STATUS_INCALL: - Message m("drop"); + Message m("call.drop"); m.addParam("id","oss/"); Engine::dispatch(m); break; @@ -538,7 +538,7 @@ class GtkClientHandler : public MessageHandler { public: GtkClientHandler(int prio) - : MessageHandler("route",prio) { } + : MessageHandler("call.route",prio) { } virtual bool received(Message &msg); }; diff --git a/configure.in b/configure.in index 907c1b49..128fa3f8 100644 --- a/configure.in +++ b/configure.in @@ -1,8 +1,16 @@ # Process this file with autoconf to produce a configure script. -AC_INIT(YATE, 0.8.5) +AC_INIT(YATE, 0.8.6) AC_CONFIG_SRCDIR([README]) AC_PREREQ(2.52) +PACKAGE_VERSION_MAJOR="${PACKAGE_VERSION%%.*}" +PACKAGE_VERSION_MINOR="${PACKAGE_VERSION#*.}" +PACKAGE_VERSION_MINOR="${PACKAGE_VERSION_MINOR%.*}" +PACKAGE_VERSION_BUILD="${PACKAGE_VERSION##*.}" +AC_SUBST(PACKAGE_VERSION_MAJOR) +AC_SUBST(PACKAGE_VERSION_MINOR) +AC_SUBST(PACKAGE_VERSION_BUILD) + # Checks for programs. AC_PROG_CXX AC_PROG_CC @@ -466,6 +474,7 @@ AC_SUBST(MODULE_SYMBOLS) AC_CONFIG_FILES([yate.spec yate.pc + yateversn.h Makefile modules/Makefile scripts/Makefile diff --git a/engine/DataBlock.cpp b/engine/DataBlock.cpp index 72c9f02f..f5ed0785 100644 --- a/engine/DataBlock.cpp +++ b/engine/DataBlock.cpp @@ -314,7 +314,7 @@ DataSource::~DataSource() DataEndpoint::~DataEndpoint() { - disconnect(); + disconnect(true,0); setSource(); setConsumer(); } @@ -354,7 +354,7 @@ bool DataEndpoint::connect(DataEndpoint *peer) return true; } -void DataEndpoint::disconnect(const char *reason) +void DataEndpoint::disconnect(bool final, const char *reason) { if (!m_peer) return; @@ -373,7 +373,7 @@ void DataEndpoint::disconnect(const char *reason) m_peer = 0; temp->setPeer(0,reason); temp->deref(); - disconnected(reason); + disconnected(final,reason); deref(); } @@ -383,7 +383,7 @@ void DataEndpoint::setPeer(DataEndpoint *peer, const char *reason) if (m_peer) connected(); else - disconnected(reason); + disconnected(false,reason); } void DataEndpoint::setSource(DataSource *source) diff --git a/engine/Engine.cpp b/engine/Engine.cpp index 7197b08d..d579f5e7 100644 --- a/engine/Engine.cpp +++ b/engine/Engine.cpp @@ -164,7 +164,7 @@ public: class EngineStatusHandler : public MessageHandler { public: - EngineStatusHandler() : MessageHandler("status",0) { } + EngineStatusHandler() : MessageHandler("engine.status",0) { } virtual bool received(Message &msg); }; diff --git a/modules/Makefile.in b/modules/Makefile.in index 56f3732e..e98744f6 100644 --- a/modules/Makefile.in +++ b/modules/Makefile.in @@ -10,12 +10,12 @@ DEBUG := CXX := @CXX@ -Wall SED := sed DEFS := -INCLUDES := -I@top_srcdir@ +INCLUDES := -I.. -I@top_srcdir@ CFLAGS := -O2 @MODULE_CFLAGS@ @INLINE_FLAGS@ LDFLAGS:= -L.. -lyate MODFLAGS:= @MODULE_LDFLAGS@ MODSTRIP:= @MODULE_SYMBOLS@ -INCFILES := @top_srcdir@/telengine.h @top_srcdir@/telephony.h @top_srcdir@/yateversn.h +INCFILES := @top_srcdir@/telengine.h @top_srcdir@/telephony.h ../yateversn.h SUBDIRS := MKDEPS := ../config.status diff --git a/modules/cdrbuild.cpp b/modules/cdrbuild.cpp index 36f458db..79974979 100644 --- a/modules/cdrbuild.cpp +++ b/modules/cdrbuild.cpp @@ -52,7 +52,7 @@ private: class StatusHandler : public MessageHandler { public: - StatusHandler() : MessageHandler("status") { } + StatusHandler() : MessageHandler("engine.status") { } virtual bool received(Message &msg); }; @@ -67,6 +67,7 @@ public: String getStatus() const; static CdrBuilder *find(String &id); private: + void emit(const char *operation = 0); inline static int sec(unsigned long long usec) { return (usec + 500000) / 1000000; } unsigned long long @@ -78,42 +79,55 @@ private: String m_caller; String m_called; String m_status; + bool m_first; }; static ObjList cdrs; CdrBuilder::CdrBuilder(const char *name, const char *caller, const char *called) - : String(name), m_caller(caller), m_called(called), m_status("unknown") + : String(name), m_caller(caller), m_called(called), m_status("unknown"), m_first(true) { m_ring = m_call = m_ringing = m_answer = m_hangup = 0; } CdrBuilder::~CdrBuilder() { + emit("finalize"); +} + +void CdrBuilder::emit(const char *operation) +{ + unsigned long long t_hangup = m_hangup ? m_hangup : Time::now(); const char *dir = m_ring ? (m_call ? "bidir" : "incoming") : (m_call ? "outgoing" : "unknown"); - if (!m_hangup) - m_hangup = Time::now(); - if (!m_ring) - m_ring = m_call; - if (!m_call) - m_call = m_ring; - if (!m_ringing) - m_ringing = m_call; - if (!m_answer) - m_answer = m_hangup; + unsigned long long + t_ring = m_ring, t_call = m_call, + t_ringing = m_ringing, t_answer = m_answer; + if (!t_ring) + t_ring = t_call; + if (!t_call) + t_call = t_ring; + if (!t_ringing) + t_ringing = t_call; + if (!t_answer) + t_answer = t_hangup; - Message *m = new Message("cdr"); - m->addParam("time",String(sec(m_ring))); + if (!operation) + operation = m_first ? "initialize" : "update"; + m_first = false; + + Message *m = new Message("call.cdr"); + m->addParam("operation",operation); + m->addParam("time",String(sec(t_ring))); m->addParam("chan",c_str()); m->addParam("direction",dir); m->addParam("caller",m_caller); m->addParam("called",m_called); - m->addParam("duration",String(sec(m_hangup - m_ring))); - m->addParam("billtime",String(sec(m_hangup - m_answer))); - m->addParam("ringtime",String(sec(m_answer - m_ringing))); + m->addParam("duration",String(sec(t_hangup - t_ring))); + m->addParam("billtime",String(sec(t_hangup - t_answer))); + m->addParam("ringtime",String(sec(t_answer - t_ringing))); m->addParam("status",m_status); Engine::enqueue(m); } @@ -143,8 +157,10 @@ void CdrBuilder::update(int type, unsigned long long val) break; case CdrHangup: m_hangup = val; - break; + cdrs.remove(this); + return; } + emit(); } CdrBuilder *CdrBuilder::find(String &id) @@ -186,10 +202,6 @@ bool CdrHandler::received(Message &msg) if (s) b->setStatus(s); b->update(m_type,msg.msgTime().usec()); - if (m_type == CdrHangup) { - cdrs.remove(b); - return false; - } } else Debug("CdrBuilder",DebugGoOn,"Got message '%s' for untracked id '%s'", @@ -205,10 +217,15 @@ bool StatusHandler::received(Message &msg) String st("name=cdrbuild,type=cdr,format=Status|Caller|Called"); st << ";cdrs=" << cdrs.count() << ";"; ObjList *l = &cdrs; + bool first = true; for (; l; l=l->next()) { CdrBuilder *b = static_cast(l->get()); if (b) { - st << "," << *b << "=" << b->getStatus(); + if (first) + first = false; + else + st << ","; + st << *b << "=" << b->getStatus(); } } msg.retValue() << st << "\n"; @@ -236,12 +253,12 @@ void CdrBuildPlugin::initialize() Output("Initializing module CdrBuild"); if (m_first) { m_first = false; - Engine::install(new CdrHandler("ring",CdrRing)); - Engine::install(new CdrHandler("call",CdrCall)); - Engine::install(new CdrHandler("ringing",CdrRinging)); - Engine::install(new CdrHandler("answer",CdrAnswer)); - Engine::install(new CdrHandler("hangup",CdrHangup)); - Engine::install(new CdrHandler("dropcdr",CdrDrop)); + Engine::install(new CdrHandler("call.preroute",CdrRing)); + Engine::install(new CdrHandler("call.execute",CdrCall)); + Engine::install(new CdrHandler("call.ringing",CdrRinging)); + Engine::install(new CdrHandler("call.answered",CdrAnswer)); + Engine::install(new CdrHandler("call.hangup",CdrHangup)); + Engine::install(new CdrHandler("call.dropcdr",CdrDrop)); Engine::install(new CdrHandler("engine.halt",EngHalt)); Engine::install(new StatusHandler); } diff --git a/modules/cdrfile.cpp b/modules/cdrfile.cpp index b68d8920..b3036bbb 100644 --- a/modules/cdrfile.cpp +++ b/modules/cdrfile.cpp @@ -62,6 +62,10 @@ void CdrFileHandler::init(const char *fname, bool tabsep) bool CdrFileHandler::received(Message &msg) { + String op(msg.getValue("operation")); + if (op != "finalize") + return false; + Lock lock(m_lock); if (m_file) { const char *format = m_tabs @@ -104,7 +108,7 @@ void CdrFilePlugin::initialize() Configuration cfg(Engine::configFile("cdrfile")); const char *file = cfg.getValue("general","file"); if (file && !m_handler) { - m_handler = new CdrFileHandler("cdr"); + m_handler = new CdrFileHandler("call.cdr"); Engine::install(m_handler); } if (m_handler) diff --git a/modules/cdrpgsql.cpp b/modules/cdrpgsql.cpp index 559e62d9..2366040c 100644 --- a/modules/cdrpgsql.cpp +++ b/modules/cdrpgsql.cpp @@ -43,6 +43,10 @@ private: bool CdrPgsqlHandler::received(Message &msg) { + String op(msg.getValue("operation")); + if (op != "finalize") + return false; + // const char *calltime = c_safe(msg.getValue("time")); const char *channel = c_safe(msg.getValue("channel")); const char *called = c_safe(msg.getValue("called")); @@ -134,9 +138,9 @@ void CdrPgsqlPlugin::initialize() } if (!m_handler) { Output("Installing Cdr for PostgreSQL handler"); - m_handler = new CdrPgsqlHandler("cdr"); + m_handler = new CdrPgsqlHandler("call.cdr"); Engine::install(m_handler); - Engine::install(new StatusHandler("status")); + Engine::install(new StatusHandler("engine.status")); } } diff --git a/modules/extmodule.cpp b/modules/extmodule.cpp index d93f1655..121bfaf1 100644 --- a/modules/extmodule.cpp +++ b/modules/extmodule.cpp @@ -85,7 +85,7 @@ public: }; static ExtModChan* build(const char *file, const char *args, int type); ~ExtModChan(); - virtual void disconnected(const char *reason); + virtual void disconnected(bool final, const char *reason); inline ExtModReceiver* receiver() const { return m_recv; } inline void setRecv(ExtModReceiver* recv) @@ -303,7 +303,7 @@ ExtModChan::~ExtModChan() m_recv->die(false); } -void ExtModChan::disconnected(const char *reason) +void ExtModChan::disconnected(bool final, const char *reason) { Debugger debug("ExtModChan::disconnected()"," '%s' [%p]",reason,this); } @@ -837,9 +837,9 @@ void ExtModulePlugin::initialize() s_cfg = Engine::configFile("extmodule"); s_cfg.load(); if (!m_handler) { - m_handler = new ExtModHandler("call"); + m_handler = new ExtModHandler("call.execute"); Engine::install(m_handler); - Engine::install(new ExtModCommand("command")); + Engine::install(new ExtModCommand("engine.command")); NamedList *list = s_cfg.getSection("scripts"); if (list) { diff --git a/modules/faxchan.cpp b/modules/faxchan.cpp index 9ba10101..8f57f680 100644 --- a/modules/faxchan.cpp +++ b/modules/faxchan.cpp @@ -58,7 +58,7 @@ class FaxChan : public DataEndpoint public: FaxChan(const char *file, bool receive, bool iscaller, const char *ident = 0); ~FaxChan(); - virtual void disconnected(const char *reason); + virtual void disconnected(bool final, const char *reason); void rxData(const DataBlock &data); void rxBlock(void *buff, int len); int txBlock(); @@ -303,7 +303,7 @@ void FaxChan::phaseE(int result) m_eof = true; } -void FaxChan::disconnected(const char *reason) +void FaxChan::disconnected(bool final, const char *reason) { Debug(DebugInfo,"FaxChan::disconnected() '%s' [%p]",reason,this); } @@ -350,15 +350,15 @@ bool FaxHandler::received(Message &msg) fc->destruct(); return false; } - Message m("preroute"); + Message m("call.preroute"); m.addParam("id",dest); m.addParam("caller",dest); m.addParam("called",targ); m.userData(fc); Engine::dispatch(m); - m = "route"; + m = "call.route"; if (Engine::dispatch(m)) { - m = "call"; + m = "call.execute"; m.addParam("callto",m.retValue()); m.retValue() = 0; if (Engine::dispatch(m)) { @@ -384,7 +384,7 @@ void FaxPlugin::initialize() { Output("Initializing module Fax"); if (!m_handler) { - m_handler = new FaxHandler("call"); + m_handler = new FaxHandler("call.execute"); Engine::install(m_handler); } } diff --git a/modules/h323chan.cpp b/modules/h323chan.cpp index 874e5de3..369d6f82 100644 --- a/modules/h323chan.cpp +++ b/modules/h323chan.cpp @@ -225,19 +225,22 @@ public: BOOL OnCreateLogicalChannel(const H323Capability & capability, H323Channel::Directions dir, unsigned & errorCode ) ; BOOL StartExternalRTP(const char* remoteIP, WORD remotePort, H323Channel::Directions dir, YateH323_ExternalRTPChannel* chan); void OnStoppedExternal(H323Channel::Directions dir); - virtual void disconnected(const char *reason); + virtual void disconnected(bool final, const char *reason); inline const String &id() const { return m_id; } inline const String &status() const { return m_status; } inline void setStatus(const char *status) { m_status = status; } + inline void setTarget(const char *target = 0) + { m_targetid = target; } inline static int total() { return s_total; } private: bool m_nativeRtp; String m_id; String m_status; + String m_targetid; static int s_total; }; @@ -280,6 +283,20 @@ public: virtual bool received(Message &msg); }; +class H323DTMF : public MessageHandler +{ +public: + H323DTMF(const char *name) : MessageHandler(name) { } + virtual bool received(Message &msg); +}; + +class H323Text : public MessageHandler +{ +public: + H323Text(const char *name) : MessageHandler(name) { } + virtual bool received(Message &msg); +}; + class H323Stopper : public MessageHandler { public: @@ -309,7 +326,7 @@ private: class StatusHandler : public MessageHandler { public: - StatusHandler() : MessageHandler("status") { } + StatusHandler() : MessageHandler("engine.status") { } virtual bool received(Message &msg); }; @@ -321,7 +338,7 @@ public: virtual void initialize(); virtual bool isBusy() const; void cleanup(); - YateH323Connection *findConnectionLock(const char *id); + YateH323Connection *findConnectionLock(const String& id); inline YateH323EndPoint *ep() { return m_endpoint; } inline ObjList &calls() @@ -346,9 +363,7 @@ bool H323MsgThread::route() { Debug(DebugAll,"Routing thread for %s [%p]",m_id.c_str(),this); Engine::dispatch(m_msg); - *m_msg = "preroute"; - Engine::dispatch(m_msg); - *m_msg = "route"; + *m_msg = "call.route"; bool ok = Engine::dispatch(m_msg) && !m_msg->retValue().null(); YateH323Connection *conn = hplugin.findConnectionLock(m_id); if (!conn) { @@ -357,13 +372,14 @@ bool H323MsgThread::route() } if (ok) { conn->AnsweringCall(H323Connection::AnswerCallPending); - *m_msg = "call"; + *m_msg = "call.execute"; m_msg->addParam("callto",m_msg->retValue()); m_msg->retValue() = 0; m_msg->userData(static_cast(conn)); if (Engine::dispatch(m_msg)) { Debug(DebugInfo,"Routing H.323 call %s [%p] to '%s'",m_id.c_str(),conn,m_msg->getValue("callto")); conn->setStatus("routed"); + conn->setTarget(m_msg->getValue("targetid")); conn->AnsweringCall(H323Connection::AnswerCallNow); conn->deref(); } @@ -617,7 +633,7 @@ H323Connection::AnswerCallResponse YateH323Connection::OnAnswerCall(const PStrin return H323Connection::AnswerCallDenied; } - Message *m = new Message("ring"); + Message *m = new Message("call.preroute"); m->addParam("driver","h323"); m->addParam("id",m_id); const char *s = s_cfg.getValue("incoming","context"); @@ -667,11 +683,13 @@ void YateH323Connection::OnEstablished() s_total++; setStatus("connected"); s_calls.unlock(); - if (!HadAnsweredCall()) + if (HadAnsweredCall()) return; - Message *m = new Message("answer"); + Message *m = new Message("call.answered"); m->addParam("driver","h323"); m->addParam("id",m_id); + if (m_targetid) + m->addParam("targetid",m_targetid); m->addParam("status","answered"); Engine::enqueue(m); } @@ -680,23 +698,24 @@ void YateH323Connection::OnCleared() { Debug(DebugInfo,"YateH323Connection::OnCleared() [%p]",this); setStatus("cleared"); - bool ans = HadAnsweredCall(); - disconnect(); - if (!ans) - return; - Message *m = new Message("hangup"); + Message *m = new Message("call.hangup"); m->addParam("driver","h323"); m->addParam("id",m_id); + if (m_targetid) + m->addParam("targetid",m_targetid); Engine::enqueue(m); + disconnect(); } BOOL YateH323Connection::OnAlerting(const H323SignalPDU &alertingPDU, const PString &user) { Debug(DebugInfo,"YateH323Connection::OnAlerting '%s' [%p]",(const char *)user,this); setStatus("ringing"); - Message *m = new Message("ringing"); + Message *m = new Message("call.ringing"); m->addParam("driver","h323"); m->addParam("id",m_id); + if (m_targetid) + m->addParam("targetid",m_targetid); Engine::enqueue(m); return true; } @@ -704,11 +723,31 @@ BOOL YateH323Connection::OnAlerting(const H323SignalPDU &alertingPDU, const PStr void YateH323Connection::OnUserInputTone(char tone, unsigned duration, unsigned logicalChannel, unsigned rtpTimestamp) { Debug(DebugInfo,"YateH323Connection::OnUserInputTone '%c' duration=%u [%p]",tone,duration,this); + char buf[2]; + buf[0] = tone; + buf[1] = 0; + Message *m = new Message("chan.dtmf"); + m->addParam("driver","h323"); + m->addParam("id",m_id); + if (m_targetid) + m->addParam("targetid",m_targetid); + m->addParam("text",buf); + m->addParam("duration",String(duration)); + Engine::enqueue(m); } void YateH323Connection::OnUserInputString(const PString &value) { Debug(DebugInfo,"YateH323Connection::OnUserInputString '%s' [%p]",(const char *)value,this); + String text((const char *)value); + const char *type = text.startSkip("MSG") ? "chan.text" : "chan.dtmf"; + Message *m = new Message(type); + m->addParam("driver","h323"); + m->addParam("id",m_id); + if (m_targetid) + m->addParam("targetid",m_targetid); + m->addParam("text",text); + Engine::enqueue(m); } BOOL YateH323Connection::OpenAudioChannel(BOOL isEncoding, unsigned bufferSize, @@ -743,10 +782,11 @@ BOOL YateH323Connection::OpenAudioChannel(BOOL isEncoding, unsigned bufferSize, return false; } -void YateH323Connection::disconnected(const char *reason) +void YateH323Connection::disconnected(bool final, const char *reason) { Debugger debug("YateH323Connection::disconnected()"," '%s' [%p]",reason,this); setStatus("disconnected"); + setTarget(); // we must bypass the normal Yate refcounted destruction as OpenH323 will destroy the object ref(); if (getSource() && m_nativeRtp) @@ -770,7 +810,7 @@ H323Channel *YateH323Connection::CreateRealTimeLogicalChannel(const H323Capabili // GetControlChannel().GetLocalAddress().GetIpAndPort(externalIpAddress, port); GetControlChannel().GetLocalAddress().GetIpAddress(externalIpAddress); Debug(DebugInfo,"address '%s'",(const char *)externalIpAddress.AsString()); - Message m("rtp"); + Message m("chan.rtp"); m.addParam("localip",externalIpAddress.AsString()); m.userData(static_cast(this)); Debug(DebugAll,"userData=%p this=%p",m.userData(),this); @@ -812,7 +852,7 @@ BOOL YateH323Connection::StartExternalRTP(const char* remoteIP, WORD remotePort, const char* sdir = lookup(dir,dict_h323_dir); Debug(DebugAll,"YateH323Connection::StartExternalRTP(\"%s\",%u,%s,%p) [%p]", remoteIP,remotePort,sdir,chan,this); - Message m("rtp"); + Message m("chan.rtp"); m.userData(static_cast(this)); Debug(DebugAll,"userData=%p this=%p",m.userData(),this); if (sdir) @@ -1019,7 +1059,7 @@ BOOL YateH323AudioSource::Write(const void *buf, PINDEX len) BOOL YateGatekeeperServer::GetUsersPassword(const PString & alias,PString & password) const { - Message *m = new Message("auth"); + Message *m = new Message("user.auth"); m->addParam("username",alias); Engine::dispatch(m); if (m->retValue() != NULL) @@ -1056,7 +1096,7 @@ H323GatekeeperRequest::Response YateGatekeeperServer::OnRegistration(H323Gatekee * we deal just with the first callSignalAddress, since openh323 * don't give a shit for multi hosted boxes. */ - Message *m = new Message("regist"); + Message *m = new Message("user.register"); m->addParam("username",alias); m->addParam("techno","h323gk"); m->addParam("data",ips); @@ -1077,7 +1117,7 @@ H323GatekeeperRequest::Response YateGatekeeperServer::OnUnregistration(H323Gatek PString alias = H323GetAliasAddressString(request.urq.m_endpointAlias[j]); if (alias.IsEmpty()) return H323GatekeeperRequest::Reject; - Message *m = new Message("unregist"); + Message *m = new Message("user.unregister"); m->addParam("username",alias); Engine::dispatch(m); } @@ -1089,7 +1129,7 @@ H323GatekeeperRequest::Response YateGatekeeperServer::OnUnregistration(H323Gatek BOOL YateGatekeeperServer::TranslateAliasAddressToSignalAddress(const H225_AliasAddress & alias,H323TransportAddress & address) { PString aliasString = H323GetAliasAddressString(alias); - Message m("route"); + Message m("call.route"); m.addParam("called",aliasString); Engine::dispatch(m); String s = m.retValue(); @@ -1172,7 +1212,9 @@ bool H323Handler::received(Message &msg) Debug(DebugInfo,"Found call to H.323 target='%s'", dest.matchString(1).c_str()); PString p; - H323Connection *conn = hplugin.ep()->MakeCallLocked(dest.matchString(1).c_str(),p,msg.userData()); + YateH323Connection* conn = static_cast( + hplugin.ep()->MakeCallLocked(dest.matchString(1).c_str(),p,msg.userData()) + ); if (conn) { String caller(msg.getValue("caller")); if (caller.null()) @@ -1183,6 +1225,8 @@ bool H323Handler::received(Message &msg) Debug(DebugInfo,"Setting H.323 caller name to '%s'",caller.c_str()); conn->SetLocalPartyName(caller.c_str()); } + conn->setTarget(msg.getValue("id")); + msg.addParam("targetid",conn->id()); conn->Unlock(); return true; } @@ -1216,6 +1260,39 @@ bool H323Dropper::received(Message &msg) return false; }; +bool H323DTMF::received(Message &msg) +{ + String id(msg.getValue("targetid")); + if (!id.startsWith("h323")) + return false; + String text(msg.getValue("text")); + YateH323Connection *conn = hplugin.findConnectionLock(id); + if (conn) { + Debug("H323DTMF",DebugInfo,"Text '%s' for %s [%p]",text.c_str(),conn->id().c_str(),conn); + for (unsigned int i = 0; i < text.length(); i++) + conn->SendUserInputTone(text[i]); + conn->Unlock(); + return true; + } + return false; +}; + +bool H323Text::received(Message &msg) +{ + String id(msg.getValue("targetid")); + if (!id.startsWith("h323")) + return false; + String text(msg.getValue("text")); + YateH323Connection *conn = hplugin.findConnectionLock(id); + if (conn) { + Debug("H323Text",DebugInfo,"Text '%s' for %s [%p]",text.c_str(),conn->id().c_str(),conn); + conn->SendUserInputIndicationString(text.safe()); + conn->Unlock(); + return true; + } + return false; +}; + bool StatusHandler::received(Message &msg) { const char *sel = msg.getValue("module"); @@ -1277,7 +1354,7 @@ H323Plugin::~H323Plugin() } } -YateH323Connection *H323Plugin::findConnectionLock(const char *id) +YateH323Connection *H323Plugin::findConnectionLock(const String& id) { s_calls.lock(); ObjList *l = &m_calls; @@ -1334,8 +1411,10 @@ void H323Plugin::initialize() s_externalRtp = s_cfg.getBoolValue("general","external_rtp",false); if (m_first) { m_first = false; - Engine::install(new H323Handler("call")); - Engine::install(new H323Dropper("drop")); + Engine::install(new H323Handler("call.execute")); + Engine::install(new H323Dropper("call.drop")); + Engine::install(new H323DTMF("chan.dtmf")); + Engine::install(new H323Text("chan.text")); Engine::install(new H323Stopper("engine.halt")); Engine::install(new StatusHandler); } diff --git a/modules/iaxchan.cpp b/modules/iaxchan.cpp index d70ebdf8..8a14929e 100644 --- a/modules/iaxchan.cpp +++ b/modules/iaxchan.cpp @@ -128,7 +128,7 @@ class YateIAXConnection : public DataEndpoint public: YateIAXConnection(iax_session *session = 0); ~YateIAXConnection(); - virtual void disconnected(const char *reason); + virtual void disconnected(bool final, const char *reason); void abort(); int makeCall(char *cidnum, char *cidname, char *target = 0, char *lang = 0); void hangup(char *reason = "Unexpected problem"); @@ -139,7 +139,7 @@ public: inline iax_session *session() const { return m_session; } String ourcallid; - String partycallid; + String targetid; String calleraddress; String calledaddress; private: @@ -390,7 +390,7 @@ bool YateIAXEndPoint::accepting(iax_event *e) s_mutex.unlock(); return 1; } - Message m("auth"); + Message m("user.auth"); if (e->ies.username) m.addParam("username",e->ies.username); else @@ -459,7 +459,7 @@ void YateIAXEndPoint::answer(iax_event *e) { if (!accepting(e)) return; - Message *m = new Message("route"); + Message *m = new Message("call.route"); m->addParam("driver","iax"); // m->addParam("id",String(e->did)); if (e->ies.calling_name) @@ -477,10 +477,10 @@ void YateIAXEndPoint::answer(iax_event *e) //this have to be here to get the right called_address. conn->calledaddress = m->retValue(); - *m = "call"; + *m = "call.execute"; m->userData(conn); m->addParam("callto",m->retValue()); - m->addParam("ourcallid",conn->ourcallid); + m->addParam("id",conn->ourcallid); m->retValue().clear(); if (!Engine::dispatch(m)) { @@ -490,10 +490,10 @@ void YateIAXEndPoint::answer(iax_event *e) return; } /* i do this to setup the peercallid by getting - * partycallid (that mean ourcallid from the other party) */ - String partycallid(m->getValue("partycallid")); - Debug(DebugInfo,"partycallid %s",partycallid.c_str()); - conn->partycallid = partycallid; + * targetid (that mean ourcallid from the other party) */ + String targetid(m->getValue("targetid")); + Debug(DebugInfo,"targetid %s",targetid.c_str()); + conn->targetid = targetid; conn->deref(); s_mutex.lock(); ::iax_answer(e->session); @@ -526,7 +526,7 @@ void YateIAXEndPoint::answer(iax_event *e) void YateIAXEndPoint::reg(iax_event *e) { - Message m("auth"); + Message m("user.auth"); if (e->ies.username) m.addParam("username",e->ies.username); else @@ -652,30 +652,30 @@ void YateIAXConnection::handleEvent(iax_event *event) break; case IAX_EVENT_TEXT: { - Message m("sms"); + Message m("chan.text"); m.addParam("text",(char *)event->data); - m.addParam("ourcallid",ourcallid.c_str()); - m.addParam("partycallid",partycallid.c_str()); + m.addParam("id",ourcallid.c_str()); + m.addParam("targetid",targetid.c_str()); m.addParam("callerid",event->session->callerid); m.addParam("calledid",event->session->dnid); Engine::dispatch(m); - Debug(DebugInfo,"this text is inside a call: %s",(char *)event->data); + Debug("IAX EVENT TEXT",DebugInfo,"this text is inside a call: %s",(char *)event->data); } break; case IAX_EVENT_DTMF: { - Message m("dtmf"); + Message m("chan.dtmf"); /* this is because Paul wants this to be usable on non i386 */ char buf[2]; buf[0] = event->subclass; buf[1] = 0; m.addParam("text",buf); - m.addParam("ourcallid",ourcallid.c_str()); - m.addParam("partycallid",partycallid.c_str()); + m.addParam("id",ourcallid.c_str()); + m.addParam("targetid",targetid.c_str()); m.addParam("callerid",event->session->callerid); m.addParam("calledid",event->session->dnid); Engine::dispatch(m); - Debug(DebugInfo,"this text is inside a call: %d",event->subclass); + Debug("IAX EVENT DTMF",DebugInfo,"this text is inside a call: %d",event->subclass); } break; #if 0 @@ -783,19 +783,19 @@ void YateIAXConnection::sourceAudio(void *buffer, int len, int format) } } -void YateIAXConnection::disconnected(const char *reason) +void YateIAXConnection::disconnected(bool final, const char *reason) { Debug(DebugAll,"YateIAXConnection::disconnected() '%s'",reason); // If we still have a connection this is the last chance to get transferred - if (!m_final) { - Message m("disconnected"); - m.addParam("ourcallid",ourcallid.c_str()); + if (!(final || m_final)) { + Message m("chan.disconnected"); + m.addParam("id",ourcallid.c_str()); if (reason) m.addParam("reason",reason); - if (partycallid) { + if (targetid) { // Announce our old party but at this point it may be destroyed - m.addParam("partycallid",partycallid.c_str()); - partycallid.clear(); + m.addParam("targetid",targetid.c_str()); + targetid.clear(); } m.userData(this); Engine::dispatch(m); @@ -849,13 +849,13 @@ void YateIAXAudioConsumer::Consume(const DataBlock &data, unsigned long timeDelt bool SMSHandler::received(Message &msg) { - String ourcallid(msg.getValue("partycallid")); + String ourcallid(msg.getValue("targetid")); if (!ourcallid) return false; String text(msg.getValue("text")); if (!text) return false; - Debug(DebugInfo,"text %s ourcallid %s",text.c_str(),ourcallid.c_str()); + Debug("IAX TEXT",DebugInfo,"text %s ourcallid %s",text.c_str(),ourcallid.c_str()); YateIAXConnection *conn= iplugin.m_endpoint->findconn(ourcallid); if (conn){ s_mutex.lock(); @@ -868,13 +868,13 @@ bool SMSHandler::received(Message &msg) bool DTMFHandler::received(Message &msg) { - String ourcallid(msg.getValue("partycallid")); + String ourcallid(msg.getValue("targetid")); if (!ourcallid) return false; String text(msg.getValue("text")); if (!text) return false; - Debug(DebugInfo,"text %s ourcallid %s",text.c_str(), ourcallid.c_str()); + Debug("IAX DTMF",DebugInfo,"text %s ourcallid %s",text.c_str(), ourcallid.c_str()); YateIAXConnection *conn= iplugin.m_endpoint->findconn(ourcallid); if (conn){ s_mutex.lock(); @@ -902,8 +902,8 @@ bool IAXHandler::received(Message &msg) YateIAXConnection *conn = new YateIAXConnection(); /* i do this to setup the peercallid by getting ourcallid * from the other party */ - String partycallid(msg.getValue("ourcallid")); - conn->partycallid = partycallid; + String targetid(msg.getValue("id")); + conn->targetid = targetid; conn->calledaddress = dest; int i = conn->makeCall((char *)msg.getValue("caller"),(char *)msg.getValue("callername"),(char *)dest.matchString(1).safe()); if (i < 0) { @@ -914,7 +914,7 @@ bool IAXHandler::received(Message &msg) DataEndpoint *dd = static_cast(msg.userData()); if (dd && conn->connect(dd)) { - msg.addParam("partycallid",conn->ourcallid); + msg.addParam("targetid",conn->ourcallid); conn->deref(); } return true; @@ -936,7 +936,7 @@ bool StatusHandler::received(Message &msg) first = false; else st << ","; - st << c->ourcallid << "=" << c->calledaddress << "|" << c->partycallid; + st << c->ourcallid << "=" << c->calledaddress << "|" << c->targetid; } } msg.retValue() << st << "\n"; @@ -945,7 +945,7 @@ bool StatusHandler::received(Message &msg) bool DropHandler::received(Message &msg) { - String ourcallid(msg.getValue("ourcallid")); + String ourcallid(msg.getValue("id")); if (ourcallid.null()) { Debug("IAXDroper",DebugInfo,"Dropping all calls"); ObjList *l = &iplugin.m_endpoint->calls(); @@ -969,7 +969,7 @@ bool DropHandler::received(Message &msg) bool TransferHandler::received(Message &msg) { - String ourcallid(msg.getValue("partycallid")); + String ourcallid(msg.getValue("targetid")); if (!ourcallid) return false; String callto(msg.getValue("callto")); @@ -979,15 +979,15 @@ bool TransferHandler::received(Message &msg) if (conn) { Debug(DebugInfo,"Transferring connection '%s' [%p] to '%s'", ourcallid.c_str(),conn,callto.c_str()); - Message m("call"); + Message m("call.execute"); m.addParam("callto",callto.c_str()); - m.addParam("ourcallid",conn->ourcallid); + m.addParam("id",conn->ourcallid); m.userData(conn); if (Engine::dispatch(m)) { - String partycallid(m.getValue("partycallid")); - Debug(DebugInfo,"IAX [%p] transferred, new partyid '%s'", - conn,partycallid.c_str()); - conn->partycallid = partycallid; + String targetid(m.getValue("targetid")); + Debug(DebugInfo,"IAX [%p] transferred, new targetid '%s'", + conn,targetid.c_str()); + conn->targetid = targetid; return true; } } @@ -1033,12 +1033,12 @@ void IAXPlugin::initialize() YateIAXEndPoint::Setup(); if (m_first) { m_first = false; - Engine::install(new IAXHandler("call")); - Engine::install(new SMSHandler("sms")); - Engine::install(new DTMFHandler("dtmf")); - Engine::install(new StatusHandler("status")); - Engine::install(new DropHandler("drop")); - Engine::install(new TransferHandler("transfer")); + Engine::install(new IAXHandler("call.execute")); + Engine::install(new SMSHandler("chan.text")); + Engine::install(new DTMFHandler("chan.dtmf")); + Engine::install(new StatusHandler("engine.status")); + Engine::install(new DropHandler("call.drop")); + Engine::install(new TransferHandler("call.transfer")); } } diff --git a/modules/osschan.cpp b/modules/osschan.cpp index 6cc7afb7..df29f730 100644 --- a/modules/osschan.cpp +++ b/modules/osschan.cpp @@ -94,7 +94,7 @@ public: bool init(); ~OssChan(); int setformat(); - virtual void disconnected(const char *reason); + virtual void disconnected(bool final, const char *reason); int soundcard_setinput(bool force); int soundcard_setoutput(bool force); int time_has_passed(void); @@ -116,7 +116,7 @@ public: class StatusHandler : public MessageHandler { public: - StatusHandler() : MessageHandler("status") { } + StatusHandler() : MessageHandler("engine.status") { } virtual bool received(Message &msg); }; @@ -358,7 +358,6 @@ int OssChan::soundcard_setinput(bool force) return 1; } - int OssChan::soundcard_setoutput(bool force) { /* Make sure the soundcard is in output mode. */ @@ -384,10 +383,10 @@ int OssChan::soundcard_setoutput(bool force) return 1; } -void OssChan::disconnected(const char *reason) +void OssChan::disconnected(bool final, const char *reason) { Debugger debug("OssChan::disconnected()"," '%s' [%p]",reason,this); - destruct(); +// destruct(); } bool OssHandler::received(Message &msg) @@ -414,7 +413,7 @@ bool OssHandler::received(Message &msg) const char *direct = msg.getValue("direct"); if (direct) { - Message m("call"); + Message m("call.execute"); m.addParam("id",dest); m.addParam("caller",dest); m.addParam("callto",direct); @@ -429,12 +428,12 @@ bool OssHandler::received(Message &msg) Debug(DebugWarn,"OSS outgoing call with no target!"); return false; } - Message m("preroute"); + Message m("call.preroute"); m.addParam("id",dest); m.addParam("caller",dest); m.addParam("called",targ); Engine::dispatch(m); - m = "route"; + m = "call.route"; if (Engine::dispatch(m)) { m = "call"; m.addParam("callto",m.retValue()); @@ -486,8 +485,8 @@ void OssPlugin::initialize() { Output("Initializing module OssChan"); if (!m_handler) { - m_handler = new OssHandler("call"); - Engine::install(new DropHandler("drop")); + m_handler = new OssHandler("call.execute"); + Engine::install(new DropHandler("call.drop")); Engine::install(m_handler); Engine::install(new StatusHandler); } diff --git a/modules/pgsqlroute.cpp b/modules/pgsqlroute.cpp index a0d0c759..804eb4e8 100644 --- a/modules/pgsqlroute.cpp +++ b/modules/pgsqlroute.cpp @@ -223,9 +223,9 @@ void PGSQLRoutePlugin::initialize() if (m_first && conn) { m_first = false; unsigned prio = cfg.getIntValue("general","priority",100); - Engine::install(new PrerouteHandler("preroute",prio)); - Engine::install(new RouteHandler("route",prio)); - Engine::install(new StatusHandler("status")); + Engine::install(new PrerouteHandler("call.preroute",prio)); + Engine::install(new RouteHandler("call.route",prio)); + Engine::install(new StatusHandler("engine.status")); } } diff --git a/modules/regexroute.cpp b/modules/regexroute.cpp index e2013f60..44c6d118 100644 --- a/modules/regexroute.cpp +++ b/modules/regexroute.cpp @@ -35,7 +35,7 @@ class RouteHandler : public MessageHandler { public: RouteHandler(int prio) - : MessageHandler("route",prio) { } + : MessageHandler("call.route",prio) { } virtual bool received(Message &msg); }; @@ -191,7 +191,7 @@ class PrerouteHandler : public MessageHandler { public: PrerouteHandler(int prio) - : MessageHandler("preroute",prio) { } + : MessageHandler("call.preroute",prio) { } virtual bool received(Message &msg); }; diff --git a/modules/regfile.cpp b/modules/regfile.cpp index 29413f6e..6207e0f4 100644 --- a/modules/regfile.cpp +++ b/modules/regfile.cpp @@ -141,9 +141,21 @@ bool RouteHandler::received(Message &msg) bool StatusHandler::received(Message &msg) { - msg.retValue() << "Regfile,users="; - for (int i=0;i #include +#include #include #include #include @@ -45,6 +46,8 @@ public: inline void setNotify(const String& id) { m_id = id; } private: + void detectAuFormat(); + void detectWavFormat(); DataEndpoint *m_chan; DataBlock m_data; int m_fd; @@ -77,7 +80,7 @@ class WaveChan : public DataEndpoint public: WaveChan(const String& file, bool record, unsigned maxlen = 0); ~WaveChan(); - virtual void disconnected(const char *reason); + virtual void disconnected(bool final, const char *reason); inline const String &id() const { return m_id; } private: @@ -99,14 +102,14 @@ private: class WaveHandler : public MessageHandler { public: - WaveHandler(const char *name) : MessageHandler(name) { } + WaveHandler() : MessageHandler("call.execute") { } virtual bool received(Message &msg); }; class AttachHandler : public MessageHandler { public: - AttachHandler() : MessageHandler("attach") { } + AttachHandler() : MessageHandler("chan.attach") { } virtual bool received(Message &msg); }; @@ -123,24 +126,32 @@ WaveSource::WaveSource(const String& file, DataEndpoint *chan, bool autoclose) : m_chan(chan), m_fd(-1), m_brate(16000), m_total(0), m_time(0), m_autoclose(autoclose) { Debug(DebugAll,"WaveSource::WaveSource(\"%s\",%p) [%p]",file.c_str(),chan,this); + m_fd = ::open(file.safe(),O_RDONLY|O_NOCTTY); + if (m_fd < 0) { + Debug(DebugGoOn,"Opening '%s': error %d: %s", + file.c_str(), errno, ::strerror(errno)); + m_format = ""; + return; + } if (file.endsWith(".gsm")) { m_format = "gsm"; m_brate = 1650; } - else if (file.endsWith(".alaw")) { + else if (file.endsWith(".alaw") || file.endsWith(".A")) { m_format = "alaw"; m_brate = 8000; } - else if (file.endsWith(".mulaw")) { + else if (file.endsWith(".mulaw") || file.endsWith(".u")) { m_format = "mulaw"; m_brate = 8000; } - m_fd = ::open(file.safe(),O_RDONLY|O_NOCTTY); - if (m_fd >= 0) - start("WaveSource"); - else - Debug(DebugGoOn,"Opening '%s': error %d: %s", - file.c_str(), errno, ::strerror(errno)); + else if (file.endsWith(".au")) + detectAuFormat(); + else if (file.endsWith(".wav")) + detectWavFormat(); + else if (!file.endsWith(".slin")) + Debug(DebugMild,"Unknown format for file '%s', assuming signed linear",file.c_str()); + start("WaveSource"); } WaveSource::~WaveSource() @@ -159,6 +170,50 @@ WaveSource::~WaveSource() } } +void WaveSource::detectAuFormat() +{ + struct { + uint32_t sign; + uint32_t offs; + uint32_t len; + uint32_t form; + uint32_t freq; + uint32_t chan; + } header; + if ((::read(m_fd,&header,sizeof(header)) != sizeof(header)) || + (ntohl(header.sign) != 0x2E736E64)) { + Debug(DebugMild,"Invalid .au file header, assuming raw signed linear"); + ::lseek(m_fd,0,SEEK_SET); + return; + } + ::lseek(m_fd,ntohl(header.offs),SEEK_SET); + int samp = ntohl(header.freq); + int chan = ntohl(header.chan); + m_brate = samp; + switch (ntohl(header.form)) { + case 1: + m_format = "mulaw"; + break; + case 27: + m_format = "alaw"; + break; + case 3: + m_brate *= 2; + break; + default: + Debug(DebugMild,"Unknown .au format 0x%0X, assuming signed linear",ntohl(header.form)); + } + if (samp != 8000) + m_format = String(samp) + "/" + m_format; + if (chan != 1) + m_format = String(chan) + "*" + m_format; +} + +void WaveSource::detectWavFormat() +{ + Debug(DebugMild,".wav not supported yet, assuming raw signed linear"); +} + void WaveSource::run() { m_data.assign(0,(m_brate*20)/1000); @@ -187,7 +242,7 @@ void WaveSource::run() } while (r > 0); Debug(DebugAll,"WaveSource [%p] end of data [%p] [%s] ",this,m_chan,m_id.c_str()); if (m_chan && !m_id.null()) { - Message *m = new Message("notify"); + Message *m = new Message("chan.notify"); m->addParam("id",m_id); m->userData(m_chan); Engine::enqueue(m); @@ -209,9 +264,9 @@ WaveConsumer::WaveConsumer(const String& file, DataEndpoint *chan, unsigned maxl file.c_str(),chan,maxlen,this); if (file.endsWith(".gsm")) m_format = "gsm"; - else if (file.endsWith(".alaw")) + else if (file.endsWith(".alaw") || file.endsWith(".A")) m_format = "alaw"; - else if (file.endsWith(".mulaw")) + else if (file.endsWith(".mulaw") || file.endsWith(".u")) m_format = "mulaw"; m_fd = ::creat(file.safe(),S_IRUSR|S_IWUSR); if (m_fd < 0) @@ -252,7 +307,7 @@ void WaveConsumer::Consume(const DataBlock &data, unsigned long timeDelta) } if (m_chan && !m_id.null()) { m_chan->setConsumer(); - Message *m = new Message("notify"); + Message *m = new Message("chan.notify"); m->addParam("id",m_id); m->userData(m_chan); Engine::enqueue(m); @@ -295,7 +350,7 @@ WaveChan::~WaveChan() Debug(DebugAll,"WaveChan::~WaveChan() %s [%p]",m_id.c_str(),this); } -void WaveChan::disconnected(const char *reason) +void WaveChan::disconnected(bool final, const char *reason) { Debugger debug("WaveChan::disconnected()"," '%s' [%p]",reason,this); } @@ -340,14 +395,14 @@ bool WaveHandler::received(Message &msg) Debug(DebugWarn,"Wave outgoing call with no target!"); return false; } - Message m("preroute"); + Message m("call.preroute"); m.addParam("id",dest); m.addParam("caller",dest); m.addParam("called",targ); Engine::dispatch(m); - m = "route"; + m = "call.route"; if (Engine::dispatch(m)) { - m = "call"; + m = "call.execute"; m.addParam("callto",m.retValue()); m.retValue() = 0; WaveChan *c = new WaveChan(dest.matchString(2),meth,maxlen); @@ -449,7 +504,7 @@ void WaveFilePlugin::initialize() { Output("Initializing module WaveFile"); if (!m_handler) { - m_handler = new WaveHandler("call"); + m_handler = new WaveHandler; Engine::install(m_handler); Engine::install(new AttachHandler); } diff --git a/modules/zapchan.cpp b/modules/zapchan.cpp index 7903d6fc..a4760c52 100644 --- a/modules/zapchan.cpp +++ b/modules/zapchan.cpp @@ -381,7 +381,7 @@ class ZapChan : public DataEndpoint public: ZapChan(PriSpan *parent, int chan, unsigned int bufsize); virtual ~ZapChan(); - virtual void disconnected(const char *reason); + virtual void disconnected(bool final, const char *reason); virtual bool nativeConnect(DataEndpoint *peer); inline PriSpan *span() const { return m_span; } @@ -394,6 +394,7 @@ public: void ring(q931_call *call = 0); void hangup(int cause = PRI_CAUSE_INVALID_MSG_UNSPECIFIED); void sendDigit(char digit); + void gotDigits(const char *digits); bool call(Message &msg, const char *called = 0); bool answer(); void answered(); @@ -408,6 +409,10 @@ public: { return m_fd; } inline int law() const { return m_law; } + const String& id() const + { return m_id; } + inline void setTarget(const char *target = 0) + { m_targetid = target; } private: PriSpan *m_span; int m_chan; @@ -419,6 +424,8 @@ private: int m_fd; int m_law; bool m_isdn; + String m_id; + String m_targetid; }; class ZapSource : public ThreadedSource @@ -464,21 +471,28 @@ private: class ZapHandler : public MessageHandler { public: - ZapHandler(const char *name) : MessageHandler(name) { } + ZapHandler() : MessageHandler("call.execute") { } virtual bool received(Message &msg); }; class ZapDropper : public MessageHandler { public: - ZapDropper(const char *name) : MessageHandler(name) { } + ZapDropper() : MessageHandler("call.drop") { } + virtual bool received(Message &msg); +}; + +class ZapDTMF : public MessageHandler +{ +public: + ZapDTMF() : MessageHandler("chan.dtmf") { } virtual bool received(Message &msg); }; class StatusHandler : public MessageHandler { public: - StatusHandler() : MessageHandler("status") { } + StatusHandler() : MessageHandler("engine.status") { } virtual bool received(Message &msg); }; @@ -776,8 +790,9 @@ void PriSpan::ringChan(int chan, pri_event_ring &ev) ev.callednum,ev.redirectingnum,ev.calledplan); Debug(DebugInfo,"type=%d complete=%d format='%s'", ev.ctype,ev.complete,lookup(ev.layer1,dict_str2law,"unknown")); - Message *m = new Message("ring"); + Message *m = new Message("call.preroute"); m->addParam("driver","zap"); + m->addParam("id",getChan(chan)->id()); m->addParam("span",String(m_span)); m->addParam("channel",String(chan)); if (ev.callingnum[0]) @@ -785,11 +800,9 @@ void PriSpan::ringChan(int chan, pri_event_ring &ev) if (ev.callednum[0]) m->addParam("called",ev.callednum); Engine::dispatch(m); - *m = "preroute"; - Engine::dispatch(m); - *m = "route"; + *m = "call.route"; if (Engine::dispatch(m)) { - *m = "call"; + *m = "call.execute"; m->addParam("callto",m->retValue()); m->retValue() = 0; int dataLaw = -1; @@ -803,8 +816,10 @@ void PriSpan::ringChan(int chan, pri_event_ring &ev) } getChan(chan)->open(dataLaw); m->userData(getChan(chan)); - if (Engine::dispatch(m)) + if (Engine::dispatch(m)) { + getChan(chan)->setTarget(m->getValue("targetid")); getChan(chan)->answer(); + } else getChan(chan)->hangup(PRI_CAUSE_REQUESTED_CHAN_UNAVAIL); } @@ -824,6 +839,7 @@ void PriSpan::infoChan(int chan, pri_event_ring &ev) ev.callingname,ev.callingnum,ev.callingplan); Debug(DebugInfo,"callednum='%s' redirectnum='%s' calledplan=%d", ev.callednum,ev.redirectingnum,ev.calledplan); + getChan(chan)->gotDigits(ev.callednum); } void PriSpan::hangupChan(int chan,pri_event_hangup &ev) @@ -953,6 +969,7 @@ ZapChan::ZapChan(PriSpan *parent, int chan, unsigned int bufsize) // I hate counting from one... m_abschan = m_chan+m_span->chan1()-1; m_isdn = true; + m_id << "zap/" << m_abschan; } ZapChan::~ZapChan() @@ -961,9 +978,22 @@ ZapChan::~ZapChan() hangup(PRI_CAUSE_NORMAL_UNSPECIFIED); } -void ZapChan::disconnected(const char *reason) +void ZapChan::disconnected(bool final, const char *reason) { Debugger debug("ZapChan::disconnected()", " '%s' [%p]",reason,this); + if (!final) { + Message m("chan.disconnected"); + m.addParam("driver","zap"); + m.addParam("id",id()); + m.addParam("span",String(m_span->span())); + m.addParam("channel",String(m_chan)); + if (m_targetid) { + m.addParam("targetid",m_targetid); + setTarget(); + } + m.addParam("reason",reason); + Engine::enqueue(m); + } // FIXME: we can't know from which thread we got disconnected bool gotLock = zplugin.mutex.lock(1000); hangup(PRI_CAUSE_NORMAL_CLEARING); @@ -1070,12 +1100,6 @@ bool ZapChan::answer() m_timeout = 0; Output("Answering on zap/%d (%d/%d)",m_abschan,m_span->span(),m_chan); ::pri_answer(m_span->pri(),m_call,m_chan,!m_isdn); - Message *m = new Message("answer"); - m->addParam("driver","zap"); - m->addParam("span",String(m_span->span())); - m->addParam("channel",String(m_chan)); - m->addParam("status","answered"); - Engine::enqueue(m); return true; } @@ -1086,6 +1110,7 @@ void ZapChan::hangup(int cause) Debug(DebugInfo,"Hanging up zap/%d in state %s: %s (%d)", m_abschan,status(),reason,cause); m_timeout = 0; + setTarget(); disconnect(reason); close(); m_ring = false; @@ -1093,8 +1118,9 @@ void ZapChan::hangup(int cause) ::pri_hangup(m_span->pri(),m_call,cause); ::pri_destroycall(m_span->pri(),m_call); m_call = 0; - Message *m = new Message("hangup"); + Message *m = new Message("call.hangup"); m->addParam("driver","zap"); + m->addParam("id",id()); m->addParam("span",String(m_span->span())); m->addParam("channel",String(m_chan)); m->addParam("reason",pri_cause2str(cause)); @@ -1111,14 +1137,30 @@ void ZapChan::answered() } m_timeout = 0; Output("Remote answered on zap/%d (%d/%d)",m_abschan,m_span->span(),m_chan); - Message *m = new Message("answer"); + Message *m = new Message("call.answered"); m->addParam("driver","zap"); + m->addParam("id",id()); m->addParam("span",String(m_span->span())); m->addParam("channel",String(m_chan)); + if (m_targetid) + m->addParam("targetid",m_targetid); m->addParam("status","answered"); Engine::enqueue(m); } +void ZapChan::gotDigits(const char *digits) +{ + Message *m = new Message("chan.dtmf"); + m->addParam("driver","zap"); + m->addParam("id",id()); + m->addParam("span",String(m_span->span())); + m->addParam("channel",String(m_chan)); + if (m_targetid) + m->addParam("targetid",m_targetid); + m->addParam("text",digits); + Engine::enqueue(m); +} + void ZapChan::sendDigit(char digit) { if (m_call) @@ -1158,6 +1200,7 @@ bool ZapChan::call(Message &msg, const char *called) break; } connect(dd); + msg.addParam("targetid",id()); } else msg.userData(this); @@ -1272,6 +1315,28 @@ bool ZapDropper::received(Message &msg) return false; } +bool ZapDTMF::received(Message &msg) +{ + String id(msg.getValue("targetid")); + if (!id.startsWith("zap/")) + return false; + String text(msg.getValue("text")); + ZapChan *c = 0; + id >> "zap/"; + int n = id.toInteger(); + if ((n > 0) && (c = zplugin.findChan(n))) { + Debug("ZapDTMF",DebugInfo,"Sending to zap/%d (%d/%d)", + n,c->span()->span(),c->chan()); + zplugin.mutex.lock(); + for (unsigned int i = 0; i < text.length(); i++) + c->sendDigit(text[i]); + zplugin.mutex.unlock(); + return true; + } + Debug("ZapDTMF",DebugInfo,"Could not find zap/%s",id.c_str()); + return false; +} + bool StatusHandler::received(Message &msg) { const char *sel = msg.getValue("module"); @@ -1305,7 +1370,7 @@ bool StatusHandler::received(Message &msg) first = false; else st << ","; - st << "zap/" << c->absChan() << "="; + st << c->id() << "="; st << s->span() << "|" << n << "|" << c->status(); } } @@ -1426,8 +1491,9 @@ void ZaptelPlugin::initialize() } if (m_spans.count()) { Output("Created %d spans",m_spans.count()); - Engine::install(new ZapHandler("call")); - Engine::install(new ZapDropper("drop")); + Engine::install(new ZapHandler); + Engine::install(new ZapDropper); + Engine::install(new ZapDTMF); Engine::install(new StatusHandler); } else diff --git a/scripts/dtmf1.pl b/scripts/dtmf1.pl index 63a67512..6d195e56 100755 --- a/scripts/dtmf1.pl +++ b/scripts/dtmf1.pl @@ -16,7 +16,7 @@ sub OnNotify($) { } my $message = new YateMessage(); -$message->install("dtmf",\&OnDTMF,10); -$message->install("notify",\&OnNotify); +$message->install("chan.dtmf",\&OnDTMF,10); +$message->install("chan.notify",\&OnNotify); $message->listen(); diff --git a/scripts/noroute.pl b/scripts/noroute.pl index 4453c992..e344c8be 100755 --- a/scripts/noroute.pl +++ b/scripts/noroute.pl @@ -29,5 +29,5 @@ sub demo2($) { my $message = new YateMessage(); $message->install("engine.timer",\&demo); -$message->install("route",\&demo2); +$message->install("call.route",\&demo2); $message->listen(); diff --git a/scripts/route.php b/scripts/route.php index 13a2c3ff..49367501 100755 --- a/scripts/route.php +++ b/scripts/route.php @@ -13,8 +13,8 @@ Yate::Init(); /* Install a handler for the engine generated timer message */ //Yate::Install("engine.timer",10); -Yate::Install("dtmf",10); -Yate::Install("sms",10); +Yate::Install("chan.dtmf",10); +Yate::Install("chan.text",10); /* Create and dispatch an initial test message */ /*$m=new Yate("test"); @@ -49,7 +49,7 @@ for (;;) { $ev->handled = true; /* This is extremely important. We MUST let messages return, handled or not */ - $m=new Yate("sms"); + $m=new Yate("chan.text"); $m->params["ourcallid"]= $ev->params["partycallid"]; $m->params["partycallid"]= $ev->params["ourcallid"]; $m->params["text"] = $ev->params["text"]; diff --git a/yatengine.h b/yatengine.h index 552f5d2b..a8da3b14 100644 --- a/yatengine.h +++ b/yatengine.h @@ -1197,6 +1197,13 @@ public: inline unsigned int length() const { return m_params.length(); } + /** + * Get the number of non-null parameters + * @return Count of existing named strings + */ + inline unsigned int count() const + { return m_params.count(); } + /** * Add a named string to the parameter list. * @param param Parameter to add diff --git a/yatephone.h b/yatephone.h index 1e815fda..885634f1 100644 --- a/yatephone.h +++ b/yatephone.h @@ -411,7 +411,8 @@ public: * Disconnect from the connected endpoint * @param reason Text that describes disconnect reason */ - void disconnect(const char *reason = 0); + inline void disconnect(const char *reason = 0) + { disconnect(false,reason); } /** * Set the data source of this object @@ -461,9 +462,10 @@ protected: /** * Disconnect notification method + * @param final True if this disconnect was called from the destructor * @param reason Text that describes disconnect reason */ - virtual void disconnected(const char *reason) { } + virtual void disconnected(bool final, const char *reason) { } /** * Attempt to connect the endpoint to a peer of the same type @@ -481,6 +483,7 @@ protected: void setPeer(DataEndpoint *peer, const char *reason = 0); private: + void disconnect(bool final, const char *reason); String m_name; DataSource *m_source; DataConsumer *m_consumer; diff --git a/yateversn.h.in b/yateversn.h.in new file mode 100644 index 00000000..e928f8fc --- /dev/null +++ b/yateversn.h.in @@ -0,0 +1,15 @@ +/** + * yateversn.h + * This file is part of the YATE Project http://YATE.null.ro + * + * This is a generated file. You should never need to modify it. + */ + +#ifndef __YATEVERSN_H +#define __YATEVERSN_H + +#define YATE_MAJOR @PACKAGE_VERSION_MAJOR@ +#define YATE_MINOR @PACKAGE_VERSION_MINOR@ +#define YATE_BUILD @PACKAGE_VERSION_BUILD@ + +#endif /* __YATEVERSN_H */