Commits

Anonymous committed a81664a Draft

Lots of thread interlocking fixes, extra H.323 options for inband DTMF and
silence detection suppression.

  • Participants
  • Parent commits 5e17194

Comments (0)

Files changed (8)

File conf.d/h323chan.conf.sample

 ; maxconns: int: Maximum number of simultaneous connections (0 = no limit)
 ;maxconns = 0
 
+; dtmfinband: bool: Wheter to decode inband DTMF (CPU intensive)
+;dtmfinband = false
+
+; silencedetect: keyword: Silence detection algorithm: none, fixed, adaptive
+;silencedetect = none
+
 ; gkclient: bool: If h323 module endpoint should register to a gatekeeper
 gkclient = false
 

File engine/Mutex.cpp

 	m_locked = false;
 	if (--s_locks < 0) {
 	    GlobalMutex::unlock();
-	    Debug(DebugFail,"MutexPrivate::locks() is %d",s_locks);
+	    Debug(DebugFail,"MutexPrivate::locks() is %d [%p]",s_locks,this);
 	    GlobalMutex::lock();
 	}
 	::pthread_mutex_unlock(&m_mutex);
     }
     else {
 	GlobalMutex::unlock();
-	Debug(DebugFail,"MutexPrivate::unlock called on unlocked mutex");
+	Debug(DebugFail,"MutexPrivate::unlock called on unlocked mutex [%p]",this);
     }
 }
 
 	m_private->unlock();
 }
 
+bool Mutex::check(long long int maxwait)
+{
+    bool ret = lock(maxwait);
+    if (ret)
+	unlock();
+    return ret;
+}
+
 int Mutex::count()
 {
     return MutexPrivate::s_count;

File engine/TelEngine.cpp

 static void (*s_intout)(const char *) = 0;
 
 static Mutex out_mux;
+static Mutex ind_mux;
 
 static void common_output(char *buf)
 {
 	::sprintf(buf,"<%d> ",level);
 	va_list va;
 	va_start(va,format);
+	ind_mux.lock();
 	dbg_output(buf,format,va);
+	ind_mux.unlock();
 	va_end(va);
 	if (s_abort && (level == DebugFail))
 	    abort();
 	::snprintf(buf,sizeof(buf),"<%s:%d> ",facility,level);
 	va_list va;
 	va_start(va,format);
+	ind_mux.lock();
 	dbg_output(buf,format,va);
+	ind_mux.unlock();
 	va_end(va);
 	if (s_abort && (level == DebugFail))
 	    abort();
 	::snprintf(buf,sizeof(buf),">>> %s",m_name);
 	va_list va;
 	va_start(va,format);
+	ind_mux.lock();
 	dbg_output(buf,format,va);
 	va_end(va);
-	out_mux.lock();
 	s_indent++;
-	out_mux.unlock();
+	ind_mux.unlock();
     }
     else
 	m_name = 0;
 	::snprintf(buf,sizeof(buf),">>> %s",m_name);
 	va_list va;
 	va_start(va,format);
+	ind_mux.lock();
 	dbg_output(buf,format,va);
 	va_end(va);
-	out_mux.lock();
 	s_indent++;
-	out_mux.unlock();
+	ind_mux.unlock();
     }
     else
 	m_name = 0;
 Debugger::~Debugger()
 {
     if (m_name) {
-	out_mux.lock();
+	ind_mux.lock();
 	s_indent--;
-	out_mux.unlock();
 	if (s_debugging) {
 	    char buf[64];
 	    ::snprintf(buf,sizeof(buf),"<<< %s",m_name);
 	    va_list va = 0;
 	    dbg_output(buf,format,va);
 	}
+	ind_mux.unlock();
     }
 }
 

File modules/h323chan.cpp

     { 0 , 0 },
 };
 
+static TokenDict dict_silence[] = {
+    { "none", H323AudioCodec::NoSilenceDetection },
+    { "fixed", H323AudioCodec::FixedSilenceDetection },
+    { "adaptive", H323AudioCodec::AdaptiveSilenceDetection },
+    { 0 , 0 },
+};
+
 class H323Process : public PProcess
 {
     PCLASSINFO(H323Process, PProcess)
     virtual BOOL Read(void *buf, PINDEX len);
     virtual void Consume(const DataBlock &data, unsigned long timeDelta);
 private:
+    PAdaptiveDelay readDelay;
     DataBlock m_buffer;
     bool m_exit;
     Mutex m_mutex;
 
     AddAllUserInputCapabilities(0,1);
     DisableDetectInBandDTMF(!s_cfg.getBoolValue("ep","dtmfinband",false));
+    SetSilenceDetectionMode(static_cast<H323AudioCodec::SilenceDetectionMode>
+	(s_cfg.getIntValue("ep","silencedetect",dict_silence,H323AudioCodec::NoSilenceDetection)));
 
     PIPSocket::Address addr = INADDR_ANY;
     int port = s_cfg.getIntValue("ep","port",1720);
     Debug(DebugAll,"h.323 consumer [%p] deleted",this);
     m_exit = true;
     // Delay actual destruction until the mutex is released
-    m_mutex.lock();
-    m_mutex.unlock();
+    m_mutex.check();
 }
 
 BOOL YateH323AudioConsumer::Close()
 {
+    Debug(DebugAll,"h.323 consumer [%p] closed",this);
     m_exit = true;
     return true;
 }
 {
     while (!m_exit) {
 	Lock lock(m_mutex);
+	if (!getConnSource()) {
+	    ::memset(buf,0,len);
+	    readDelay.Delay(len/16);
+	    break;
+	}
 	if (len >= (int)m_buffer.length()) {
+	    lock.drop();
 	    Thread::yield();
 	    if (m_exit || Engine::exiting())
 		return false;
 
 BOOL YateH323AudioSource::Close()
 {
+    Debug(DebugAll,"h.323 source [%p] closed",this);
     m_exit = true;
     return true;
 }

File modules/rmanager.cpp

 	Message m("help");
 	if (!str.null())
 	{
-	    m.addParam("command",str);
+	    m.addParam("line",str);
 	    if (Engine::dispatch(m))
 		write(m.retValue());
 	    else

File modules/tonegen.cpp

 
 static ObjList tones;
 static ObjList chans;
+static Mutex mutex;
 
 typedef struct {
     int nsamples;
 
 ToneSource::~ToneSource()
 {
+    Lock lock(mutex);
     Debug(DebugAll,"ToneSource::~ToneSource() [%p] total=%u stamp=%lu",this,m_total,timeStamp());
     if (m_time) {
 	m_time = Time::now() - m_time;
 
 ToneSource *ToneSource::getTone(const String &tone)
 {
+    Lock lock(mutex);
     ObjList *l = &tones;
     for (; l; l = l->next()) {
 	ToneSource *t = static_cast<ToneSource *>(l->get());
     : DataEndpoint("tone")
 {
     Debug(DebugAll,"ToneChan::ToneChan(\"%s\") [%p]",tone.c_str(),this);
+    mutex.lock();
     chans.append(this);
+    mutex.unlock();
     ToneSource *t = ToneSource::getTone(tone);
     if (t) {
 	setSource(t);
 ToneChan::~ToneChan()
 {
     Debug(DebugAll,"ToneChan::~ToneChan() [%p]",this);
+    mutex.lock();
     chans.remove(this,false);
+    mutex.unlock();
 }
 
 void ToneChan::disconnected()
 {
     Debugger debug("ToneChan::disconnected()"," [%p]",this);
-    destruct();
 }
 
 bool ToneHandler::received(Message &msg)
 	return false;
     String tone = dest.matchString(1);
     DataEndpoint *dd = static_cast<DataEndpoint *>(msg.userData());
-    if (dd)
-	dd->connect(new ToneChan(tone));
+    if (dd) {
+	ToneChan *tc = new ToneChan(tone);
+	if (dd->connect(tc))
+	    tc->deref();
+	else {
+	    tc->destruct();
+	    return false;
+	}
+    }
     else {
 	const char *targ = msg.getValue("target");
 	if (!targ) {
 	    m.retValue() = 0;
 	    ToneChan *tc = new ToneChan(dest.matchString(1).c_str());
 	    m.userData(tc);
-	    if (Engine::dispatch(m))
+	    if (Engine::dispatch(m)) {
+		tc->deref();
 		return true;
+	    }
 	    Debug(DebugWarn,"Tone outgoing call not accepted!");
-	    delete tc;
+	    tc->destruct();
 	}
 	else
 	    Debug(DebugWarn,"Tone outgoing call but no route!");

File modules/wavefile.cpp

 void WaveChan::disconnected()
 {
     Debugger debug("WaveChan::disconnected()"," [%p]",this);
-    destruct();
 }
 
 bool WaveHandler::received(Message &msg)
     if (dd) {
 	Debug(DebugInfo,"%s wave file '%s'", (meth ? "Record to" : "Play from"),
 	    dest.matchString(2).c_str());
-	dd->connect(new WaveChan(dest.matchString(2),meth,maxlen));
-	return true;
+	WaveChan *c = new WaveChan(dest.matchString(2),meth,maxlen);
+	if (dd->connect(c)) {
+	    c->deref();
+	    return true;
+	}
+	else {
+	    c->destruct();
+	    return false;
+	}
     }
 
     const char *targ = msg.getValue("target");
 	m.retValue() = 0;
 	WaveChan *c = new WaveChan(dest.matchString(2),meth,maxlen);
 	m.userData(c);
-	if (Engine::dispatch(m))
+	if (Engine::dispatch(m)) {
+	    c->deref();
 	    return true;
+	}
 	Debug(DebugWarn,"Wave outgoing call not accepted!");
-	delete c;
+	c->destruct();
     }
     else
 	Debug(DebugWarn,"Wave outgoing call but no route!");
     void unlock();
 
     /**
+     * Check if the mutex is unlocked (try to lock and unlock the mutex)
+     * @param maxait Time in microseconds to wait for the mutex, -1 wait forever
+     * @return True if successfully locked and unlocked, false on failure
+     */
+    bool check(long long int maxwait = -1);
+
+    /**
      * Get the number of mutexes counting the shared ones only once
      * @return Count of individual mutexes
      */
     inline Mutex *mutex() const
 	{ return m_mutex; }
 
+    /**
+     * Unlock the mutex if it was locked and drop the reference to it
+     */
+    inline void drop()
+	{ if (m_mutex) m_mutex->unlock(); m_mutex = 0; }
+
 private:
     Mutex *m_mutex;
 };