From d6b03a2919286ffca806447fa2e16efe1cba025e Mon Sep 17 00:00:00 2001 From: paulc Date: Mon, 30 May 2005 15:13:02 +0000 Subject: [PATCH] no message git-svn-id: http://yate.null.ro/svn/yate/trunk@378 acf43c95-373e-0410-b603-e72c3f656dc1 --- engine/DataFormat.cpp | 100 +++++++++++++++++++++++++++++++++++++----- engine/Thread.cpp | 7 +-- modules/wavefile.cpp | 89 +++++++++++++++++++++++++++++++++++++ yatengine.h | 8 ++++ yatephone.h | 30 +++++++++++++ 5 files changed, 217 insertions(+), 17 deletions(-) diff --git a/engine/DataFormat.cpp b/engine/DataFormat.cpp index 1cb1c51f..71c22ad5 100644 --- a/engine/DataFormat.cpp +++ b/engine/DataFormat.cpp @@ -232,7 +232,9 @@ void* DataSource::getObject(const String& name) const } DataEndpoint::DataEndpoint(CallEndpoint* call, const char* name) - : m_name(name), m_source(0), m_consumer(0), m_peer(0), m_call(call) + : m_name(name), m_source(0), m_consumer(0), + m_peer(0), m_call(call), + m_peerRecord(0), m_callRecord(0) { Debug(DebugInfo,"DataEndpoint::DataEndpoint(%p,'%s') [%p]",call,name,this); if (m_call) @@ -246,6 +248,8 @@ DataEndpoint::~DataEndpoint() if (m_call) m_call->m_data.remove(this,false); disconnect(); + setPeerRecord(); + setCallRecord(); setSource(); setConsumer(); } @@ -281,6 +285,9 @@ bool DataEndpoint::connect(DataEndpoint* peer) if (!native) { DataSource *s = getSource(); DataConsumer *c = peer->getConsumer(); + if (s && c) + DataTranslator::attachChain(s,c); + c = peer->getPeerRecord(); if (s && c) DataTranslator::attachChain(s,c); @@ -288,6 +295,9 @@ bool DataEndpoint::connect(DataEndpoint* peer) c = getConsumer(); if (s && c) DataTranslator::attachChain(s,c); + c = getPeerRecord(); + if (s && c) + DataTranslator::attachChain(s,c); } m_peer = peer; @@ -304,11 +314,17 @@ void DataEndpoint::disconnect() DataSource *s = getSource(); DataConsumer *c = m_peer->getConsumer(); + if (s && c) + DataTranslator::detachChain(s,c); + c = m_peer->getPeerRecord(); if (s && c) DataTranslator::detachChain(s,c); s = m_peer->getSource(); c = getConsumer(); + if (s && c) + DataTranslator::detachChain(s,c); + c = getPeerRecord(); if (s && c) DataTranslator::detachChain(s,c); @@ -323,27 +339,50 @@ void DataEndpoint::setSource(DataSource* source) { if (source == m_source) return; - DataConsumer *consumer = m_peer ? m_peer->getConsumer() : 0; + DataConsumer *c1 = m_peer ? m_peer->getConsumer() : 0; + DataConsumer *c2 = m_peer ? m_peer->getPeerRecord() : 0; DataSource *temp = m_source; - if (consumer) - consumer->ref(); + if (c1) + c1->ref(); + if (c2) + c2->ref(); + if (m_callRecord) + m_callRecord->ref(); m_source = 0; if (temp) { - if (consumer) { - DataTranslator::detachChain(temp,consumer); - if (consumer->getConnSource()) - Debug(DebugWarn,"consumer source not cleared in %p",consumer); + if (c1) { + DataTranslator::detachChain(temp,c1); + if (c1->getConnSource()) + Debug(DebugWarn,"consumer source not cleared in %p",c1); + } + if (c2) { + DataTranslator::detachChain(temp,c2); + if (c2->getConnSource()) + Debug(DebugWarn,"consumer source not cleared in %p",c2); + } + if (m_callRecord) { + DataTranslator::detachChain(temp,m_callRecord); + if (m_callRecord->getConnSource()) + Debug(DebugWarn,"consumer source not cleared in %p",m_callRecord); } temp->deref(); } if (source) { source->ref(); - if (consumer) - DataTranslator::attachChain(source,consumer); + if (c1) + DataTranslator::attachChain(source,c1); + if (c2) + DataTranslator::attachChain(source,c2); + if (m_callRecord) + DataTranslator::attachChain(source,m_callRecord); } m_source = source; - if (consumer) - consumer->deref(); + if (c1) + c1->deref(); + if (c2) + c2->deref(); + if (m_callRecord) + m_callRecord->deref(); } void DataEndpoint::setConsumer(DataConsumer* consumer) @@ -365,6 +404,43 @@ void DataEndpoint::setConsumer(DataConsumer* consumer) } } +void DataEndpoint::setPeerRecord(DataConsumer* consumer) +{ + if (consumer == m_peerRecord) + return; + DataSource *source = m_peer ? m_peer->getSource() : 0; + DataConsumer *temp = m_peerRecord; + if (consumer) { + consumer->ref(); + if (source) + DataTranslator::attachChain(source,consumer); + } + m_peerRecord = consumer; + if (temp) { + if (source) + DataTranslator::detachChain(source,temp); + temp->deref(); + } +} + +void DataEndpoint::setCallRecord(DataConsumer* consumer) +{ + if (consumer == m_callRecord) + return; + DataConsumer *temp = m_callRecord; + if (consumer) { + consumer->ref(); + if (m_source) + DataTranslator::attachChain(m_source,consumer); + } + m_callRecord = consumer; + if (temp) { + if (m_source) + DataTranslator::detachChain(m_source,temp); + temp->deref(); + } +} + ThreadedSource::~ThreadedSource() { stop(); diff --git a/engine/Thread.cpp b/engine/Thread.cpp index 3dd83f95..4d7e5bce 100644 --- a/engine/Thread.cpp +++ b/engine/Thread.cpp @@ -310,22 +310,19 @@ void ThreadPrivate::killall() while (l && (t = static_cast(l->get())) != 0) { Debug(DebugInfo,"Trying to kill ThreadPrivate '%s' [%p], attempt %d",t->m_name,t,c); - tmutex.unlock(); bool ok = t->cancel(c > SOFT_KILLS); if (ok) { int d = 0; // delay a little (exponentially) so threads have a chance to clean up for (int i=1; i<=KILL_WAIT; i<<=1) { + tmutex.unlock(); Thread::msleep(i-d); d = i; tmutex.lock(); - bool done = (t != l->get()); - tmutex.unlock(); - if (done) + if (t != l->get()) break; } } - tmutex.lock(); if (t != l->get()) c = 1; else { diff --git a/modules/wavefile.cpp b/modules/wavefile.cpp index 565c1e22..3d57ca9f 100644 --- a/modules/wavefile.cpp +++ b/modules/wavefile.cpp @@ -97,6 +97,13 @@ public: virtual bool received(Message &msg); }; +class RecordHandler : public MessageHandler +{ +public: + RecordHandler() : MessageHandler("chan.record") { } + virtual bool received(Message &msg); +}; + class WaveFileDriver : public Driver { public: @@ -430,6 +437,87 @@ bool AttachHandler::received(Message &msg) return !more; } +bool RecordHandler::received(Message &msg) +{ + int more = 2; + + String c1(msg.getValue("call")); + if (c1.null()) + more--; + else { + Regexp r("^wave/\\([^/]*\\)/\\(.*\\)$"); + if (c1.matches(r)) { + if (c1.matchString(1) == "record") { + c1 = c1.matchString(2); + more--; + } + else { + Debug(DebugWarn,"Could not attach call recorder with method '%s', use 'record'", + c1.matchString(1).c_str()); + c1 = ""; + } + } + else + c1 = ""; + } + + String c2(msg.getValue("peer")); + if (c2.null()) + more--; + else { + Regexp r("^wave/\\([^/]*\\)/\\(.*\\)$"); + if (c2.matches(r)) { + if (c2.matchString(1) == "record") { + c2 = c2.matchString(2); + more--; + } + else { + Debug(DebugWarn,"Could not attach peer recorder with method '%s', use 'record'", + c2.matchString(1).c_str()); + c2 = ""; + } + } + else + c2 = ""; + } + + if (c1.null() && c2.null()) + return false; + + String ml(msg.getValue("maxlen")); + unsigned maxlen = ml.toInteger(0); + + CallEndpoint *ch = static_cast(msg.userData("CallEndpoint")); + DataEndpoint *de = static_cast(msg.userData("DataEndpoint")); + if (ch && !de) + de = ch->setEndpoint(); + + if (!de) { + if (!c1.null()) + Debug(DebugWarn,"Wave source '%s' call record with no data channel!",c1.c_str()); + if (!c2.null()) + Debug(DebugWarn,"Wave source '%s' peer record with no data channel!",c2.c_str()); + return false; + } + + if (!c1.null()) { + WaveConsumer* c = new WaveConsumer(c1,ch,maxlen); + c->setNotify(msg.getValue("notify")); + de->setCallRecord(c); + c->deref(); + } + + if (!c2.null()) { + WaveConsumer* c = new WaveConsumer(c2,ch,maxlen); + c->setNotify(msg.getValue("notify")); + de->setPeerRecord(c); + c->deref(); + } + + // Stop dispatching if we handled all requested + return !more; +} + bool WaveFileDriver::msgExecute(Message& msg, String& dest) { Regexp r("^\\([^/]*\\)/\\(.*\\)$"); @@ -509,6 +597,7 @@ void WaveFileDriver::initialize() if (!m_handler) { m_handler = new AttachHandler; Engine::install(m_handler); + Engine::install(new RecordHandler); } } diff --git a/yatengine.h b/yatengine.h index 48e261db..a04bad69 100644 --- a/yatengine.h +++ b/yatengine.h @@ -235,6 +235,14 @@ public: inline RefObject* userData() const { return m_data; } + /** + * Get a pointer to a derived class of user data given that class name + * @param name Name of the class we are asking for + * @return Pointer to the requested class or NULL if user object id NULL or doesn't implement it + */ + inline void* userData(const String& name) const + { return m_data ? m_data->getObject(name) : 0; } + /** * Set obscure data associated with the message. * The user data is reference counted to avoid stray pointers. diff --git a/yatephone.h b/yatephone.h index 2f7d5919..12ff29ad 100644 --- a/yatephone.h +++ b/yatephone.h @@ -669,6 +669,34 @@ public: inline DataConsumer* getConsumer() const { return m_consumer; } + /** + * Set the data consumer for recording peer generated data. + * This will be connected to the peer data source. + * @param consumer A pointer to the new consumer or NULL + */ + void setPeerRecord(DataConsumer* consumer = 0); + + /** + * Get the data consumer used for recording peer generated data. + * @return A pointer to the DataConsumer object or NULL + */ + inline DataConsumer* getPeerRecord() const + { return m_peerRecord; } + + /** + * Set the data consumer for recording local call generated data + * This will be connected to the local data source. + * @param consumer A pointer to the new consumer or NULL + */ + void setCallRecord(DataConsumer* consumer = 0); + + /** + * Get the data consumer used for recording local call generated data. + * @return A pointer to the DataConsumer object or NULL + */ + inline DataConsumer* getCallRecord() const + { return m_callRecord; } + /* * Get a pointer to the peer endpoint * @return A pointer to the peer endpoint or NULL @@ -705,6 +733,8 @@ private: DataConsumer* m_consumer; DataEndpoint* m_peer; CallEndpoint* m_call; + DataConsumer* m_peerRecord; + DataConsumer* m_callRecord; }; /**