Added caller channel id in rmanager output.

Analyzer outputs quality estimation.


git-svn-id: http://yate.null.ro/svn/yate/trunk@707 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
paulc 2006-02-28 14:39:58 +00:00
parent fff299e2a8
commit 2e625f110d
5 changed files with 135 additions and 33 deletions

View File

@ -30,6 +30,13 @@
#include <yatephone.h>
// minimum allowed for the maximum
#define ALLOW_MIN 2500.0
// threshold from max we consider a peak
#define PEAKS_THR 0.015
// expected number of peaks
#define PEAKS_NUM 2
#include <string.h>
#include <stdio.h>
#include <math.h>
@ -64,15 +71,21 @@ public:
};
virtual ~AsyncFFT();
static AsyncFFT* create(unsigned int length, WinType window = Rectangle, Priority prio = Low);
inline unsigned int length() const
inline unsigned int samples() const
{ return m_length; }
inline unsigned int length() const
{ return m_length >> 1; }
inline bool ready() const
{ return m_ready; }
double operator[](int index) const;
bool prepare(const short* samples);
double at(int index) const;
inline double operator[](int index) const
{ return at(index); }
bool prepare(const short* samp);
inline void stop()
{ m_stop = true; }
{ m_notify = 0; m_stop = true; }
virtual void run();
inline void setNotify(Runnable* notified = 0)
{ m_notify = notified; }
private:
AsyncFFT(unsigned int length, WinType window, Priority prio);
void buildWindow(WinType window);
@ -81,14 +94,16 @@ private:
bool m_ready;
bool m_start;
bool m_stop;
Runnable* m_notify;
unsigned int m_length;
double* m_window;
double* m_real;
double* m_imag;
unsigned int m_nBits;
const char* m_winName;
};
class AnalyzerCons : public DataConsumer
class AnalyzerCons : public DataConsumer, public Runnable
{
YCLASS(AnalyzerCons,DataConsumer)
public:
@ -96,6 +111,7 @@ public:
virtual ~AnalyzerCons();
virtual void Consume(const DataBlock& data, unsigned long tStamp);
virtual void statusParams(String& str);
virtual void run();
protected:
DataBlock m_data;
u_int64_t m_timeStart;
@ -103,6 +119,9 @@ protected:
unsigned int m_tsGapCount;
unsigned long m_tsGapLength;
AsyncFFT* m_spectrum;
unsigned long m_total;
unsigned long m_valid;
bool m_analyze;
};
class AnalyzerChan : public Channel
@ -148,9 +167,9 @@ private:
INIT_PLUGIN(AnalyzerDriver);
static TokenDict dict_windows[] = {
{ "rectangle", AsyncFFT::Rectangle },
{ "no", AsyncFFT::None },
{ "none", AsyncFFT::None },
{ "rectangle", AsyncFFT::Rectangle },
{ "triangle", AsyncFFT::Triangle },
{ "bartlett", AsyncFFT::Bartlett },
{ "hanning", AsyncFFT::Hanning },
@ -160,6 +179,8 @@ static TokenDict dict_windows[] = {
{ 0, 0 }
};
static Mutex s_mutex;
static int s_res = 1;
static const char* printTime(char* buf,unsigned long usec)
@ -198,8 +219,9 @@ AsyncFFT* AsyncFFT::create(unsigned int length, WinType window, Priority prio)
}
AsyncFFT::AsyncFFT(unsigned int length, WinType window, Priority prio)
: Thread("AsyncFFT",prio), m_ready(false), m_start(false), m_stop(false),
m_length(0), m_window(0), m_real(0), m_imag(0), m_nBits(0)
: Thread("AsyncFFT",prio),
m_ready(false), m_start(false), m_stop(false), m_notify(0),
m_length(0), m_window(0), m_real(0), m_imag(0), m_nBits(0), m_winName(0)
{
DDebug(&__plugin,DebugAll,"AsyncFFT::AsyncFFT(%u) [%p]",length,this);
for (unsigned int i = 0; i <= 256 ;i++)
@ -218,6 +240,7 @@ AsyncFFT::AsyncFFT(unsigned int length, WinType window, Priority prio)
AsyncFFT::~AsyncFFT()
{
DDebug(&__plugin,DebugAll,"AsyncFFT::~AsyncFFT() [%p]",this);
m_notify = 0;
m_ready = false;
m_start = false;
delete[] m_real;
@ -227,6 +250,7 @@ AsyncFFT::~AsyncFFT()
void AsyncFFT::buildWindow(WinType window)
{
m_winName = lookup(window,dict_windows);
if (window == Rectangle)
return;
m_window = new double[m_length];
@ -261,7 +285,7 @@ void AsyncFFT::buildWindow(WinType window)
}
}
double AsyncFFT::operator[](int index) const
double AsyncFFT::at(int index) const
{
if ((index < 0) || ((unsigned int)index > (m_length >> 1)))
return 0.0;
@ -282,13 +306,17 @@ void AsyncFFT::run()
m_ready = false;
compute();
m_ready = true;
s_mutex.lock();
if (m_notify)
m_notify->run();
s_mutex.unlock();
m_start = false;
}
}
bool AsyncFFT::prepare(const short* samples)
bool AsyncFFT::prepare(const short* samp)
{
if (m_start || m_stop || !(samples && m_real))
if (m_start || m_stop || !(samp && m_real))
return false;
m_ready = false;
XDebug(&__plugin,DebugAll,"Preparing FFT buffer from %u samples [%p]",m_length,this);
@ -296,9 +324,9 @@ bool AsyncFFT::prepare(const short* samples)
for (i = 0; i < m_length; i++) {
j = revBits(i);
if (m_window)
m_real[i] = m_window[j] * samples[j];
m_real[i] = m_window[j] * samp[j];
else
m_real[i] = samples[j];
m_real[i] = samp[j];
m_imag[i] = 0.0;
}
m_start = true;
@ -318,7 +346,7 @@ unsigned int AsyncFFT::revBits(unsigned int index)
void AsyncFFT::compute()
{
#ifdef XDEBUG
Debug(&__plugin,DebugAll,"Computing FFT with length %u [%p]",m_length,this);
Debug(&__plugin,DebugInfo,"Computing FFT with length %u [%p]",m_length,this);
Time t;
#endif
unsigned int i, j, n;
@ -363,26 +391,29 @@ void AsyncFFT::compute()
for (i = 0; i < n; i++)
m_real[i] = ::sqrt(m_real[i]*m_real[i] + m_imag[i]*m_imag[i]) / n;
#ifdef XDEBUG
Debug(&__plugin,DebugAll,"Computing FFT with length %u took " FMT64U " usec [%p]",
Debug(&__plugin,DebugInfo,"Computing FFT with length %u took " FMT64U " usec [%p]",
m_length,Time::now()-t,this);
#endif
for (i = 0; i < n; i ++) {
Output("fft[%u] = %0.2f",i,m_real[i]);
}
#ifdef XDEBUG
for (i = 0; i < n; i++)
Debug(&__plugin,DebugAll,"fft[%u] = %0.2f",i,m_real[i]);
#endif
}
AnalyzerCons::AnalyzerCons(const String& type, const char* window)
: m_timeStart(0), m_tsStart(0), m_tsGapCount(0), m_tsGapLength(0),
m_spectrum(false)
m_spectrum(false), m_total(0), m_valid(0), m_analyze(false)
{
DDebug(&__plugin,DebugAll,"AnalyzerCons::AnalyzerCons('%s') [%p]",
type.c_str(),this);
unsigned int len = 0;
if ((type == "spectrum") || type.startsWith("tone/probe")) {
if ((type == "probe") || type.startsWith("tone/probe")) {
len = 256;
m_analyze = true;
m_spectrum = AsyncFFT::create(len,(AsyncFFT::WinType)lookup(window,dict_windows,AsyncFFT::Rectangle));
m_spectrum->setNotify(this);
return;
}
else if (type == "fft1024")
@ -395,18 +426,22 @@ AnalyzerCons::AnalyzerCons(const String& type, const char* window)
len = 128;
else if (type == "fft64")
len = 64;
if (len)
if (len) {
m_spectrum = AsyncFFT::create(len,(AsyncFFT::WinType)lookup(window,dict_windows,AsyncFFT::Triangle));
m_spectrum->setNotify(this);
}
}
AnalyzerCons::~AnalyzerCons()
{
DDebug(&__plugin,DebugAll,"AnalyzerCons::~AnalyzerCons() %p [%p]",m_spectrum,this);
s_mutex.lock();
if (m_spectrum) {
AsyncFFT* tmp = m_spectrum;
m_spectrum = 0;
tmp->stop();
}
s_mutex.unlock();
}
void AnalyzerCons::Consume(const DataBlock& data, unsigned long tStamp)
@ -430,7 +465,7 @@ void AnalyzerCons::Consume(const DataBlock& data, unsigned long tStamp)
if (!m_spectrum)
return;
m_data += data;
unsigned int len = 2 * m_spectrum->length();
unsigned int len = 2 * m_spectrum->samples();
if (m_data.length() < len)
return;
// limit the length of the buffer
@ -443,6 +478,44 @@ void AnalyzerCons::Consume(const DataBlock& data, unsigned long tStamp)
m_data.cut(-(int)len);
}
void AnalyzerCons::run()
{
// this method is called with the mutex hold
if (!m_spectrum)
return;
unsigned int n = m_spectrum->length();
double max = 0.0;
unsigned int i;
for (i = 1; i < n; i++) {
double val = m_spectrum->at(i);
if (max < val)
max = val;
}
if (!m_analyze)
return;
double limit = max;
if (max < ALLOW_MIN) {
// don't start until we get some data
if (!m_total)
return;
limit = ALLOW_MIN;
}
unsigned int peaks = 0;
limit *= PEAKS_THR;
for (i = 1; i < n; i++) {
if (m_spectrum->at(i) > limit)
peaks++;
}
DDebug(&__plugin,DebugInfo,"Got %u peaks, limit=%f, max=%f [%p]",peaks,limit,max,this);
m_total++;
if (peaks == PEAKS_NUM)
m_valid++;
}
void AnalyzerCons::statusParams(String& str)
{
unsigned long samples = timeStamp() - m_tsStart;
@ -454,6 +527,12 @@ void AnalyzerCons::statusParams(String& str)
utime = utime ? ((1000000 * (u_int64_t)samples) + (utime / 2)) / utime : 0;
str << ",rate=" << (unsigned int)utime;
}
if (m_total > 0) {
double q = m_valid * 100.0 / m_total;
char buf[64];
snprintf(buf,sizeof(buf)-1,"quality=%0.2f",q);
str.append(buf,",");
}
}
@ -478,7 +557,7 @@ AnalyzerChan::~AnalyzerChan()
str.append("totaltime=",",") << buf;
if (cons)
cons->statusParams(str);
Output("Analyzer %s finished: %s",id().c_str(),str.c_str());
Output("Finished '%s' status: %s",id().c_str(),str.c_str());
Engine::enqueue(message("chan.hangup"));
}
@ -556,7 +635,7 @@ void AnalyzerChan::addSource()
{
if (getSource())
return;
const char* src = "tone/dial";
const char* src = "tone/probe";
if (m_address.startsWith("tone/"))
src = m_address;
Message m("chan.attach");
@ -600,6 +679,7 @@ bool AnalyzerDriver::startCall(NamedList& params, const String& dest)
if (tmp.null())
tmp << prefix() << dest;
m->addParam("caller",tmp);
params.setParam("id",ac->id());
return ac->startRouter(m);
}

View File

@ -325,6 +325,7 @@ bool MOHHandler::received(Message &msg)
m.setParam("id",mc->id());
m.userData(mc);
if (Engine::dispatch(m)) {
msg.setParam("id",mc->id());
mc->deref();
return true;
}

View File

@ -39,6 +39,7 @@ static const char s_helpmsg[] =
" help [command]\n"
" status [module]\n"
" machine [on|off]\n"
" output [on|off]\n"
" auth password\n"
"Authenticated commands:\n"
" debug [level|on|off]\n"
@ -84,6 +85,7 @@ public:
private:
bool m_auth;
bool m_debug;
bool m_output;
bool m_machine;
Socket* m_socket;
String m_address;
@ -158,7 +160,8 @@ Connection *Connection::checkCreate(Socket* sock, const char* addr)
Connection::Connection(Socket* sock, const char* addr)
: Thread("RManager Connection"),
m_auth(false), m_debug(false), m_machine(false), m_socket(sock), m_address(addr)
m_auth(false), m_debug(false), m_output(true), m_machine(false),
m_socket(sock), m_address(addr)
{
s_mutex.lock();
connectionlist.append(this);
@ -168,6 +171,7 @@ Connection::Connection(Socket* sock, const char* addr)
Connection::~Connection()
{
m_debug = false;
m_output = false;
s_mutex.lock();
connectionlist.remove(this,false);
s_mutex.unlock();
@ -283,6 +287,14 @@ bool Connection::processLine(const char *line)
writeStr(str);
return false;
}
else if (str.startSkip("output"))
{
str >> m_output;
str = "Output mode: ";
str += (m_output ? "on\n" : "off\n");
writeStr(str);
return false;
}
else if (str.startSkip("quit"))
{
writeStr(m_machine ? "%%=quit\n" : "Goodbye!\n");
@ -360,8 +372,13 @@ bool Connection::processLine(const char *line)
m.addParam("callto",str.substr(0,pos));
m.addParam((target.find('/') > 0) ? "direct" : "target",target);
if (Engine::dispatch(m))
str = (m_machine ? "%%=call:success:" : "Called ") + str + "\n";
if (Engine::dispatch(m)) {
String id(m.getValue("id"));
if (m_machine)
str = "%%=call:success:" + id + ":" + str + "\n";
else
str = "Calling '" + id + "' " + str + "\n";
}
else
str = (m_machine ? "%%=call:fail:" : "Could not call ") + str + "\n";
writeStr(str);
@ -460,7 +477,9 @@ void Connection::writeStr(const Message &msg, bool received)
void Connection::writeDebug(const char *str, int level)
{
if (m_debug && !null(str))
if (null(str))
return;
if (m_debug || (m_output && (level < 0)))
writeStr(str,::strlen(str));
}

View File

@ -252,9 +252,9 @@ static const ToneDesc s_desc[] = {
{ t_dtmf[13], "dtmf/b", "b" },
{ t_dtmf[14], "dtmf/c", "c" },
{ t_dtmf[15], "dtmf/d", "d" },
{ t_probes[0], "probe/1", "test1" },
{ t_probes[1], "probe/2", "test2" },
{ t_probes[2], "probe/3", "test3" },
{ t_probes[0], "probe/0", "probe" },
{ t_probes[1], "probe/1", 0 },
{ t_probes[2], "probe/2", 0 },
{ 0, 0, 0 }
};
@ -666,9 +666,10 @@ bool ToneGenDriver::msgExecute(Message& msg, String& dest)
m = "call.execute";
m.addParam("callto",callto);
ToneChan *tc = new ToneChan(dest);
m.setParam("targetid",tc->id());
m.setParam("id",tc->id());
m.userData(tc);
if (Engine::dispatch(m)) {
msg.setParam("id",tc->id());
tc->deref();
return true;
}

View File

@ -716,9 +716,10 @@ bool WaveFileDriver::msgExecute(Message& msg, String& dest)
m = "call.execute";
m.addParam("callto",callto);
WaveChan *c = new WaveChan(dest.matchString(2),meth,maxlen);
m.setParam("targetid",c->id());
m.setParam("id",c->id());
m.userData(c);
if (Engine::dispatch(m)) {
msg.setParam("id",c->id());
c->deref();
return true;
}