Merge branch 'master' of git.freeswitch.org:freeswitch

This commit is contained in:
Mathieu Parent 2010-04-08 20:52:30 +02:00
commit 917e152518
75 changed files with 4520 additions and 1946 deletions

80
.gitignore vendored
View File

@ -8,10 +8,10 @@
.deps .deps
.\#* .\#*
\#* \#*
Debug/ /Debug/
Release/ /Release/
All/ /All/
bin/ /bin/
*.user *.user
*.suo *.suo
*.ncb *.ncb
@ -26,43 +26,47 @@ bin/
*.manifest *.manifest
*.dep *.dep
*.dll *.dll
BuildLog.htm /BuildLog.htm
Path /Path
w32/Library/lastversion /w32/Library/lastversion
w32/Library/tmpVersion.Bat /w32/Library/tmpVersion.Bat
.version !/w32/Console/FreeSwitchConsole.vcproj.user
AUTHORS !/w32/Setup/inno_setup/vcredist_x64.exe
COPYING !/w32/Setup/inno_setup/vcredist_x86.exe
ChangeLog /.version
Makefile /AUTHORS
Makefile.in /COPYING
NEWS /ChangeLog
README /Makefile
/Makefile.in
/NEWS
/README
aclocal.m4 aclocal.m4
autom4te.cache autom4te.cache
build/Makefile /build/Makefile
build/Makefile.in /build/Makefile.in
build/config/compile /build/config/compile
build/config/config.guess /build/config/config.guess
build/config/depcomp /build/config/depcomp
build/config/install-sh /build/config/install-sh
build/config/ltmain.sh /build/config/ltmain.sh
build/config/missing /build/config/missing
build/freeswitch.pc /build/freeswitch.pc
build/getlib.sh /build/getlib.sh
build/getsounds.sh /build/getsounds.sh
build/modmake.rules /build/modmake.rules
config.cache config.cache
config.log config.log
config.status config.status
configure /configure
configure.lineno configure.lineno
freeswitch /freeswitch
fs_cli /fs_cli
fs_ivrd /fs_ivrd
libtool /libtool
modules.conf /modules.conf
quiet_libtool /quiet_libtool
scripts/fsxs /scripts/fsxs
scripts/gentls_cert /scripts/gentls_cert
a.out.dSYM /a.out.dSYM
/freeswitch-sounds-*

View File

@ -470,6 +470,7 @@ update: is-scm
echo Updating... ; \ echo Updating... ; \
svn update ; \ svn update ; \
elif test -d .git ; then \ elif test -d .git ; then \
test ! -f .version || rm -f .version ; \
echo "Pulling updates..." ; \ echo "Pulling updates..." ; \
git pull ; \ git pull ; \
else \ else \

32
fscomm/.gitignore vendored Normal file
View File

@ -0,0 +1,32 @@
*~
*.o
*.so
*.lo
*.a
*.la
.libs
.deps
.\#*
\#*
/Debug/
/Release/
/All/
/bin/
*.user
*.suo
*.ncb
*.pdb
*.map
*.lib
*.obj
*.idb
*.res
*.exp
*.exe
*.manifest
*.dep
*.dll
Makefile
fscomm
fscomm.exe
fscomm.app

View File

@ -31,7 +31,12 @@ SOURCES += main.cpp \
preferences/prefsofia.cpp \ preferences/prefsofia.cpp \
preferences/accountdialog.cpp \ preferences/accountdialog.cpp \
preferences/prefaccounts.cpp \ preferences/prefaccounts.cpp \
account.cpp account.cpp \
widgets/codecwidget.cpp \
channel.cpp \
debugtools/consolewindow.cpp \
debugtools/sortfilterproxymodel.cpp \
debugtools/statedebugdialog.cpp
HEADERS += mainwindow.h \ HEADERS += mainwindow.h \
fshost.h \ fshost.h \
call.h \ call.h \
@ -41,9 +46,17 @@ HEADERS += mainwindow.h \
preferences/prefsofia.h \ preferences/prefsofia.h \
preferences/accountdialog.h \ preferences/accountdialog.h \
preferences/prefaccounts.h \ preferences/prefaccounts.h \
account.h account.h \
widgets/codecwidget.h \
channel.h \
debugtools/consolewindow.h \
debugtools/sortfilterproxymodel.h \
debugtools/statedebugdialog.h
FORMS += mainwindow.ui \ FORMS += mainwindow.ui \
preferences/prefdialog.ui \ preferences/prefdialog.ui \
preferences/accountdialog.ui preferences/accountdialog.ui \
widgets/codecwidget.ui \
debugtools/consolewindow.ui \
debugtools/statedebugdialog.ui
RESOURCES += resources.qrc RESOURCES += resources.qrc
OTHER_FILES += conf/freeswitch.xml OTHER_FILES += conf/freeswitch.xml

View File

@ -33,16 +33,28 @@
Call::Call() Call::Call()
{ {
_answeredEpoch = 0;
} }
Call::Call(int call_id, QString cid_name, QString cid_number, fscomm_call_direction_t direction, QString uuid) : switch_status_t Call::toggleHold(bool holdPressed)
_call_id(call_id),
_cid_name(cid_name),
_cid_number(cid_number),
_direction(direction),
_uuid (uuid)
{ {
_isActive = false; if (_state != FSCOMM_CALL_STATE_ANSWERED) return SWITCH_STATUS_FALSE;
switch_stream_handle_t stream = { 0 };
SWITCH_STANDARD_STREAM(stream);
QString holdStr;
if (holdPressed)
{
holdStr = _channel.data()->getUuid();
}
else
{
holdStr = "off " + _channel.data()->getUuid();
}
switch_status_t st = switch_api_execute("uuid_hold", holdStr.toAscii().data(), NULL, &stream);
switch_safe_free(stream.data);
return st;
} }
switch_status_t Call::toggleRecord(bool startRecord) switch_status_t Call::toggleRecord(bool startRecord)
@ -56,14 +68,14 @@ switch_status_t Call::toggleRecord(bool startRecord)
_recording_filename = QString("%1/.fscomm/recordings/%2_%3.wav").arg( _recording_filename = QString("%1/.fscomm/recordings/%2_%3.wav").arg(
conf_dir.absolutePath(), conf_dir.absolutePath(),
QDateTime::currentDateTime().toString("yyyyMMddhhmmss"), QDateTime::currentDateTime().toString("yyyyMMddhhmmss"),
_cid_number); getCidNumber());
status = g_FSHost.sendCmd("uuid_record", QString("%1 start %2").arg(_uuid, _recording_filename).toAscii().data(),&result); status = g_FSHost.sendCmd("uuid_record", QString("%1 start %2").arg(getUuid(), _recording_filename).toAscii().data(),&result);
} }
else else
{ {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Stopping call recording on call [%s]\n", switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Stopping call recording on call [%s]\n",
_uuid.toAscii().data()); getUuid().toAscii().data());
status = g_FSHost.sendCmd("uuid_record", QString("%1 stop %2").arg(_uuid, _recording_filename).toAscii().data(),&result); status = g_FSHost.sendCmd("uuid_record", QString("%1 stop %2").arg(getUuid(), _recording_filename).toAscii().data(),&result);
} }
return status; return status;
@ -74,13 +86,29 @@ void Call::sendDTMF(QString digit)
QString result; QString result;
QString dtmf_string = QString("dtmf %1").arg(digit); QString dtmf_string = QString("dtmf %1").arg(digit);
if (g_FSHost.sendCmd("pa", dtmf_string.toAscii(), &result) == SWITCH_STATUS_FALSE) { if (g_FSHost.sendCmd("pa", dtmf_string.toAscii(), &result) == SWITCH_STATUS_FALSE) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not send DTMF digit %s on call[%s]", digit.toAscii().data(), _uuid.toAscii().data()); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not send DTMF digit %s on call[%s]", digit.toAscii().data(), getUuid().toAscii().data());
QMessageBox::critical(0, QWidget::tr("DTMF Error"), QWidget::tr("There was an error sending DTMF, please report this bug."), QMessageBox::Ok); QMessageBox::critical(0, QWidget::tr("DTMF Error"), QWidget::tr("There was an error sending DTMF, please report this bug."), QMessageBox::Ok);
} }
} }
QTime Call::getCurrentStateTime() QTime Call::getCurrentStateTime()
{ {
int now = QDateTime::fromTime_t(_answered_epoch).secsTo(QDateTime::currentDateTime()); qulonglong time = 0;
if (_state == FSCOMM_CALL_STATE_ANSWERED)
{
time = _answeredEpoch;
}
else if(_state == FSCOMM_CALL_STATE_RINGING)
{
if (_direction == FSCOMM_CALL_DIRECTION_INBOUND)
{
time = _channel.data()->getCreatedEpoch();
}
else
_otherLegChannel.data()->getProgressEpoch() == 0 ? time = _otherLegChannel.data()->getProgressMediaEpoch() : time = _otherLegChannel.data()->getProgressEpoch();
}
int now = QDateTime::fromTime_t(time).secsTo(QDateTime::currentDateTime());
return QTime::fromString(QString::number(now), "s"); return QTime::fromString(QString::number(now), "s");
} }

View File

@ -32,6 +32,7 @@
#include <QtCore> #include <QtCore>
#include <QString> #include <QString>
#include <switch.h> #include <switch.h>
#include "channel.h"
typedef enum { typedef enum {
FSCOMM_CALL_STATE_RINGING = 0, FSCOMM_CALL_STATE_RINGING = 0,
@ -48,36 +49,44 @@ typedef enum {
class Call { class Call {
public: public:
Call(); Call();
Call(int call_id, QString cid_name, QString cid_number, fscomm_call_direction_t direction, QString uuid); /* Needs rework */
QString getCidName(void) { return _cid_name; } QString getCidName(void) { return (_direction == FSCOMM_CALL_DIRECTION_INBOUND) ? _otherLegChannel.data()->getCidName() : _channel.data()->getCidName(); }
QString getCidNumber(void) { return _cid_number; } QString getCidNumber(void) { return (_direction == FSCOMM_CALL_DIRECTION_INBOUND) ? _otherLegChannel.data()->getCidNumber() : _channel.data()->getCidNumber(); }
int getCallID(void) { return _call_id; } QString getDestinationNumber(void) { return _otherLegChannel.data()->getDestinationNumber(); }
QString getUUID(void) { return _uuid; }
void setbUUID(QString uuid) { _buuid = uuid; } void setChannel(QSharedPointer<Channel> channel) { _channel = channel; }
QSharedPointer<Channel> getChannel() { return _channel; }
void setOtherLegChannel(QSharedPointer<Channel> channel) { _otherLegChannel = channel; }
QSharedPointer<Channel> getOtherLegChannel() { return _otherLegChannel; }
QString getUuid(void) { return _channel.data()->getUuid(); }
QString getOtherLegUuid(void) { return _otherLegChannel.data()->getUuid(); }
void setCallDirection(fscomm_call_direction_t dir) { _direction = dir; }
int getCallID(void) { return _channel.data()->getPaCallId(); }
fscomm_call_direction_t getDirection() { return _direction; } fscomm_call_direction_t getDirection() { return _direction; }
fscomm_call_state_t getState() { return _state; } fscomm_call_state_t getState() { return _state; }
void setState(fscomm_call_state_t state) { _state = state; } void setState(fscomm_call_state_t state) { _state = state; }
void setCause(QString cause) { _cause = cause; } void setCause(QString cause) { _cause = cause; qDebug()<<cause; }
QString getCause() { return _cause; } QString getCause() { return _cause; qDebug() << _cause; }
void setActive(bool isActive) { _isActive = isActive; } void setActive(bool isActive) { _isActive = isActive; }
bool isActive() { return _isActive == true; } bool isActive() { return _isActive == true; }
switch_status_t toggleRecord(bool); switch_status_t toggleRecord(bool);
switch_status_t toggleHold(bool);
void sendDTMF(QString digit); void sendDTMF(QString digit);
void setAnsweredEpoch(qulonglong time) { _answered_epoch = time/1000000; } void setAnsweredEpoch(qulonglong time) { _answeredEpoch = time/1000000; }
QTime getCurrentStateTime(); QTime getCurrentStateTime();
private: private:
int _call_id; QSharedPointer<Channel> _channel; /* This should be our portaudio channel */
QString _cid_name; QSharedPointer<Channel> _otherLegChannel;
QString _cid_number;
QString _cause; QString _cause;
fscomm_call_direction_t _direction; fscomm_call_direction_t _direction;
QString _uuid;
QString _buuid;
bool _isActive; bool _isActive;
QString _recording_filename; QString _recording_filename;
fscomm_call_state_t _state; fscomm_call_state_t _state;
qulonglong _answered_epoch; qulonglong _answeredEpoch;
}; };
Q_DECLARE_METATYPE(Call) Q_DECLARE_METATYPE(Call)

9
fscomm/channel.cpp Normal file
View File

@ -0,0 +1,9 @@
#include "channel.h"
Channel::Channel(QString uuid):
_uuid(uuid)
{
_progressEpoch = 0;
_progressMediaEpoch = 0;
_createdEpoch = 0;
}

42
fscomm/channel.h Normal file
View File

@ -0,0 +1,42 @@
#ifndef CHANNEL_H
#define CHANNEL_H
#include <QtCore>
class Channel
{
public:
Channel() {}
Channel(QString uuid);
QString getUuid() { return _uuid; }
void setCidName(QString cidName) { _cidName = cidName; }
QString getCidName() { return _cidName; }
void setCidNumber(QString cidNumber) { _cidNumber = cidNumber; }
QString getCidNumber() { return _cidNumber; }
void setDestinatinonNumber(QString destinationNumber) { _destinationNumber = destinationNumber; }
QString getDestinationNumber() { return _destinationNumber; }
int getPaCallId() { return _paCallId; }
void setPaCallId(int paCallId) { _paCallId = paCallId;}
void setProgressEpoch(qulonglong time) { _progressEpoch = time/1000000; }
qulonglong getProgressEpoch() { return _progressEpoch; }
void setProgressMediaEpoch(qulonglong time) { _progressMediaEpoch = time/1000000; }
qulonglong getProgressMediaEpoch() { return _progressMediaEpoch; }
void setCreatedEpoch(qulonglong time) { _createdEpoch = time/1000000; }
qulonglong getCreatedEpoch() { return _createdEpoch; }
private:
QString _uuid;
QString _cidName;
QString _cidNumber;
QString _destinationNumber;
int _paCallId;
qulonglong _progressEpoch;
qulonglong _progressMediaEpoch;
qulonglong _createdEpoch;
};
Q_DECLARE_METATYPE(Channel)
#endif // CHANNEL_H

View File

@ -89,6 +89,7 @@
<load module="mod_ilbc"/> <load module="mod_ilbc"/>
<load module="mod_speex"/> <load module="mod_speex"/>
<load module="mod_celt"/> <load module="mod_celt"/>
<load module="mod_silk"/>
<load module="mod_siren"/> <load module="mod_siren"/>
<load module="mod_sndfile"/> <load module="mod_sndfile"/>
<load module="mod_tone_stream"/> <load module="mod_tone_stream"/>

View File

@ -0,0 +1,158 @@
#include "consolewindow.h"
#include "ui_consolewindow.h"
ConsoleWindow::ConsoleWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::ConsoleWindow),
findNext(false)
{
ui->setupUi(this);
sourceModel = new ConsoleModel(this);
model = new SortFilterProxyModel(this);
model->setSourceModel(sourceModel);
model->setFilterKeyColumn(0);
ui->consoleListView->setModel(model);
ui->consoleListView->setColumnWidth(0, 2000);
connect(sourceModel, SIGNAL(beforeInserting()),
this, SLOT(setConditionalScroll()));
connect(sourceModel, SIGNAL(afterInserting()),
this, SLOT(conditionalScroll()));
connect(ui->btnSend, SIGNAL(clicked()),
this, SLOT(cmdSendClicked()));
connect(ui->lineCmd, SIGNAL(textChanged(QString)),
this, SLOT(lineCmdChanged(QString)));
_levelFilter = new QSignalMapper(this);
connect(ui->checkEmerg, SIGNAL(clicked()), _levelFilter, SLOT(map()));
connect(ui->checkAlert, SIGNAL(clicked()), _levelFilter, SLOT(map()));
connect(ui->checkCrit, SIGNAL(clicked()), _levelFilter, SLOT(map()));
connect(ui->checkDebug, SIGNAL(clicked()), _levelFilter, SLOT(map()));
connect(ui->checkError, SIGNAL(clicked()), _levelFilter, SLOT(map()));
connect(ui->checkInfo, SIGNAL(clicked()), _levelFilter, SLOT(map()));
connect(ui->checkNotice, SIGNAL(clicked()), _levelFilter, SLOT(map()));
connect(ui->checkWarn, SIGNAL(clicked()), _levelFilter, SLOT(map()));
_levelFilter->setMapping(ui->checkEmerg, SWITCH_LOG_CONSOLE);
_levelFilter->setMapping(ui->checkAlert, SWITCH_LOG_ALERT);
_levelFilter->setMapping(ui->checkCrit, SWITCH_LOG_CRIT);
_levelFilter->setMapping(ui->checkDebug, SWITCH_LOG_DEBUG);
_levelFilter->setMapping(ui->checkError, SWITCH_LOG_ERROR);
_levelFilter->setMapping(ui->checkInfo, SWITCH_LOG_INFO);
_levelFilter->setMapping(ui->checkNotice, SWITCH_LOG_NOTICE);
_levelFilter->setMapping(ui->checkWarn, SWITCH_LOG_WARNING);
connect(_levelFilter, SIGNAL(mapped(int)), this, SLOT(filterModelLogLevel(int)));
connect(ui->btnFilterClear, SIGNAL(clicked()),
this, SLOT(filterClear()));
connect(ui->lineFilter, SIGNAL(textChanged(QString)),
this, SLOT(filterStringChanged()));
connect(ui->filterCaseSensitivityCheckBox, SIGNAL(toggled(bool)),
this, SLOT(filterStringChanged()));
connect(ui->filterSyntaxComboBox, SIGNAL(currentIndexChanged(int)),
this, SLOT(filterStringChanged()));
connect(ui->filterReverseCheckBox, SIGNAL(toggled(bool)),
this, SLOT(reverseFilterChecked()));
connect(&g_FSHost, SIGNAL(eventLog(QSharedPointer<switch_log_node_t>,switch_log_level_t)), this, SLOT(loggerHandler(QSharedPointer<switch_log_node_t>,switch_log_level_t)));
}
ConsoleWindow::~ConsoleWindow()
{
delete ui;
}
void ConsoleWindow::changeEvent(QEvent *e)
{
QMainWindow::changeEvent(e);
switch (e->type()) {
case QEvent::LanguageChange:
ui->retranslateUi(this);
break;
default:
break;
}
}
void ConsoleWindow::setConditionalScroll()
{
autoScroll = (ui->consoleListView->verticalScrollBar()->maximum() == ui->consoleListView->verticalScrollBar()->value());
}
void ConsoleWindow::conditionalScroll()
{
if (autoScroll)
ui->consoleListView->scrollToBottom();
}
void ConsoleWindow::cmdSendClicked()
{
if (ui->lineCmd->text().isEmpty()) return;
QString cmd = ui->lineCmd->text().split(" ", QString::SkipEmptyParts)[0];
if (cmd.isEmpty()) return;
QStringList split = ui->lineCmd->text().split(" ", QString::SkipEmptyParts);
if (split.isEmpty()) return;
QString args;
for (int i=1; i<split.length(); i++)
{
args += split[i];
if (i!=split.length()-1)
args += " ";
}
QString res;
g_FSHost.sendCmd(cmd.toAscii().data(), args.toAscii().data(), &res);
QStandardItem *item = new QStandardItem(res);
item->setData(SWITCH_LOG_CONSOLE, ConsoleModel::LogLevelRole);
addNewConsoleItem(item);
ui->lineCmd->clear();
}
void ConsoleWindow::lineCmdChanged(QString text)
{
ui->btnSend->setDisabled(text.isEmpty());
}
void ConsoleWindow::filterModelLogLevel(int level)
{
model->setLogLevelFilter(level);
}
void ConsoleWindow::loggerHandler(QSharedPointer<switch_log_node_t> node, switch_log_level_t level)
{
if (level > ui->comboLogLevel->currentIndex()) return;
QString text(node.data()->data);
if (!text.isEmpty())
{
/* Remove \r\n */
QStringList textList = text.split(QRegExp("(\r+)"), QString::SkipEmptyParts);
QString final_str;
for (int line = 0; line<textList.size(); line++)
{
final_str += textList[line];
}
QStringList lines = final_str.split(QRegExp("(\n+)"), QString::SkipEmptyParts);
for (int line = 0; line < lines.size(); ++line)
{
QStandardItem *item = new QStandardItem(lines[line]);
item->setData(level, ConsoleModel::LogLevelRole);
item->setData(node.data()->userdata, ConsoleModel::UUIDRole);
addNewConsoleItem(item);
}
}
}
void ConsoleWindow::addNewConsoleItem(QStandardItem *item)
{
QSettings settings;
settings.beginGroup("Console");
QPalette palette = settings.value(QString("log-level-%1-palette").arg(item->data(Qt::UserRole).toInt())).value<QPalette>();
QFont font = settings.value(QString("log-level-%1-font").arg(item->data(Qt::UserRole).toInt())).value<QFont>();
item->setBackground(palette.base());
item->setForeground(palette.text());
item->setFont(font);
sourceModel->appendRow(item);
}

View File

@ -0,0 +1,56 @@
#ifndef CONSOLEWINDOW_H
#define CONSOLEWINDOW_H
#include <QtGui>
#include "fshost.h"
#include "sortfilterproxymodel.h"
namespace Ui {
class ConsoleWindow;
}
class ConsoleWindow : public QMainWindow {
Q_OBJECT
public:
ConsoleWindow(QWidget *parent = 0);
~ConsoleWindow();
protected:
void changeEvent(QEvent *e);
/*public slots:
void clearConsoleContents();
void saveLogToFile();
void pastebinLog();
void filterLogUUID(QString);
void findText();*/
private slots:
void setConditionalScroll();
void conditionalScroll();
/*void filterClear();
void filterStringChanged();*/
void loggerHandler(QSharedPointer<switch_log_node_t> node, switch_log_level_t level);
void addNewConsoleItem(QStandardItem *item);
void cmdSendClicked();
void lineCmdChanged(QString);
/*void reverseFilterChecked();*/
void filterModelLogLevel(int);
private:
Ui::ConsoleWindow *ui;
ConsoleModel *sourceModel;
QModelIndexList foundItems;
SortFilterProxyModel *model;
/*pastebinDialog *_pastebinDlg;
FindDialog *_findDialog;*/
bool findNext;
bool autoScroll;
QSignalMapper *_levelFilter;
/*void readSettings();
void writeSettings();*/
};
#endif // CONSOLEWINDOW_H

View File

@ -0,0 +1,466 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ConsoleWindow</class>
<widget class="QMainWindow" name="ConsoleWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>696</width>
<height>559</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>118</height>
</size>
</property>
<property name="title">
<string>Filter</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLineEdit" name="lineFilter">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="filterSyntaxComboBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContentsOnFirstShow</enum>
</property>
<item>
<property name="text">
<string>Regular Expression</string>
</property>
</item>
<item>
<property name="text">
<string>Wildcard</string>
</property>
</item>
<item>
<property name="text">
<string>Fixed String</string>
</property>
</item>
<item>
<property name="text">
<string>UUID</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnFilterClear">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;Clear</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QCheckBox" name="filterCaseSensitivityCheckBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Case sensitive filter</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="filterReverseCheckBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Reverse filter</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblWarningMsg">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>358</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QWidget" name="layoutWidget_2">
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="sizeConstraint">
<enum>QLayout::SetMaximumSize</enum>
</property>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="maximumSize">
<size>
<width>120</width>
<height>16777215</height>
</size>
</property>
<property name="title">
<string>Log Level Filter</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QCheckBox" name="checkEmerg">
<property name="text">
<string>Console</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkAlert">
<property name="text">
<string>Alert</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkCrit">
<property name="text">
<string>Critical</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkError">
<property name="text">
<string>Error</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkWarn">
<property name="text">
<string>Warning</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkNotice">
<property name="text">
<string>Notice</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkInfo">
<property name="text">
<string>Info</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkDebug">
<property name="text">
<string>Debug</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>18</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="maximumSize">
<size>
<width>120</width>
<height>16777215</height>
</size>
</property>
<property name="title">
<string>Loglevel</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QComboBox" name="comboLogLevel">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="currentIndex">
<number>7</number>
</property>
<item>
<property name="text">
<string>Console</string>
</property>
</item>
<item>
<property name="text">
<string>Alert</string>
</property>
</item>
<item>
<property name="text">
<string>Critical</string>
</property>
</item>
<item>
<property name="text">
<string>Error</string>
</property>
</item>
<item>
<property name="text">
<string>Warning</string>
</property>
</item>
<item>
<property name="text">
<string>Notice</string>
</property>
</item>
<item>
<property name="text">
<string>Info</string>
</property>
</item>
<item>
<property name="text">
<string>Debug</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QTableView" name="consoleListView">
<property name="autoScroll">
<bool>false</bool>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="tabKeyNavigation">
<bool>false</bool>
</property>
<property name="showDropIndicator" stdset="0">
<bool>false</bool>
</property>
<property name="dragDropOverwriteMode">
<bool>false</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
<property name="horizontalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
<property name="showGrid">
<bool>false</bool>
</property>
<property name="wordWrap">
<bool>false</bool>
</property>
<property name="cornerButtonEnabled">
<bool>false</bool>
</property>
<attribute name="horizontalHeaderVisible">
<bool>false</bool>
</attribute>
<attribute name="horizontalHeaderCascadingSectionResizes">
<bool>false</bool>
</attribute>
<attribute name="horizontalHeaderHighlightSections">
<bool>false</bool>
</attribute>
<attribute name="horizontalHeaderShowSortIndicator" stdset="0">
<bool>false</bool>
</attribute>
<attribute name="horizontalHeaderStretchLastSection">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderCascadingSectionResizes">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderDefaultSectionSize">
<number>20</number>
</attribute>
<attribute name="verticalHeaderHighlightSections">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderShowSortIndicator" stdset="0">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderStretchLastSection">
<bool>false</bool>
</attribute>
</widget>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLineEdit" name="lineCmd">
<property name="enabled">
<bool>true</bool>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>26</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnSend">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>28</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>85</width>
<height>28</height>
</size>
</property>
<property name="text">
<string>Send</string>
</property>
<property name="shortcut">
<string>Return</string>
</property>
<property name="autoDefault">
<bool>true</bool>
</property>
<property name="default">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>696</width>
<height>24</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,116 @@
#include <QtGui>
#include "sortfilterproxymodel.h"
ConsoleModel::ConsoleModel (QObject *parent)
: QAbstractTableModel(parent)
{
QSettings settings;
batchSize = settings.value("Console/batchSize", 200).toInt();
insertionTimer = new QBasicTimer;
insertionTimer->start(0, this);
}
int ConsoleModel::rowCount ( const QModelIndex & parent ) const
{
if (parent.isValid())
return 0;
return _listDisplayModel.count();
}
int ConsoleModel::columnCount ( const QModelIndex & /*parent*/ ) const
{
return 1;
}
QVariant ConsoleModel::data ( const QModelIndex & index, int role ) const
{
if (!index.isValid())
return QVariant();
return _listDisplayModel.at(index.row())->data(role);
}
void ConsoleModel::clear()
{
_listDisplayModel.clear();
reset();
}
void ConsoleModel::appendRow ( QStandardItem* item )
{
_listInsertModel.append(item);
insertionTimer->start(0, this);
}
void ConsoleModel::timerEvent(QTimerEvent *e)
{
if (e->timerId() == insertionTimer->timerId())
{
if (!_listInsertModel.isEmpty())
{
int inserted_items = 0;
int toBeInserted = 0;
if (_listInsertModel.size() < batchSize)
{
toBeInserted = _listInsertModel.size() - 1;
} else {
toBeInserted = batchSize - 1;
}
emit beforeInserting();
beginInsertRows( QModelIndex(), _listDisplayModel.size(), _listDisplayModel.size() + toBeInserted );
while( !_listInsertModel.isEmpty() && inserted_items <= batchSize)
{
_listDisplayModel.append(_listInsertModel.takeFirst());
inserted_items++;
}
endInsertRows();
emit afterInserting();
} else {
insertionTimer->stop();
}
}
}
SortFilterProxyModel::SortFilterProxyModel(QObject *parent)
: QSortFilterProxyModel(parent)
{
reverseFlag = false;
for(int i = 0; i < 8; i++)
loglevels.insert(i, true);
}
void SortFilterProxyModel::toggleReverseFlag()
{
reverseFlag = !reverseFlag;
invalidateFilter();
}
void SortFilterProxyModel::setLogLevelFilter(int level)
{
loglevels.replace(level, loglevels.value(level) == false);
// Let us filter
invalidateFilter();
}
void SortFilterProxyModel::setUUIDFilterLog(QString uuid)
{
_uuid = uuid;
invalidateFilter();
}
bool SortFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
QModelIndex index0 = sourceModel()->index(source_row, 0, source_parent);
bool uuidMatch = true;
if (!_uuid.isEmpty())
uuidMatch = (sourceModel()->data(index0, ConsoleModel::UUIDRole).toString() == _uuid);
bool res = (loglevels.value(sourceModel()->data(index0, Qt::UserRole).toInt()) == true
&& sourceModel()->data(index0).toString().contains(filterRegExp())
&& uuidMatch);
if (reverseFlag)
return !res;
else
return res;
}

View File

@ -0,0 +1,97 @@
/*
* Copyright (c) 2007, Anthony Minessale II
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Contributor(s):
*
* Joao Mesquita <jmesquita (at) freeswitch.org>
*
*/
#ifndef SORTFILTERPROXYMODEL_H
#define SORTFILTERPROXYMODEL_H
#include <QSortFilterProxyModel>
#include <QAbstractTableModel>
#include <QVector>
#include <QList>
class QBasicTimer;
class QStandardItem;
class QScrollBar;
class ConsoleModel : public QAbstractTableModel
{
Q_OBJECT
public:
ConsoleModel (QObject *parent = 0);
int rowCount ( const QModelIndex & parent = QModelIndex() ) const;
int columnCount ( const QModelIndex & parent = QModelIndex() ) const;
QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const;
void appendRow ( QStandardItem* item );
void clear();
QList<QStandardItem *> modelData() { return _listDisplayModel; }
enum {
LogLevelRole = Qt::UserRole,
UUIDRole
};
signals:
void beforeInserting();
void afterInserting();
protected:
void timerEvent(QTimerEvent *);
private:
QList<QStandardItem *> _listDisplayModel;
QList<QStandardItem *> _listInsertModel;
int batchSize;
QBasicTimer *insertionTimer;
};
class SortFilterProxyModel : public QSortFilterProxyModel
{
Q_OBJECT
public:
SortFilterProxyModel(QObject *parent = 0);
void setLogLevelFilter(int level);
void setUUIDFilterLog(QString uuid);
void toggleReverseFlag();
protected:
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const;
private:
QVector<bool> loglevels;
QString _uuid;
bool reverseFlag;
};
#endif // SORTFILTERPROXYMODEL_H

View File

@ -0,0 +1,77 @@
#include "statedebugdialog.h"
#include "ui_statedebugdialog.h"
StateDebugDialog::StateDebugDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::StateDebugDialog)
{
ui->setupUi(this);
connect(&g_FSHost, SIGNAL(newEvent(QSharedPointer<switch_event_t>)), this, SLOT(newEvent(QSharedPointer<switch_event_t>)));
connect(ui->listUUID, SIGNAL(itemSelectionChanged()), this, SLOT(currentUuidChanged()));
connect(ui->listEvents, SIGNAL(itemSelectionChanged()), this, SLOT(currentEventsChanged()));
}
StateDebugDialog::~StateDebugDialog()
{
delete ui;
}
void StateDebugDialog::changeEvent(QEvent *e)
{
QDialog::changeEvent(e);
switch (e->type()) {
case QEvent::LanguageChange:
ui->retranslateUi(this);
break;
default:
break;
}
}
void StateDebugDialog::newEvent(QSharedPointer<switch_event_t>event)
{
/* We don't want to keep track of events that are not calls at this moment */
if (QString(switch_event_get_header_nil(event.data(), "Unique-ID")).isEmpty())
return;
QString uuid(switch_event_get_header_nil(event.data(), "Unique-ID"));
if (!_events.contains(uuid))
{
QList<QSharedPointer<switch_event_t> > tmpListEvents;
tmpListEvents.append(event);
_events.insert(uuid, tmpListEvents);
ui->listUUID->addItem(new QListWidgetItem(uuid));
}
else
{
QList<QSharedPointer<switch_event_t> > tmpListEvents = _events.value(uuid);
tmpListEvents.append(event);
_events.insert(uuid, tmpListEvents);
}
}
void StateDebugDialog::currentUuidChanged()
{;
ui->listEvents->clear();
ui->listDetails->clear();
QString uuid = ui->listUUID->currentItem()->text();
foreach(QSharedPointer<switch_event_t> e, _events.value(uuid))
{
ui->listEvents->addItem(new QListWidgetItem(switch_event_name(e.data()->event_id)));
}
}
void StateDebugDialog::currentEventsChanged()
{
ui->listDetails->clear();
int r = ui->listEvents->currentRow();
if (r == -1) return;
QString uuid = ui->listUUID->currentItem()->text();
QList<QSharedPointer<switch_event_t> > tmpListEvents = _events.value(uuid);
QSharedPointer<switch_event_t> e = tmpListEvents.at(r);
for(switch_event_header_t* h = e.data()->headers; h != e.data()->last_header; h = h->next)
{
ui->listDetails->addItem(new QListWidgetItem(QString("%1 = %2").arg(h->name, h->value)));
}
}

View File

@ -0,0 +1,30 @@
#ifndef STATEDEBUGDIALOG_H
#define STATEDEBUGDIALOG_H
#include <QtGui>
#include "fshost.h"
namespace Ui {
class StateDebugDialog;
}
class StateDebugDialog : public QDialog {
Q_OBJECT
public:
StateDebugDialog(QWidget *parent = 0);
~StateDebugDialog();
private slots:
void newEvent(QSharedPointer<switch_event_t> event);
void currentUuidChanged();
void currentEventsChanged();
protected:
void changeEvent(QEvent *e);
private:
Ui::StateDebugDialog *ui;
QHash<QString, QList<QSharedPointer<switch_event_t> > > _events;
};
#endif // STATEDEBUGDIALOG_H

View File

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>StateDebugDialog</class>
<widget class="QDialog" name="StateDebugDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>804</width>
<height>235</height>
</rect>
</property>
<property name="windowTitle">
<string>Debug Events</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QWidget" name="layoutWidget">
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>UUID</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="listUUID"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="layoutWidget">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>EVENTS</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="listEvents"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="layoutWidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>DETAILS</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="listDetails"/>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -43,9 +43,13 @@ FSHost::FSHost(QObject *parent) :
switch_core_set_globals(); switch_core_set_globals();
qRegisterMetaType<QSharedPointer<Call> >("QSharedPointer<Call>"); qRegisterMetaType<QSharedPointer<Call> >("QSharedPointer<Call>");
qRegisterMetaType<QSharedPointer<switch_event_t> >("QSharedPointer<switch_event_t>");
qRegisterMetaType<QSharedPointer<switch_log_node_t> >("QSharedPointer<switch_log_node_t>");
qRegisterMetaType<switch_log_level_t>("switch_log_level_t");
qRegisterMetaType<QSharedPointer<Channel> >("QSharedPointer<Channel>");
qRegisterMetaType<QSharedPointer<Account> >("QSharedPointer<Account>"); qRegisterMetaType<QSharedPointer<Account> >("QSharedPointer<Account>");
connect(this, SIGNAL(loadedModule(QString,QString,QString)), this, SLOT(minimalModuleLoaded(QString,QString,QString))); connect(this, SIGNAL(loadedModule(QString,QString)), this, SLOT(minimalModuleLoaded(QString,QString)));
} }
@ -114,6 +118,11 @@ void FSHost::createFolders()
} }
} }
void FSHost::generalLoggerHandler(QSharedPointer<switch_log_node_t>node, switch_log_level_t level)
{
emit eventLog(node, level);
}
void FSHost::run(void) void FSHost::run(void)
{ {
switch_core_flag_t flags = SCF_USE_SQL | SCF_USE_AUTO_NAT; switch_core_flag_t flags = SCF_USE_SQL | SCF_USE_AUTO_NAT;
@ -149,6 +158,7 @@ void FSHost::run(void)
emit coreLoadingError(err); emit coreLoadingError(err);
} }
switch_log_bind_logger(loggerHandler, SWITCH_LOG_DEBUG, SWITCH_FALSE);
emit ready(); emit ready();
/* Go into the runtime loop. If the argument is true, this basically sets runtime.running = 1 and loops while that is set /* Go into the runtime loop. If the argument is true, this basically sets runtime.running = 1 and loops while that is set
@ -167,261 +177,172 @@ void FSHost::run(void)
} }
} }
switch_status_t FSHost::processAlegEvent(switch_event_t * event, QString uuid) void FSHost::generalEventHandler(QSharedPointer<switch_event_t>event)
{ {
switch_status_t status = SWITCH_STATUS_SUCCESS; QString uuid = switch_event_get_header_nil(event.data(), "Unique-ID");
QSharedPointer<Call> call = _active_calls.value(uuid);
if (call.isNull()) emit newEvent(event);
{
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "We don't have a call object for A leg on event %s.\n", switch_event_name(event->event_id));
qDebug() << _active_calls.keys();
printEventHeaders(event);
return SWITCH_STATUS_FALSE;
}
/* Inbound call */ switch(event.data()->event_id) {
if (call.data()->getDirection() == FSCOMM_CALL_DIRECTION_INBOUND) case SWITCH_EVENT_CHANNEL_CREATE: /*1A - 17B*/
{
switch(event->event_id) {
case SWITCH_EVENT_CHANNEL_ANSWER:
{
QString answeredEpoch = switch_event_get_header_nil(event, "Caller-Channel-Answered-Time");
call.data()->setAnsweredEpoch(answeredEpoch.toLong());
call.data()->setbUUID(switch_event_get_header_nil(event, "Other-Leg-Unique-ID"));
_bleg_uuids.insert(switch_event_get_header_nil(event, "Other-Leg-Unique-ID"), uuid);
call.data()->setState(FSCOMM_CALL_STATE_ANSWERED);
emit answered(call);
break;
}
case SWITCH_EVENT_CHANNEL_HANGUP_COMPLETE:
{
emit hungup(_active_calls.take(uuid));
break;
}
case SWITCH_EVENT_CHANNEL_STATE:
{
qDebug() << QString("CHANNEL_STATE Answer-State: %1 | Channel-State: %2 | %3 | %4\n").arg(switch_event_get_header_nil(event, "Answer-State"),switch_event_get_header_nil(event, "Channel-State"), uuid.toAscii().constData(), switch_event_get_header_nil(event, "Other-Leg-Unique-ID"));
break;
}
default:
{
break;
}
}
}
/* Outbound call */
else
{
switch(event->event_id)
{ {
case SWITCH_EVENT_CHANNEL_BRIDGE: eventChannelCreate(event, uuid);
{
_active_calls.value(uuid).data()->setbUUID(switch_event_get_header_nil(event, "Other-Leg-Unique-ID"));
_bleg_uuids.insert(switch_event_get_header_nil(event, "Other-Leg-Unique-ID"), uuid);
break;
}
case SWITCH_EVENT_CHANNEL_HANGUP_COMPLETE:
{
if (call.data()->getState() == FSCOMM_CALL_STATE_TRYING)
{
QString cause = switch_event_get_header_nil(event, "Hangup-Cause");
call.data()->setState(FSCOMM_CALL_STATE_FAILED);
call.data()->setCause(cause);
emit callFailed(call);
_active_calls.take(uuid);
}
break;
}
default:
qDebug() << QString("A leg: %1(%2)\n").arg(switch_event_name(event->event_id), switch_event_get_header_nil(event, "Event-Subclass"));
break; break;
} }
} case SWITCH_EVENT_CHANNEL_ANSWER: /*2A - 31B*/
return status;
}
switch_status_t FSHost::processBlegEvent(switch_event_t * event, QString buuid)
{
QString uuid = _bleg_uuids.value(buuid);
switch_status_t status = SWITCH_STATUS_SUCCESS;
QSharedPointer<Call> call = _active_calls.value(uuid);
if (call.isNull())
{
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "We don't have a call object for B leg on event %s.\n", switch_event_name(event->event_id));
qDebug() << _active_calls.keys();
printEventHeaders(event);
return SWITCH_STATUS_FALSE;
}
/* Inbound call */
if (call.data()->getDirection() == FSCOMM_CALL_DIRECTION_INBOUND)
{
qDebug() << " Inbound call";
}
/* Outbound call */
else
{
switch(event->event_id)
{ {
case SWITCH_EVENT_CHANNEL_ANSWER: eventChannelAnswer(event, uuid);
{
/* When do we get here? */
QString answeredEpoch = switch_event_get_header_nil(event, "Caller-Channel-Answered-Time");
call.data()->setAnsweredEpoch(answeredEpoch.toULongLong());
emit answered(call);
break;
}
case SWITCH_EVENT_CHANNEL_HANGUP_COMPLETE:
{
_active_calls.take(uuid);
emit hungup(call);
_bleg_uuids.take(buuid);
break;
}
case SWITCH_EVENT_CHANNEL_STATE:
{
if (QString(switch_event_get_header_nil(event, "Answer-State")) == "early")
{
call.data()->setState(FSCOMM_CALL_STATE_RINGING);
emit ringing(call);
}
else if (QString(switch_event_get_header_nil(event, "Answer-State")) == "answered")
{
call.data()->setState(FSCOMM_CALL_STATE_ANSWERED);
emit answered(call);
}
break;
}
default:
qDebug() << QString("B leg: %1(%2)\n").arg(switch_event_name(event->event_id), switch_event_get_header_nil(event, "Event-Subclass"));
break; break;
} }
} case SWITCH_EVENT_CODEC:/*3/4A - 24/25B*/
return status;
}
void FSHost::generalEventHandler(switch_event_t *event)
{
/*printEventHeaders(event);*/
QString uuid = switch_event_get_header_nil(event, "Unique-ID");
if (_bleg_uuids.contains(uuid))
{
if (processBlegEvent(event, uuid) == SWITCH_STATUS_SUCCESS)
{ {
return; eventCodec(event, uuid);
break;
} }
} case SWITCH_EVENT_CHANNEL_STATE:/*6/7/8/37/44/46A - 20/21/22/28/38/40/42B*/
if (_active_calls.contains(uuid))
{
if (processAlegEvent(event, uuid) == SWITCH_STATUS_SUCCESS)
{ {
return; eventChannelState(event, uuid);
break;
} }
} case SWITCH_EVENT_CHANNEL_EXECUTE:/*9/11/13/15A*/
/* This is how we identify new calls, inbound and outbound */
switch(event->event_id) {
case SWITCH_EVENT_CUSTOM:
{ {
if (strcmp(event->subclass_name, "portaudio::ringing") == 0 && !_active_calls.contains(uuid)) eventChannelExecute(event, uuid);
break;
}
case SWITCH_EVENT_CHANNEL_EXECUTE_COMPLETE:/*10/12/14/16/35A*/
{
eventChannelExecuteComplete(event, uuid);
break;
}
case SWITCH_EVENT_CHANNEL_OUTGOING:/*18B*/
{
eventChannelOutgoing(event, uuid);
break;
}
case SWITCH_EVENT_CHANNEL_ORIGINATE:/*19B*/
{
eventChannelOriginate(event, uuid);
break;
}
case SWITCH_EVENT_CALL_UPDATE:/*23/29/30B*/
{
eventCallUpdate(event, uuid);
break;
}
case SWITCH_EVENT_CHANNEL_PROGRESS:
{
eventChannelProgress(event, uuid);
break;
}
case SWITCH_EVENT_CHANNEL_PROGRESS_MEDIA:/*26B*/
{
eventChannelProgressMedia(event, uuid);
break;
}
case SWITCH_EVENT_CHANNEL_BRIDGE:/*27A*/
{
eventChannelBridge(event, uuid);
break;
}
/*32?*/
/*case SWITCH_EVENT_RECV_INFO:
{
eventRecvInfo(event, uuid);
break;
}*/
case SWITCH_EVENT_CHANNEL_HANGUP:/*36A-33B*/
{
eventChannelHangup(event, uuid);
break;
}
case SWITCH_EVENT_CHANNEL_UNBRIDGE:/*34A*/
{
eventChannelUnbridge(event, uuid);
break;
}
case SWITCH_EVENT_CHANNEL_HANGUP_COMPLETE:/*39/43B*/
{
eventChannelHangupComplete(event, uuid);
break;
}
case SWITCH_EVENT_CHANNEL_DESTROY:/*45A-41B*/
{
eventChannelDestroy(event, uuid);
break;
}
case SWITCH_EVENT_CUSTOM:/*5A*/
{
if (strcmp(event.data()->subclass_name, "sofia::gateway_state") == 0)
{ {
Call *callPtr = new Call(atoi(switch_event_get_header_nil(event, "call_id")), QString state = switch_event_get_header_nil(event.data(), "State");
switch_event_get_header_nil(event, "Caller-Caller-ID-Name"), QString gw = switch_event_get_header_nil(event.data(), "Gateway");
switch_event_get_header_nil(event, "Caller-Caller-ID-Number"),
FSCOMM_CALL_DIRECTION_INBOUND,
uuid);
QSharedPointer<Call> call(callPtr);
_active_calls.insert(uuid, call);
call.data()->setState(FSCOMM_CALL_STATE_RINGING);
emit ringing(call);
}
else if (strcmp(event->subclass_name, "portaudio::makecall") == 0)
{
Call *callPtr = new Call(atoi(switch_event_get_header_nil(event, "call_id")),NULL,
switch_event_get_header_nil(event, "Caller-Destination-Number"),
FSCOMM_CALL_DIRECTION_OUTBOUND,
uuid);
QSharedPointer<Call> call(callPtr);
_active_calls.insert(uuid, call);
call.data()->setState(FSCOMM_CALL_STATE_TRYING);
emit newOutgoingCall(call);
}
else if (strcmp(event->subclass_name, "sofia::gateway_state") == 0)
{
QString state = switch_event_get_header_nil(event, "State");
QString gw = switch_event_get_header_nil(event, "Gateway");
QSharedPointer<Account> acc = _accounts.value(gw); QSharedPointer<Account> acc = _accounts.value(gw);
if (acc.isNull()) if (acc.isNull())
return; return;
if (state == "TRYING") { if (state == "TRYING") {
acc.data()->setStatusPhrase(switch_event_get_header_nil(event, "Phrase")); acc.data()->setStatusPhrase(switch_event_get_header_nil(event.data(), "Phrase"));
acc.data()->setState(FSCOMM_GW_STATE_TRYING); acc.data()->setState(FSCOMM_GW_STATE_TRYING);
emit accountStateChange(acc); emit accountStateChange(acc);
} else if (state == "REGISTER") { } else if (state == "REGISTER") {
acc.data()->setStatusPhrase(switch_event_get_header_nil(event, "Phrase")); acc.data()->setStatusPhrase(switch_event_get_header_nil(event.data(), "Phrase"));
acc.data()->setState(FSCOMM_GW_STATE_REGISTER); acc.data()->setState(FSCOMM_GW_STATE_REGISTER);
emit accountStateChange(acc); emit accountStateChange(acc);
} else if (state == "REGED") { } else if (state == "REGED") {
acc.data()->setStatusPhrase(switch_event_get_header_nil(event, "Phrase")); acc.data()->setStatusPhrase(switch_event_get_header_nil(event.data(), "Phrase"));
acc.data()->setState(FSCOMM_GW_STATE_REGED); acc.data()->setState(FSCOMM_GW_STATE_REGED);
emit accountStateChange(acc); emit accountStateChange(acc);
} else if (state == "UNREGED") { } else if (state == "UNREGED") {
acc.data()->setStatusPhrase(switch_event_get_header_nil(event, "Phrase")); acc.data()->setStatusPhrase(switch_event_get_header_nil(event.data(), "Phrase"));
acc.data()->setState(FSCOMM_GW_STATE_UNREGED); acc.data()->setState(FSCOMM_GW_STATE_UNREGED);
emit accountStateChange(acc); emit accountStateChange(acc);
} else if (state == "UNREGISTER") { } else if (state == "UNREGISTER") {
acc.data()->setStatusPhrase(switch_event_get_header_nil(event, "Phrase")); acc.data()->setStatusPhrase(switch_event_get_header_nil(event.data(), "Phrase"));
acc.data()->setState(FSCOMM_GW_STATE_UNREGISTER); acc.data()->setState(FSCOMM_GW_STATE_UNREGISTER);
emit accountStateChange(acc); emit accountStateChange(acc);
} else if (state =="FAILED") { } else if (state =="FAILED") {
acc.data()->setStatusPhrase(switch_event_get_header_nil(event, "Phrase")); acc.data()->setStatusPhrase(switch_event_get_header_nil(event.data(), "Phrase"));
acc.data()->setState(FSCOMM_GW_STATE_FAILED); acc.data()->setState(FSCOMM_GW_STATE_FAILED);
emit accountStateChange(acc); emit accountStateChange(acc);
} else if (state == "FAIL_WAIT") { } else if (state == "FAIL_WAIT") {
acc.data()->setState(FSCOMM_GW_STATE_FAIL_WAIT); acc.data()->setState(FSCOMM_GW_STATE_FAIL_WAIT);
emit accountStateChange(acc); emit accountStateChange(acc);
} else if (state == "EXPIRED") { } else if (state == "EXPIRED") {
acc.data()->setStatusPhrase(switch_event_get_header_nil(event, "Phrase")); acc.data()->setStatusPhrase(switch_event_get_header_nil(event.data(), "Phrase"));
acc.data()->setState(FSCOMM_GW_STATE_EXPIRED); acc.data()->setState(FSCOMM_GW_STATE_EXPIRED);
emit accountStateChange(acc); emit accountStateChange(acc);
} else if (state == "NOREG") { } else if (state == "NOREG") {
acc.data()->setStatusPhrase(switch_event_get_header_nil(event, "Phrase")); acc.data()->setStatusPhrase(switch_event_get_header_nil(event.data(), "Phrase"));
acc.data()->setState(FSCOMM_GW_STATE_NOREG); acc.data()->setState(FSCOMM_GW_STATE_NOREG);
emit accountStateChange(acc); emit accountStateChange(acc);
} }
} }
else if (strcmp(event->subclass_name, "sofia::gateway_add") == 0) else if (strcmp(event.data()->subclass_name, "sofia::gateway_add") == 0)
{ {
QString gw = switch_event_get_header_nil(event, "Gateway"); QString gw = switch_event_get_header_nil(event.data(), "Gateway");
Account * accPtr = new Account(gw); Account * accPtr = new Account(gw);
QSharedPointer<Account> acc = QSharedPointer<Account>(accPtr); QSharedPointer<Account> acc = QSharedPointer<Account>(accPtr);
acc.data()->setState(FSCOMM_GW_STATE_NOAVAIL); acc.data()->setState(FSCOMM_GW_STATE_NOAVAIL);
_accounts.insert(gw, acc); _accounts.insert(gw, acc);
emit newAccount(acc); emit newAccount(acc);
} }
else if (strcmp(event->subclass_name, "sofia::gateway_delete") == 0) else if (strcmp(event.data()->subclass_name, "sofia::gateway_delete") == 0)
{ {
QSharedPointer<Account> acc = _accounts.take(switch_event_get_header_nil(event, "Gateway")); QSharedPointer<Account> acc = _accounts.take(switch_event_get_header_nil(event.data(), "Gateway"));
if (!acc.isNull()) if (!acc.isNull())
emit delAccount(acc); emit delAccount(acc);
} }
else else
{ {
printEventHeaders(event); //printEventHeaders(event);
} }
break; break;
} }
case SWITCH_EVENT_MODULE_LOAD: case SWITCH_EVENT_MODULE_LOAD:
{ {
QString modType = switch_event_get_header_nil(event, "type"); QString modType = switch_event_get_header_nil(event.data(), "type");
QString modName = switch_event_get_header_nil(event, "name"); QString modKey = switch_event_get_header_nil(event.data(), "key");
QString modKey = switch_event_get_header_nil(event, "key"); emit loadedModule(modType, modKey);
emit loadedModule(modType, modName, modKey);
break; break;
} }
default: default:
@ -429,7 +350,114 @@ void FSHost::generalEventHandler(switch_event_t *event)
} }
} }
void FSHost::minimalModuleLoaded(QString modType, QString modName, QString modKey) void FSHost::eventChannelCreate(QSharedPointer<switch_event_t>event, QString uuid)
{
Channel *channelPtr = new Channel(uuid);
QSharedPointer<Channel>channel(channelPtr);
_channels.insert(uuid, channel);
}
void FSHost::eventChannelAnswer(QSharedPointer<switch_event_t>event, QString uuid)
{
_channels.value(uuid).data()->setDestinatinonNumber(switch_event_get_header_nil(event.data(), "Caller-Destination-Number"));
if (_active_calls.contains(uuid))
{
_active_calls.value(uuid).data()->setAnsweredEpoch(QString(switch_event_get_header_nil(event.data(), "Caller-Channel-Answered-Time")).toULongLong());
_active_calls.value(uuid).data()->setState(FSCOMM_CALL_STATE_ANSWERED);
emit answered(_active_calls.value(uuid));
}
}
void FSHost::eventChannelState(QSharedPointer<switch_event_t>event, QString uuid)
{}
void FSHost::eventChannelExecute(QSharedPointer<switch_event_t>event, QString uuid)
{}
void FSHost::eventChannelExecuteComplete(QSharedPointer<switch_event_t>event, QString uuid)
{
_channels.value(uuid).data()->setPaCallId(atoi(switch_event_get_header_nil(event.data(), "variable_pa_call_id")));
}
void FSHost::eventChannelOutgoing(QSharedPointer<switch_event_t>event, QString uuid)
{
/* Checks if this is an inbound or outbound call */
/** Outbound call */
if ( strcmp(switch_event_get_header_nil(event.data(), "Caller-Source"), "mod_portaudio") == 0 )
{
Call *callPtr = new Call();
callPtr->setCallDirection(FSCOMM_CALL_DIRECTION_OUTBOUND);
callPtr->setChannel(_channels.value(uuid));
callPtr->setOtherLegChannel(_channels.value(switch_event_get_header_nil(event.data(), "Other-Leg-Unique-ID")));
QSharedPointer<Call> call(callPtr);
_active_calls.insert(uuid, call);
call.data()->setState(FSCOMM_CALL_STATE_TRYING);
emit newOutgoingCall(call);
}
/** Inbound call */
else
{
Call *callPtr = new Call();
callPtr->setCallDirection(FSCOMM_CALL_DIRECTION_INBOUND);
callPtr->setChannel(_channels.value(uuid));
callPtr->setOtherLegChannel(_channels.value(switch_event_get_header_nil(event.data(), "Other-Leg-Unique-ID")));
QSharedPointer<Call> call(callPtr);
_active_calls.insert(uuid, call);
call.data()->setState(FSCOMM_CALL_STATE_RINGING);
_channels.value(uuid).data()->setCreatedEpoch(QString(switch_event_get_header_nil(event.data(), "Caller-Channel-Created-Time")).toULongLong());
emit ringing(call);
}
}
void FSHost::eventChannelOriginate(QSharedPointer<switch_event_t>event, QString uuid)
{}
void FSHost::eventChannelProgress(QSharedPointer<switch_event_t>event, QString uuid)
{}
void FSHost::eventChannelProgressMedia(QSharedPointer<switch_event_t>event, QString uuid)
{
_channels.value(uuid).data()->setProgressEpoch(QString(switch_event_get_header_nil(event.data(), "Caller-Channel-Progress-Time")).toULongLong());
if (_active_calls.contains(uuid))
{
_active_calls.value(uuid).data()->setState(FSCOMM_CALL_STATE_RINGING);
emit ringing(_active_calls.value(uuid));
}
}
void FSHost::eventChannelBridge(QSharedPointer<switch_event_t>event, QString uuid)
{
QString time;
time = switch_event_get_header_nil(event.data(), "Caller-Channel-Progress-Time");
if (time.toULongLong() > 0) _channels.value(uuid).data()->setProgressEpoch(time.toULongLong());
time = switch_event_get_header_nil(event.data(), "Caller-Channel-Progress-Media-Time");
if (time.toULongLong() > 0) _channels.value(uuid).data()->setProgressMediaEpoch(time.toULongLong());
}
void FSHost::eventChannelHangup(QSharedPointer<switch_event_t>event, QString uuid)
{}
void FSHost::eventChannelUnbridge(QSharedPointer<switch_event_t>event, QString uuid)
{}
void FSHost::eventChannelHangupComplete(QSharedPointer<switch_event_t>event, QString uuid)
{
if (_active_calls.contains(uuid))
{
if (_active_calls.value(uuid).data()->getState() != FSCOMM_CALL_STATE_ANSWERED)
{
_active_calls.value(uuid).data()->setState(FSCOMM_CALL_STATE_FAILED);
_active_calls.value(uuid).data()->setCause(switch_event_get_header_nil(event.data(), "variable_originate_disposition"));
emit callFailed(_active_calls.value(uuid));
return;
}
emit hungup(_active_calls.take(uuid));
}
}
void FSHost::eventChannelDestroy(QSharedPointer<switch_event_t>event, QString uuid)
{
_channels.take(uuid);
}
void FSHost::eventCodec(QSharedPointer<switch_event_t>event, QString uuid)
{
_channels.value(uuid).data()->setCidName(switch_event_get_header_nil(event.data(), "Caller-Caller-ID-Name"));
_channels.value(uuid).data()->setCidNumber(switch_event_get_header_nil(event.data(), "Caller-Caller-ID-Number"));
}
void FSHost::eventCallUpdate(QSharedPointer<switch_event_t>event, QString uuid)
{}
void FSHost::eventRecvInfo(QSharedPointer<switch_event_t>event, QString uuid)
{}
void FSHost::minimalModuleLoaded(QString modType, QString modKey)
{ {
if (modType == "endpoint") if (modType == "endpoint")
{ {
@ -501,11 +529,11 @@ QSharedPointer<Call> FSHost::getCurrentActiveCall()
return QSharedPointer<Call>(); return QSharedPointer<Call>();
} }
void FSHost::printEventHeaders(switch_event_t *event) void FSHost::printEventHeaders(QSharedPointer<switch_event_t>event)
{ {
switch_event_header_t *hp; switch_event_header_t *hp;
qDebug() << QString("Received event: %1(%2)\n").arg(switch_event_name(event->event_id), switch_event_get_header_nil(event, "Event-Subclass")); qDebug() << QString("Received event: %1(%2)").arg(switch_event_name(event.data()->event_id), switch_event_get_header_nil(event.data(), "Event-Subclass"));
for (hp = event->headers; hp; hp = hp->next) { for (hp = event.data()->headers; hp; hp = hp->next) {
qDebug() << hp->name << "=" << hp->value; qDebug() << hp->name << "=" << hp->value;
} }
qDebug() << "\n\n"; qDebug() << "\n\n";

View File

@ -35,6 +35,7 @@
#include <QSharedPointer> #include <QSharedPointer>
#include <switch.h> #include <switch.h>
#include "call.h" #include "call.h"
#include "channel.h"
#include "account.h" #include "account.h"
class FSHost : public QThread class FSHost : public QThread
@ -43,7 +44,8 @@ Q_OBJECT
public: public:
explicit FSHost(QObject *parent = 0); explicit FSHost(QObject *parent = 0);
switch_status_t sendCmd(const char *cmd, const char *args, QString *res); switch_status_t sendCmd(const char *cmd, const char *args, QString *res);
void generalEventHandler(switch_event_t *event); void generalEventHandler(QSharedPointer<switch_event_t>event);
void generalLoggerHandler(QSharedPointer<switch_log_node_t>node, switch_log_level_t level);
QSharedPointer<Call> getCallByUUID(QString uuid) { return _active_calls.value(uuid); } QSharedPointer<Call> getCallByUUID(QString uuid) { return _active_calls.value(uuid); }
QSharedPointer<Call> getCurrentActiveCall(); QSharedPointer<Call> getCurrentActiveCall();
QList<QSharedPointer<Account> > getAccounts() { return _accounts.values(); } QList<QSharedPointer<Account> > getAccounts() { return _accounts.values(); }
@ -57,15 +59,25 @@ protected:
void run(void); void run(void);
signals: signals:
/* Status signals */
void coreLoadingError(QString); void coreLoadingError(QString);
void loadingModules(QString, int, QColor); void loadingModules(QString, int, QColor);
void loadedModule(QString, QString, QString); void loadedModule(QString, QString);
void ready(void); void ready(void);
/* Logging signals */
void eventLog(QSharedPointer<switch_log_node_t>, switch_log_level_t);
void newEvent(QSharedPointer<switch_event_t>);
/* Call signals */
void ringing(QSharedPointer<Call>); void ringing(QSharedPointer<Call>);
void answered(QSharedPointer<Call>); void answered(QSharedPointer<Call>);
void newOutgoingCall(QSharedPointer<Call>); void newOutgoingCall(QSharedPointer<Call>);
void callFailed(QSharedPointer<Call>); void callFailed(QSharedPointer<Call>);
void hungup(QSharedPointer<Call>); void hungup(QSharedPointer<Call>);
/* Account signals */
void accountStateChange(QSharedPointer<Account>); void accountStateChange(QSharedPointer<Account>);
void newAccount(QSharedPointer<Account>); void newAccount(QSharedPointer<Account>);
void delAccount(QSharedPointer<Account>); void delAccount(QSharedPointer<Account>);
@ -73,16 +85,39 @@ signals:
private slots: private slots:
/* We need to wait for the gateway deletion before reloading it */ /* We need to wait for the gateway deletion before reloading it */
void accountReloadSlot(QSharedPointer<Account>); void accountReloadSlot(QSharedPointer<Account>);
void minimalModuleLoaded(QString, QString, QString); void minimalModuleLoaded(QString, QString);
private: private:
switch_status_t processBlegEvent(switch_event_t *, QString); /* Helper methods */
switch_status_t processAlegEvent(switch_event_t *, QString);
void createFolders(); void createFolders();
void printEventHeaders(switch_event_t *event); void printEventHeaders(QSharedPointer<switch_event_t>event);
/*FSM State handlers*/
/** Channel Related*/
void eventChannelCreate(QSharedPointer<switch_event_t> event, QString uuid);
void eventChannelAnswer(QSharedPointer<switch_event_t> event, QString uuid);
void eventChannelState(QSharedPointer<switch_event_t>event, QString uuid);
void eventChannelExecute(QSharedPointer<switch_event_t>event, QString uuid);
void eventChannelExecuteComplete(QSharedPointer<switch_event_t>event, QString uuid);
void eventChannelOutgoing(QSharedPointer<switch_event_t>event, QString uuid);
void eventChannelOriginate(QSharedPointer<switch_event_t>event, QString uuid);
void eventChannelProgress(QSharedPointer<switch_event_t>event, QString uuid);
void eventChannelProgressMedia(QSharedPointer<switch_event_t>event, QString uuid);
void eventChannelBridge(QSharedPointer<switch_event_t>event, QString uuid);
void eventChannelHangup(QSharedPointer<switch_event_t>event, QString uuid);
void eventChannelUnbridge(QSharedPointer<switch_event_t>event, QString uuid);
void eventChannelHangupComplete(QSharedPointer<switch_event_t>event, QString uuid);
void eventChannelDestroy(QSharedPointer<switch_event_t>event, QString uuid);
/** Others*/
void eventCodec(QSharedPointer<switch_event_t>event, QString uuid);
void eventCallUpdate(QSharedPointer<switch_event_t>event, QString uuid);
void eventRecvInfo(QSharedPointer<switch_event_t>event, QString uuid);
/* Structures to keep track of things */
QHash<QString, QSharedPointer<Call> > _active_calls; QHash<QString, QSharedPointer<Call> > _active_calls;
QHash<QString, QSharedPointer<Account> > _accounts; QHash<QString, QSharedPointer<Account> > _accounts;
QHash<QString, QString> _bleg_uuids; QHash<QString, QSharedPointer<Channel> > _channels;
QList<QString> _reloading_Accounts; QList<QString> _reloading_Accounts;
QList<QString> _loadedModules; QList<QString> _loadedModules;
}; };
@ -92,14 +127,25 @@ extern FSHost g_FSHost;
/* /*
Used to match callback from fs core. We dup the event and call the class Used to match callback from fs core. We dup the event and call the class
method callback to make use of the signal/slot infrastructure. method callback to make use of the signal/slot infrastructure.
*/ */
static void eventHandlerCallback(switch_event_t *event) static void eventHandlerCallback(switch_event_t *event)
{ {
switch_event_t *clone = NULL; switch_event_t *clone = NULL;
if (switch_event_dup(&clone, event) == SWITCH_STATUS_SUCCESS) { if (switch_event_dup(&clone, event) == SWITCH_STATUS_SUCCESS) {
g_FSHost.generalEventHandler(clone); QSharedPointer<switch_event_t> e(clone);
g_FSHost.generalEventHandler(e);
} }
switch_safe_free(clone); }
/*
Used to propagate logs on the application
*/
static switch_status_t loggerHandler(const switch_log_node_t *node, switch_log_level_t level)
{
switch_log_node_t *clone = switch_log_node_dup(node);
QSharedPointer<switch_log_node_t> l(clone);
g_FSHost.generalLoggerHandler(l, level);
return SWITCH_STATUS_SUCCESS;
} }
#endif // FSHOST_H #endif // FSHOST_H

View File

@ -36,7 +36,10 @@
MainWindow::MainWindow(QWidget *parent) : MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent), QMainWindow(parent),
ui(new Ui::MainWindow), ui(new Ui::MainWindow),
preferences(NULL) preferences(NULL),
_consoleWindow(NULL),
_stateDebugDialog(NULL)
{ {
ui->setupUi(this); ui->setupUi(this);
@ -97,9 +100,12 @@ MainWindow::MainWindow(QWidget *parent) :
connect(ui->answerBtn, SIGNAL(clicked()), this, SLOT(paAnswer())); connect(ui->answerBtn, SIGNAL(clicked()), this, SLOT(paAnswer()));
connect(ui->hangupBtn, SIGNAL(clicked()), this, SLOT(paHangup())); connect(ui->hangupBtn, SIGNAL(clicked()), this, SLOT(paHangup()));
connect(ui->recoredCallBtn, SIGNAL(toggled(bool)), SLOT(recordCall(bool))); connect(ui->recoredCallBtn, SIGNAL(toggled(bool)), SLOT(recordCall(bool)));
connect(ui->btnHold, SIGNAL(toggled(bool)), this, SLOT(holdCall(bool)));
connect(ui->tableCalls, SIGNAL(itemDoubleClicked(QTableWidgetItem*)), this, SLOT(callTableDoubleClick(QTableWidgetItem*))); connect(ui->tableCalls, SIGNAL(itemDoubleClicked(QTableWidgetItem*)), this, SLOT(callTableDoubleClick(QTableWidgetItem*)));
connect(ui->action_Preferences, SIGNAL(triggered()), this, SLOT(prefTriggered())); connect(ui->action_Preferences, SIGNAL(triggered()), this, SLOT(prefTriggered()));
connect(ui->action_Exit, SIGNAL(triggered()), this, SLOT(close())); connect(ui->action_Exit, SIGNAL(triggered()), this, SLOT(close()));
connect(ui->actionConsole, SIGNAL(triggered()), this, SLOT(debugConsoleTriggered()));
connect(ui->actionEvents, SIGNAL(triggered()), this, SLOT(debugEventsTriggered()));
connect(ui->actionAbout, SIGNAL(triggered()), this, SLOT(showAbout())); connect(ui->actionAbout, SIGNAL(triggered()), this, SLOT(showAbout()));
connect(ui->actionSetDefaultAccount, SIGNAL(triggered(bool)), this, SLOT(setDefaultAccount())); connect(ui->actionSetDefaultAccount, SIGNAL(triggered(bool)), this, SLOT(setDefaultAccount()));
connect(sysTray, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(sysTrayActivated(QSystemTrayIcon::ActivationReason))); connect(sysTray, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(sysTrayActivated(QSystemTrayIcon::ActivationReason)));
@ -133,7 +139,7 @@ void MainWindow::updateCallTimers()
QSharedPointer<Call> call = g_FSHost.getCallByUUID(item->data(Qt::UserRole).toString()); QSharedPointer<Call> call = g_FSHost.getCallByUUID(item->data(Qt::UserRole).toString());
QTime time = call.data()->getCurrentStateTime(); QTime time = call.data()->getCurrentStateTime();
item->setText(time.toString("hh:mm:ss")); item->setText(time.toString("hh:mm:ss"));
item->setTextAlignment(Qt::AlignRight); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
} }
} }
@ -151,6 +157,28 @@ void MainWindow::setDefaultAccount()
settings.endGroup(); settings.endGroup();
} }
void MainWindow::debugEventsTriggered()
{
if (!_stateDebugDialog)
_stateDebugDialog = new StateDebugDialog();
_stateDebugDialog->raise();
_stateDebugDialog->show();
_stateDebugDialog->activateWindow();
}
void MainWindow::debugConsoleTriggered()
{
if (!_consoleWindow)
_consoleWindow = new ConsoleWindow();
_consoleWindow->raise();
_consoleWindow->show();
_consoleWindow->activateWindow();
}
void MainWindow::prefTriggered() void MainWindow::prefTriggered()
{ {
if (!preferences) if (!preferences)
@ -267,7 +295,6 @@ void MainWindow::makeCall()
switch_core_set_variable("fscomm_caller_id_name", cidName.toAscii().data()); switch_core_set_variable("fscomm_caller_id_name", cidName.toAscii().data());
switch_core_set_variable("fscomm_caller_id_num", cidNum.toAscii().data()); switch_core_set_variable("fscomm_caller_id_num", cidNum.toAscii().data());
qDebug() << "Name:" << cidName << "Num:" << cidNum;
} }
if (ok && !dialstring.isEmpty()) if (ok && !dialstring.isEmpty())
@ -337,16 +364,35 @@ void MainWindow::paHangup()
ui->hangupBtn->setEnabled(false); ui->hangupBtn->setEnabled(false);
} }
void MainWindow::holdCall(bool pressed)
{
QSharedPointer<Call> call = g_FSHost.getCurrentActiveCall();
if (call.isNull())
{
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not hold call because there is not current active call!.\n");
return;
}
if (call.data()->toggleHold(pressed) != SWITCH_STATUS_SUCCESS)
{
QMessageBox::warning(this,tr("Hold call"),
tr("<p>Could not get active call to hold/unhold."
"<p>Please report this bug."),
QMessageBox::Ok);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not hold/unhold call [%s].\n", call.data()->getUuid().toAscii().data());
return;
}
}
void MainWindow::recordCall(bool pressed) void MainWindow::recordCall(bool pressed)
{ {
QSharedPointer<Call> call = g_FSHost.getCurrentActiveCall(); QSharedPointer<Call> call = g_FSHost.getCurrentActiveCall();
if (call.isNull()) if (call.isNull())
{ {
QMessageBox::warning(this,tr("Record call"),
tr("<p>FSComm reports that there are no active calls to be recorded."
"<p>Please report this bug."),
QMessageBox::Ok);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not record call because there is not current active call!.\n"); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not record call because there is not current active call!.\n");
return; return;
} }
@ -357,26 +403,26 @@ void MainWindow::recordCall(bool pressed)
tr("<p>Could not get active call to start/stop recording." tr("<p>Could not get active call to start/stop recording."
"<p>Please report this bug."), "<p>Please report this bug."),
QMessageBox::Ok); QMessageBox::Ok);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not record call [%s].\n", call.data()->getUUID().toAscii().data()); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not record call [%s].\n", call.data()->getUuid().toAscii().data());
return; return;
} }
} }
void MainWindow::newOutgoingCall(QSharedPointer<Call> call) void MainWindow::newOutgoingCall(QSharedPointer<Call> call)
{ {
ui->textEdit->setText(QString("Calling %1 (%2)").arg(call.data()->getCidName(), call.data()->getCidNumber())); ui->textEdit->setText(QString("Calling %1").arg(call.data()->getDestinationNumber()));
ui->tableCalls->setRowCount(ui->tableCalls->rowCount()+1); ui->tableCalls->setRowCount(ui->tableCalls->rowCount()+1);
QTableWidgetItem *item0 = new QTableWidgetItem(QString("%1 (%2)").arg(call.data()->getCidName(), call.data()->getCidNumber())); QTableWidgetItem *item0 = new QTableWidgetItem(QString("%1").arg(call.data()->getDestinationNumber()));
item0->setData(Qt::UserRole, call.data()->getUUID()); item0->setData(Qt::UserRole, call.data()->getUuid());
ui->tableCalls->setItem(ui->tableCalls->rowCount()-1,0,item0); ui->tableCalls->setItem(ui->tableCalls->rowCount()-1,0,item0);
QTableWidgetItem *item1 = new QTableWidgetItem(tr("Dialing...")); QTableWidgetItem *item1 = new QTableWidgetItem(tr("Dialing..."));
item1->setData(Qt::UserRole, call.data()->getUUID()); item1->setData(Qt::UserRole, call.data()->getUuid());
ui->tableCalls->setItem(ui->tableCalls->rowCount()-1,1,item1); ui->tableCalls->setItem(ui->tableCalls->rowCount()-1,1,item1);
QTableWidgetItem *item2 = new QTableWidgetItem("00:00:00"); QTableWidgetItem *item2 = new QTableWidgetItem("00:00:00");
item2->setData(Qt::UserRole, call.data()->getUUID()); item2->setData(Qt::UserRole, call.data()->getUuid());
ui->tableCalls->setItem(ui->tableCalls->rowCount()-1,2,item2); ui->tableCalls->setItem(ui->tableCalls->rowCount()-1,2,item2);
ui->tableCalls->resizeColumnsToContents(); ui->tableCalls->resizeColumnsToContents();
@ -393,27 +439,33 @@ void MainWindow::ringing(QSharedPointer<Call> call)
for (int i=0; i<ui->tableCalls->rowCount(); i++) for (int i=0; i<ui->tableCalls->rowCount(); i++)
{ {
QTableWidgetItem *item = ui->tableCalls->item(i, 1); QTableWidgetItem *item = ui->tableCalls->item(i, 1);
if (item->data(Qt::UserRole).toString() == call.data()->getUUID()) if (item->data(Qt::UserRole).toString() == call.data()->getUuid())
{ {
item->setText(tr("Ringing")); item->setText(tr("Ringing"));
ui->textEdit->setText(QString("Call from %1 (%2)").arg(call.data()->getCidName(), call.data()->getCidNumber())); if (call.data()->getDirection() == FSCOMM_CALL_DIRECTION_INBOUND)
ui->textEdit->setText(QString("Call from %1 (%2)").arg(call.data()->getCidName(), call.data()->getCidNumber()));
else
ui->textEdit->setText(QString("Call to %1 is ringing.").arg(call.data()->getDestinationNumber()));
return; return;
} }
} }
ui->textEdit->setText(QString("Call from %1 (%2)").arg(call.data()->getCidName(), call.data()->getCidNumber())); if (call.data()->getDirection() == FSCOMM_CALL_DIRECTION_INBOUND)
ui->textEdit->setText(QString("Call from %1 (%2)").arg(call.data()->getCidName(), call.data()->getCidNumber()));
else
ui->textEdit->setText(QString("Call to %1 is ringing.").arg(call.data()->getDestinationNumber()));
ui->tableCalls->setRowCount(ui->tableCalls->rowCount()+1); ui->tableCalls->setRowCount(ui->tableCalls->rowCount()+1);
QTableWidgetItem *item0 = new QTableWidgetItem(QString("%1 (%2)").arg(call.data()->getCidName(), call.data()->getCidNumber())); QTableWidgetItem *item0 = new QTableWidgetItem(QString("%1 (%2)").arg(call.data()->getCidName(), call.data()->getCidNumber()));
item0->setData(Qt::UserRole, call.data()->getUUID()); item0->setData(Qt::UserRole, call.data()->getUuid());
ui->tableCalls->setItem(ui->tableCalls->rowCount()-1,0,item0); ui->tableCalls->setItem(ui->tableCalls->rowCount()-1,0,item0);
QTableWidgetItem *item1 = new QTableWidgetItem(tr("Ringing")); QTableWidgetItem *item1 = new QTableWidgetItem(tr("Ringing"));
item1->setData(Qt::UserRole, call.data()->getUUID()); item1->setData(Qt::UserRole, call.data()->getUuid());
ui->tableCalls->setItem(ui->tableCalls->rowCount()-1,1,item1); ui->tableCalls->setItem(ui->tableCalls->rowCount()-1,1,item1);
QTableWidgetItem *item2 = new QTableWidgetItem("00:00:00"); QTableWidgetItem *item2 = new QTableWidgetItem("00:00:00");
item2->setData(Qt::UserRole, call.data()->getUUID()); item2->setData(Qt::UserRole, call.data()->getUuid());
ui->tableCalls->setItem(ui->tableCalls->rowCount()-1,2,item2); ui->tableCalls->setItem(ui->tableCalls->rowCount()-1,2,item2);
ui->tableCalls->resizeColumnsToContents(); ui->tableCalls->resizeColumnsToContents();
@ -429,7 +481,7 @@ void MainWindow::answered(QSharedPointer<Call> call)
for (int i=0; i<ui->tableCalls->rowCount(); i++) for (int i=0; i<ui->tableCalls->rowCount(); i++)
{ {
QTableWidgetItem *item = ui->tableCalls->item(i, 1); QTableWidgetItem *item = ui->tableCalls->item(i, 1);
if (item->data(Qt::UserRole).toString() == call.data()->getUUID()) if (item->data(Qt::UserRole).toString() == call.data()->getUuid())
{ {
item->setText(tr("Answered")); item->setText(tr("Answered"));
ui->tableCalls->resizeColumnsToContents(); ui->tableCalls->resizeColumnsToContents();
@ -440,6 +492,9 @@ void MainWindow::answered(QSharedPointer<Call> call)
} }
ui->recoredCallBtn->setEnabled(true); ui->recoredCallBtn->setEnabled(true);
ui->recoredCallBtn->setChecked(false); ui->recoredCallBtn->setChecked(false);
ui->btnHold->setEnabled(true);
ui->btnHold->setChecked(false);
ui->btnTransfer->setEnabled(true);
ui->dtmf0Btn->setEnabled(true); ui->dtmf0Btn->setEnabled(true);
ui->dtmf1Btn->setEnabled(true); ui->dtmf1Btn->setEnabled(true);
ui->dtmf2Btn->setEnabled(true); ui->dtmf2Btn->setEnabled(true);
@ -463,7 +518,7 @@ void MainWindow::callFailed(QSharedPointer<Call> call)
for (int i=0; i<ui->tableCalls->rowCount(); i++) for (int i=0; i<ui->tableCalls->rowCount(); i++)
{ {
QTableWidgetItem *item = ui->tableCalls->item(i, 1); QTableWidgetItem *item = ui->tableCalls->item(i, 1);
if (item->data(Qt::UserRole).toString() == call.data()->getUUID()) if (item->data(Qt::UserRole).toString() == call.data()->getUuid())
{ {
ui->tableCalls->removeRow(i); ui->tableCalls->removeRow(i);
ui->tableCalls->resizeColumnsToContents(); ui->tableCalls->resizeColumnsToContents();
@ -472,13 +527,26 @@ void MainWindow::callFailed(QSharedPointer<Call> call)
break; break;
} }
} }
ui->textEdit->setText(tr("Call with %1 (%2) failed with reason %3.").arg(call.data()->getCidName(), if (call.data()->getDirection() == FSCOMM_CALL_DIRECTION_INBOUND)
call.data()->getCidNumber(), {
call.data()->getCause())); ui->textEdit->setText(tr("Call from %1 (%2) failed with reason %3.").arg(call.data()->getCidName(),
call.data()->getCidNumber(),
call.data()->getCause()));
}
else
{
ui->textEdit->setText(tr("Call to %1 failed with reason %3.").arg(call.data()->getCidName(),
call.data()->getCidNumber(),
call.data()->getCause()));
}
call.data()->setActive(false); call.data()->setActive(false);
/* TODO: Will cause problems if 2 calls are received at the same time */ /* TODO: Will cause problems if 2 calls are received at the same time */
ui->recoredCallBtn->setEnabled(false); ui->recoredCallBtn->setEnabled(false);
ui->recoredCallBtn->setChecked(false); ui->recoredCallBtn->setChecked(false);
ui->btnHold->setEnabled(false);
ui->btnHold->setChecked(false);
ui->btnTransfer->setEnabled(false);
ui->answerBtn->setEnabled(false); ui->answerBtn->setEnabled(false);
ui->hangupBtn->setEnabled(false); ui->hangupBtn->setEnabled(false);
ui->dtmf0Btn->setEnabled(false); ui->dtmf0Btn->setEnabled(false);
@ -505,7 +573,7 @@ void MainWindow::hungup(QSharedPointer<Call> call)
for (int i=0; i<ui->tableCalls->rowCount(); i++) for (int i=0; i<ui->tableCalls->rowCount(); i++)
{ {
QTableWidgetItem *item = ui->tableCalls->item(i, 1); QTableWidgetItem *item = ui->tableCalls->item(i, 1);
if (item->data(Qt::UserRole).toString() == call.data()->getUUID()) if (item->data(Qt::UserRole).toString() == call.data()->getUuid())
{ {
ui->tableCalls->removeRow(i); ui->tableCalls->removeRow(i);
ui->tableCalls->resizeColumnsToContents(); ui->tableCalls->resizeColumnsToContents();
@ -515,10 +583,20 @@ void MainWindow::hungup(QSharedPointer<Call> call)
} }
} }
call.data()->setActive(false); call.data()->setActive(false);
ui->textEdit->setText(tr("Call with %1 (%2) hungup.").arg(call.data()->getCidName(), call.data()->getCidNumber())); if (call.data()->getDirection() == FSCOMM_CALL_DIRECTION_INBOUND)
{
ui->textEdit->setText(tr("Call with %1 (%2) hungup.").arg(call.data()->getCidName(), call.data()->getCidNumber()));
}
else
{
ui->textEdit->setText(tr("Call with %1 hungup.").arg(call.data()->getDestinationNumber()));
}
/* TODO: Will cause problems if 2 calls are received at the same time */ /* TODO: Will cause problems if 2 calls are received at the same time */
ui->recoredCallBtn->setEnabled(false); ui->recoredCallBtn->setEnabled(false);
ui->recoredCallBtn->setChecked(false); ui->recoredCallBtn->setChecked(false);
ui->btnHold->setEnabled(false);
ui->btnHold->setChecked(false);
ui->btnTransfer->setEnabled(false);
ui->answerBtn->setEnabled(false); ui->answerBtn->setEnabled(false);
ui->hangupBtn->setEnabled(false); ui->hangupBtn->setEnabled(false);
ui->dtmf0Btn->setEnabled(false); ui->dtmf0Btn->setEnabled(false);

View File

@ -40,6 +40,8 @@
#include <call.h> #include <call.h>
#include <account.h> #include <account.h>
#include "preferences/prefdialog.h" #include "preferences/prefdialog.h"
#include "debugtools/consolewindow.h"
#include "debugtools/statedebugdialog.h"
namespace Ui { namespace Ui {
class MainWindow; class MainWindow;
@ -74,17 +76,22 @@ private slots:
void hungup(QSharedPointer<Call>); void hungup(QSharedPointer<Call>);
void callFailed(QSharedPointer<Call>); void callFailed(QSharedPointer<Call>);
void recordCall(bool); void recordCall(bool);
void holdCall(bool);
void setDefaultAccount(); void setDefaultAccount();
void accountAdd(QSharedPointer<Account>); void accountAdd(QSharedPointer<Account>);
void accountDel(QSharedPointer<Account>); void accountDel(QSharedPointer<Account>);
void accountStateChanged(QSharedPointer<Account>); void accountStateChanged(QSharedPointer<Account>);
void sysTrayActivated(QSystemTrayIcon::ActivationReason reason); void sysTrayActivated(QSystemTrayIcon::ActivationReason reason);
void updateCallTimers(); void updateCallTimers();
void debugConsoleTriggered();
void debugEventsTriggered();
private: private:
Ui::MainWindow *ui; Ui::MainWindow *ui;
QSignalMapper *dialpadMapper; QSignalMapper *dialpadMapper;
PrefDialog *preferences; PrefDialog *preferences;
ConsoleWindow *_consoleWindow;
StateDebugDialog * _stateDebugDialog;
QSystemTrayIcon *sysTray; QSystemTrayIcon *sysTray;
QTimer *callTimer; QTimer *callTimer;
}; };

View File

@ -14,28 +14,250 @@
<string>FSComm - A FreeSWITCH Communicator</string> <string>FSComm - A FreeSWITCH Communicator</string>
</property> </property>
<widget class="QWidget" name="centralWidget"> <widget class="QWidget" name="centralWidget">
<layout class="QHBoxLayout" name="horizontalLayout_4"> <layout class="QHBoxLayout" name="horizontalLayout_5">
<item> <item>
<layout class="QVBoxLayout" name="verticalLayout_2"> <layout class="QVBoxLayout" name="verticalLayout_3">
<item> <item>
<widget class="QTextEdit" name="textEdit"> <layout class="QVBoxLayout" name="verticalLayout_2">
<property name="enabled"> <item>
<bool>false</bool> <widget class="QTextEdit" name="textEdit">
</property> <property name="enabled">
<property name="readOnly"> <bool>false</bool>
<bool>true</bool> </property>
</property> <property name="readOnly">
</widget> <bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="newCallBtn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>New Call</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnHold">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Hold</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QPushButton" name="answerBtn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Answer</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="hangupBtn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Hangup</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QPushButton" name="dtmf1Btn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>1</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="dtmf2Btn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>2</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="dtmf3Btn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>3</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="dtmf4Btn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>4</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="dtmf5Btn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>5</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="dtmf6Btn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>6</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QPushButton" name="dtmf7Btn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>7</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="dtmf8Btn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>8</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QPushButton" name="dtmf9Btn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>9</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QPushButton" name="dtmfAstBtn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>*</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QPushButton" name="dtmf0Btn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QPushButton" name="dtmfPoundBtn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>#</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QPushButton" name="dtmfABtn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>A</string>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QPushButton" name="dtmfBBtn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>B</string>
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QPushButton" name="dtmfDBtn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>D</string>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QPushButton" name="dtmfCBtn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>C</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item> </item>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout"> <layout class="QHBoxLayout" name="horizontalLayout_4">
<item> <item>
<widget class="QPushButton" name="newCallBtn"> <widget class="QPushButton" name="btnTransfer">
<property name="enabled"> <property name="enabled">
<bool>false</bool> <bool>false</bool>
</property> </property>
<property name="text"> <property name="text">
<string>New Call</string> <string>Transfer</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -47,200 +269,6 @@
<property name="text"> <property name="text">
<string>Record</string> <string>Record</string>
</property> </property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QPushButton" name="answerBtn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Answer</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="hangupBtn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Hangup</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QPushButton" name="dtmf1Btn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>1</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="dtmf2Btn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>2</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="dtmf3Btn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>3</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="dtmf4Btn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>4</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="dtmf5Btn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>5</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="dtmf6Btn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>6</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QPushButton" name="dtmf7Btn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>7</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="dtmf8Btn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>8</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QPushButton" name="dtmf9Btn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>9</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QPushButton" name="dtmfAstBtn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>*</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QPushButton" name="dtmf0Btn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QPushButton" name="dtmfPoundBtn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>#</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QPushButton" name="dtmfABtn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>A</string>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QPushButton" name="dtmfBBtn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>B</string>
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QPushButton" name="dtmfDBtn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>D</string>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QPushButton" name="dtmfCBtn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>C</string>
</property>
</widget> </widget>
</item> </item>
</layout> </layout>
@ -375,7 +403,21 @@
</property> </property>
<addaction name="actionAbout"/> <addaction name="actionAbout"/>
</widget> </widget>
<widget class="QMenu" name="menuTools">
<property name="title">
<string>&amp;Tools</string>
</property>
<widget class="QMenu" name="menuDebug">
<property name="title">
<string>&amp;Debug</string>
</property>
<addaction name="actionConsole"/>
<addaction name="actionEvents"/>
</widget>
<addaction name="menuDebug"/>
</widget>
<addaction name="menu_File"/> <addaction name="menu_File"/>
<addaction name="menuTools"/>
<addaction name="menuHelp"/> <addaction name="menuHelp"/>
</widget> </widget>
<widget class="QToolBar" name="mainToolBar"> <widget class="QToolBar" name="mainToolBar">
@ -410,6 +452,16 @@
<string>Set the default account for dialing out.</string> <string>Set the default account for dialing out.</string>
</property> </property>
</action> </action>
<action name="actionConsole">
<property name="text">
<string>Console</string>
</property>
</action>
<action name="actionEvents">
<property name="text">
<string>Events</string>
</property>
</action>
</widget> </widget>
<layoutdefault spacing="6" margin="11"/> <layoutdefault spacing="6" margin="11"/>
<resources/> <resources/>

View File

@ -201,7 +201,7 @@
<item> <item>
<widget class="QTabWidget" name="tabWidget"> <widget class="QTabWidget" name="tabWidget">
<property name="currentIndex"> <property name="currentIndex">
<number>2</number> <number>0</number>
</property> </property>
<widget class="QWidget" name="tab"> <widget class="QWidget" name="tab">
<attribute name="title"> <attribute name="title">
@ -490,28 +490,17 @@
<string>Codecs</string> <string>Codecs</string>
</attribute> </attribute>
<layout class="QFormLayout" name="formLayout_7"> <layout class="QFormLayout" name="formLayout_7">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="label_21">
<property name="text">
<string>codec-prefs</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="sofiaCodecPrefsEdit">
<property name="text">
<string>CELT@48000h,G7221@32000h,G7221@16000h,G722,PCMU,PCMA,GSM</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_30"> <widget class="QLabel" name="label_30">
<property name="text"> <property name="text">
<string>inbound-codec-negotiation</string> <string>inbound-codec-negotiation</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="1"> <item row="0" column="1">
<widget class="QComboBox" name="sofiaInboundCodecNegotiationCombo"> <widget class="QComboBox" name="sofiaInboundCodecNegotiationCombo">
<item> <item>
<property name="text"> <property name="text">
@ -525,15 +514,15 @@
</item> </item>
</widget> </widget>
</item> </item>
<item row="2" column="0"> <item row="1" column="0">
<widget class="QLabel" name="label_42"> <widget class="QLabel" name="label_42">
<property name="text"> <property name="text">
<string>Codecs</string> <string>Codecs</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="1"> <item row="1" column="1">
<widget class="QListWidget" name="listAvailableCodecs"/> <widget class="CodecWidget" name="sofiaProfileCodecWidget" native="true"/>
</item> </item>
</layout> </layout>
</widget> </widget>
@ -1028,6 +1017,14 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<customwidgets>
<customwidget>
<class>CodecWidget</class>
<extends>QWidget</extends>
<header>widgets/codecwidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources> <resources>
<include location="../resources.qrc"/> <include location="../resources.qrc"/>
</resources> </resources>

View File

@ -42,7 +42,7 @@ void PrefSofia::readConfig()
_ui->sofiaSipPortSpin->setValue(settings.value("sip-port").toInt()); _ui->sofiaSipPortSpin->setValue(settings.value("sip-port").toInt());
_ui->sofiaDialplanEdit->setText(settings.value("dialplan").toString()); _ui->sofiaDialplanEdit->setText(settings.value("dialplan").toString());
_ui->sofiaDtmfDurationSpin->setValue(settings.value("dtmf-duration").toInt()); _ui->sofiaDtmfDurationSpin->setValue(settings.value("dtmf-duration").toInt());
_ui->sofiaCodecPrefsEdit->setText(settings.value("codec-prefs").toString()); _ui->sofiaProfileCodecWidget->setCodecString(settings.value("codec-prefs").toString());
_ui->sofiaUseRtpTimerCombo->setCurrentIndex(_ui->sofiaUseRtpTimerCombo->findText(settings.value("use-rtp-timer").toString())); _ui->sofiaUseRtpTimerCombo->setCurrentIndex(_ui->sofiaUseRtpTimerCombo->findText(settings.value("use-rtp-timer").toString()));
_ui->sofiaRtpTimerNameEdit->setText(settings.value("rtp-timer-name").toString()); _ui->sofiaRtpTimerNameEdit->setText(settings.value("rtp-timer-name").toString());
_ui->sofiaRtpIpEdit->setText(settings.value("rtp-ip").toString()); _ui->sofiaRtpIpEdit->setText(settings.value("rtp-ip").toString());
@ -68,15 +68,6 @@ void PrefSofia::readConfig()
settings.endGroup(); settings.endGroup();
settings.endGroup(); settings.endGroup();
/* This is here to show the proper codec config! */
const switch_codec_implementation_t *codecs[SWITCH_MAX_CODECS];
uint32_t num_codecs = switch_loadable_module_get_codecs(codecs, sizeof(codecs) / sizeof(codecs[0]));
uint32_t x;
for (x = 0; x < num_codecs; x++) {
_ui->listAvailableCodecs->addItem(codecs[x]->iananame);
}
} }
void PrefSofia::writeConfig() void PrefSofia::writeConfig()
@ -110,7 +101,7 @@ void PrefSofia::writeConfig()
settings.setValue("sip-port", _ui->sofiaSipPortSpin->value()); settings.setValue("sip-port", _ui->sofiaSipPortSpin->value());
settings.setValue("dialplan", _ui->sofiaDialplanEdit->text()); settings.setValue("dialplan", _ui->sofiaDialplanEdit->text());
settings.setValue("dtmf-duration", _ui->sofiaDtmfDurationSpin->value()); settings.setValue("dtmf-duration", _ui->sofiaDtmfDurationSpin->value());
settings.setValue("codec-prefs", _ui->sofiaCodecPrefsEdit->text()); settings.setValue("codec-prefs", _ui->sofiaProfileCodecWidget->getCodecString());
settings.setValue("use-rtp-timer", _ui->sofiaUseRtpTimerCombo->currentText()); settings.setValue("use-rtp-timer", _ui->sofiaUseRtpTimerCombo->currentText());
settings.setValue("rtp-timer-name", _ui->sofiaRtpTimerNameEdit->text()); settings.setValue("rtp-timer-name", _ui->sofiaRtpTimerNameEdit->text());
settings.setValue("rtp-ip", _ui->sofiaRtpIpEdit->text()); settings.setValue("rtp-ip", _ui->sofiaRtpIpEdit->text());

View File

@ -0,0 +1,148 @@
#include "codecwidget.h"
#include "ui_codecwidget.h"
#include "fshost.h"
CodecWidget::CodecWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::CodecWidget)
{
ui->setupUi(this);
connect(ui->btnEnable, SIGNAL(clicked()), this, SLOT(enableCodecs()));
connect(ui->btnDisable, SIGNAL(clicked()), this, SLOT(disableCodecs()));
connect(ui->btnUp, SIGNAL(clicked()), this, SLOT(moveUp()));
connect(ui->btnDown, SIGNAL(clicked()), this, SLOT(moveDown()));
readCodecs();
}
CodecWidget::~CodecWidget()
{
delete ui;
}
void CodecWidget::moveUp()
{
QList<QListWidgetItem *>items = ui->listEnabledCodecs->selectedItems();
foreach(QListWidgetItem *item, items)
{
int row = ui->listEnabledCodecs->row(item);
if (row != 0)
ui->listEnabledCodecs->insertItem(row-1, ui->listEnabledCodecs->takeItem(row));
}
}
void CodecWidget::moveDown()
{
QList<QListWidgetItem *>items = ui->listEnabledCodecs->selectedItems();
foreach(QListWidgetItem *item, items)
{
int row = ui->listEnabledCodecs->row(item);
if (row != ui->listEnabledCodecs->count())
ui->listEnabledCodecs->insertItem(row+1, ui->listEnabledCodecs->takeItem(row));
}
}
void CodecWidget::enableCodecs()
{
QList<QListWidgetItem *>items = ui->listAvailCodecs->selectedItems();
foreach(QListWidgetItem *item, items)
{
ui->listEnabledCodecs->insertItem(0,item->text());
delete item;
}
}
void CodecWidget::disableCodecs()
{
QList<QListWidgetItem *>items = ui->listEnabledCodecs->selectedItems();
foreach(QListWidgetItem *item, items)
{
ui->listAvailCodecs->insertItem(0,item->text());
delete item;
}
}
void CodecWidget::changeEvent(QEvent *e)
{
QWidget::changeEvent(e);
switch (e->type()) {
case QEvent::LanguageChange:
ui->retranslateUi(this);
break;
default:
break;
}
}
void CodecWidget::readCodecs(void)
{
/* This is here to show the proper codec config! */
const switch_codec_implementation_t *codecs[SWITCH_MAX_CODECS];
uint32_t num_codecs = switch_loadable_module_get_codecs(codecs, sizeof(codecs) / sizeof(codecs[0]));
uint32_t x;
for (x = 0; x < num_codecs; x++) {
/* Codecs we cannot enable/disable or dont want to */
if (QString(codecs[x]->iananame) == "PROXY" ||
QString(codecs[x]->iananame) == "PROXY-VID")
{
continue;
}
QList<QHash<QString, QString> > implList;
QHash<QString, QString> implPair;
implPair.insert(QString::number(codecs[x]->samples_per_second), QString::number(codecs[x]->microseconds_per_packet/1000));
implList.append(implPair);
/* Iterate over the other implementations */
switch_codec_implementation_t *curr = codecs[x]->next;
while (curr != NULL)
{
QHash<QString, QString> implPair;
implPair.insert(QString::number(curr->samples_per_second), QString::number(curr->microseconds_per_packet/1000));
implList.append(implPair);
curr = curr->next;
}
_listCodecs.insert(codecs[x]->iananame, implList);
ui->listAvailCodecs->insertItem(0, codecs[x]->iananame);
}
ui->listAvailCodecs->sortItems(Qt::AscendingOrder);
}
QString CodecWidget::getCodecString()
{
QString codecList;
for(int i = 0; i<ui->listEnabledCodecs->count(); i++)
{
QString codecName = ui->listEnabledCodecs->item(i)->text();
if (!_listCodecs.contains(codecName))
QMessageBox::warning(this, tr("Error"), tr("Codec %1 does not exist as loaded codec, therefore will not be used.").arg(codecName), QMessageBox::Ok);
codecList += codecName;
if (i!= ui->listEnabledCodecs->count()-1)
codecList += ",";
}
return codecList;
}
void CodecWidget::setCodecString(QString codecList)
{
QStringList rawEnCodecs;
QStringList split = codecList.split(",");
foreach(QString s, split)
{
QStringList cs = s.split("@");
if (!rawEnCodecs.contains(cs[0]))
{
ui->listEnabledCodecs->insertItem(ui->listEnabledCodecs->count(), cs[0]);
rawEnCodecs.append(cs[0]);
}
}
foreach(QString c, rawEnCodecs)
{
foreach(QListWidgetItem *i, ui->listAvailCodecs->findItems(c, Qt::MatchExactly))
{
delete i;
}
}
}

View File

@ -0,0 +1,33 @@
#ifndef CODECWIDGET_H
#define CODECWIDGET_H
#include <QtGui>
namespace Ui {
class CodecWidget;
}
class CodecWidget : public QWidget {
Q_OBJECT
public:
CodecWidget(QWidget *parent = 0);
~CodecWidget();
QString getCodecString();
void setCodecString(QString);
protected:
void changeEvent(QEvent *e);
private slots:
void enableCodecs();
void disableCodecs();
void moveUp();
void moveDown();
private:
void readCodecs(void);
Ui::CodecWidget *ui;
QHash<QString, QList<QHash<QString, QString> > > _listCodecs;
};
#endif // CODECWIDGET_H

View File

@ -0,0 +1,157 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CodecWidget</class>
<widget class="QWidget" name="CodecWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>612</width>
<height>235</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Available Codecs</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="listAvailCodecs">
<property name="dragEnabled">
<bool>true</bool>
</property>
<property name="dragDropMode">
<enum>QAbstractItemView::DragDrop</enum>
</property>
<property name="defaultDropAction">
<enum>Qt::MoveAction</enum>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QToolButton" name="btnEnable">
<property name="text">
<string>...</string>
</property>
<property name="arrowType">
<enum>Qt::RightArrow</enum>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="btnDisable">
<property name="text">
<string>...</string>
</property>
<property name="arrowType">
<enum>Qt::LeftArrow</enum>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Enabled Codecs</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="listEnabledCodecs">
<property name="dragEnabled">
<bool>true</bool>
</property>
<property name="dragDropMode">
<enum>QAbstractItemView::DragDrop</enum>
</property>
<property name="defaultDropAction">
<enum>Qt::MoveAction</enum>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
<property name="sortingEnabled">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QToolButton" name="btnUp">
<property name="text">
<string>...</string>
</property>
<property name="arrowType">
<enum>Qt::UpArrow</enum>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="btnAdv">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="btnDown">
<property name="text">
<string>...</string>
</property>
<property name="arrowType">
<enum>Qt::DownArrow</enum>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

2139
libs/.gitignore vendored

File diff suppressed because it is too large Load Diff

View File

@ -72,7 +72,8 @@ $(SRC)/libteletone_detect.c \
$(SRC)/libteletone_generate.c \ $(SRC)/libteletone_generate.c \
$(SRC)/ftdm_buffer.c \ $(SRC)/ftdm_buffer.c \
$(SRC)/ftdm_threadmutex.c \ $(SRC)/ftdm_threadmutex.c \
$(SRC)/ftdm_dso.c $(SRC)/ftdm_dso.c \
$(SRC)/ftdm_cpu_monitor.c
library_include_HEADERS = \ library_include_HEADERS = \
$(SRC)/include/fsk.h \ $(SRC)/include/fsk.h \
@ -90,7 +91,8 @@ $(SRC)/include/ftdm_buffer.h \
$(SRC)/include/ftdm_config.h \ $(SRC)/include/ftdm_config.h \
$(SRC)/include/ftdm_threadmutex.h \ $(SRC)/include/ftdm_threadmutex.h \
$(SRC)/include/ftdm_dso.h \ $(SRC)/include/ftdm_dso.h \
$(SRC)/include/ftdm_types.h $(SRC)/include/ftdm_types.h \
$(SRC)/include/ftdm_cpu_monitor.h
lib_LTLIBRARIES = libfreetdm.la lib_LTLIBRARIES = libfreetdm.la
libfreetdm_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS) libfreetdm_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)

View File

@ -1382,6 +1382,15 @@ ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session
switch_set_flag(tech_pvt->caller_profile, SWITCH_CPF_SCREEN); switch_set_flag(tech_pvt->caller_profile, SWITCH_CPF_SCREEN);
} }
tech_pvt->caller_profile->caller_ton = sigmsg->channel->caller_data.cid_num.type;
tech_pvt->caller_profile->caller_numplan = sigmsg->channel->caller_data.cid_num.plan;
tech_pvt->caller_profile->ani_ton = sigmsg->channel->caller_data.ani.type;
tech_pvt->caller_profile->ani_numplan = sigmsg->channel->caller_data.ani.plan;
tech_pvt->caller_profile->destination_number_ton = sigmsg->channel->caller_data.dnis.type;
tech_pvt->caller_profile->destination_number_numplan = sigmsg->channel->caller_data.dnis.plan;
tech_pvt->caller_profile->rdnis_ton = sigmsg->channel->caller_data.rdnis.type;
tech_pvt->caller_profile->rdnis_numplan = sigmsg->channel->caller_data.rdnis.plan;
if (sigmsg->channel->caller_data.pres) { if (sigmsg->channel->caller_data.pres) {
switch_set_flag(tech_pvt->caller_profile, SWITCH_CPF_HIDE_NAME | SWITCH_CPF_HIDE_NUMBER); switch_set_flag(tech_pvt->caller_profile, SWITCH_CPF_HIDE_NAME | SWITCH_CPF_HIDE_NUMBER);
} }
@ -2767,6 +2776,8 @@ void dump_chan(ftdm_span_t *span, uint32_t chan_id, switch_stream_handle_t *stre
"type: %s\n" "type: %s\n"
"state: %s\n" "state: %s\n"
"last_state: %s\n" "last_state: %s\n"
"txgain: %3.2f\n"
"rxgain: %3.2f\n"
"cid_date: %s\n" "cid_date: %s\n"
"cid_name: %s\n" "cid_name: %s\n"
"cid_num: %s\n" "cid_num: %s\n"
@ -2782,6 +2793,8 @@ void dump_chan(ftdm_span_t *span, uint32_t chan_id, switch_stream_handle_t *stre
ftdm_chan_type2str(span->channels[chan_id]->type), ftdm_chan_type2str(span->channels[chan_id]->type),
ftdm_channel_state2str(span->channels[chan_id]->state), ftdm_channel_state2str(span->channels[chan_id]->state),
ftdm_channel_state2str(span->channels[chan_id]->last_state), ftdm_channel_state2str(span->channels[chan_id]->last_state),
span->channels[chan_id]->txgain,
span->channels[chan_id]->rxgain,
span->channels[chan_id]->caller_data.cid_date, span->channels[chan_id]->caller_data.cid_date,
span->channels[chan_id]->caller_data.cid_name, span->channels[chan_id]->caller_data.cid_name,
span->channels[chan_id]->caller_data.cid_num.digits, span->channels[chan_id]->caller_data.cid_num.digits,
@ -2808,6 +2821,8 @@ void dump_chan_xml(ftdm_span_t *span, uint32_t chan_id, switch_stream_handle_t *
" <type>%s</type>\n" " <type>%s</type>\n"
" <state>%s</state>\n" " <state>%s</state>\n"
" <last-state>%s</last-state>\n" " <last-state>%s</last-state>\n"
" <txgain>%3.2f</txgain>\n"
" <rxgain>%3.2f</rxgain>\n"
" <cid-date>%s</cid-date>\n" " <cid-date>%s</cid-date>\n"
" <cid-name>%s</cid-name>\n" " <cid-name>%s</cid-name>\n"
" <cid-num>%s</cid-num>\n" " <cid-num>%s</cid-num>\n"
@ -2824,6 +2839,8 @@ void dump_chan_xml(ftdm_span_t *span, uint32_t chan_id, switch_stream_handle_t *
ftdm_chan_type2str(span->channels[chan_id]->type), ftdm_chan_type2str(span->channels[chan_id]->type),
ftdm_channel_state2str(span->channels[chan_id]->state), ftdm_channel_state2str(span->channels[chan_id]->state),
ftdm_channel_state2str(span->channels[chan_id]->last_state), ftdm_channel_state2str(span->channels[chan_id]->last_state),
span->channels[chan_id]->txgain,
span->channels[chan_id]->rxgain,
span->channels[chan_id]->caller_data.cid_date, span->channels[chan_id]->caller_data.cid_date,
span->channels[chan_id]->caller_data.cid_name, span->channels[chan_id]->caller_data.cid_name,
span->channels[chan_id]->caller_data.cid_num.digits, span->channels[chan_id]->caller_data.cid_num.digits,
@ -2835,7 +2852,7 @@ void dump_chan_xml(ftdm_span_t *span, uint32_t chan_id, switch_stream_handle_t *
); );
} }
#define FT_SYNTAX "list || dump <span_id> [<chan_id>] || q931_pcap <span_id> on|off [pcapfilename without suffix] || gains <span> <txgain> <rxgain>" #define FT_SYNTAX "list || dump <span_id> [<chan_id>] || q931_pcap <span_id> on|off [pcapfilename without suffix] || gains <txgain> <rxgain> <span_id> [<chan_id>]"
SWITCH_STANDARD_API(ft_function) SWITCH_STANDARD_API(ft_function)
{ {
char *mycmd = NULL, *argv[10] = { 0 }; char *mycmd = NULL, *argv[10] = { 0 };
@ -3142,6 +3159,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_freetdm_load)
module_pool = pool; module_pool = pool;
ftdm_global_set_logger(ftdm_logger); ftdm_global_set_logger(ftdm_logger);
ftdm_cpu_monitor_disable();
if (ftdm_global_init() != FTDM_SUCCESS) { if (ftdm_global_init() != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_ERROR, "Error loading FreeTDM\n"); ftdm_log(FTDM_LOG_ERROR, "Error loading FreeTDM\n");

View File

@ -326,10 +326,34 @@
Filter="h;hpp;hxx;hm;inl;inc;xsd" Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
> >
<File
RelativePath="..\src\include\freetdm.h"
>
</File>
<File <File
RelativePath="..\src\include\fsk.h" RelativePath="..\src\include\fsk.h"
> >
</File> </File>
<File
RelativePath="..\src\include\ftdm_buffer.h"
>
</File>
<File
RelativePath="..\src\include\ftdm_config.h"
>
</File>
<File
RelativePath="..\src\include\ftdm_dso.h"
>
</File>
<File
RelativePath="..\src\include\ftdm_threadmutex.h"
>
</File>
<File
RelativePath="..\src\include\ftdm_types.h"
>
</File>
<File <File
RelativePath="..\src\include\g711.h" RelativePath="..\src\include\g711.h"
> >
@ -358,34 +382,10 @@
RelativePath="..\src\include\libteletone_generate.h" RelativePath="..\src\include\libteletone_generate.h"
> >
</File> </File>
<File
RelativePath="..\src\include\freetdm.h"
>
</File>
<File <File
RelativePath="..\src\include\uart.h" RelativePath="..\src\include\uart.h"
> >
</File> </File>
<File
RelativePath="..\src\include\ftdm_buffer.h"
>
</File>
<File
RelativePath="..\src\include\ftdm_config.h"
>
</File>
<File
RelativePath="..\src\include\ftdm_dso.h"
>
</File>
<File
RelativePath="..\src\include\ftdm_threadmutex.h"
>
</File>
<File
RelativePath="..\src\include\ftdm_types.h"
>
</File>
</Filter> </Filter>
<Filter <Filter
Name="Source Files" Name="Source Files"
@ -396,6 +396,38 @@
RelativePath="..\src\fsk.c" RelativePath="..\src\fsk.c"
> >
</File> </File>
<File
RelativePath="..\src\ftdm_buffer.c"
>
</File>
<File
RelativePath="..\src\ftdm_callerid.c"
>
</File>
<File
RelativePath="..\src\ftdm_config.c"
>
</File>
<File
RelativePath="..\src\ftdm_cpu_monitor.c"
>
</File>
<File
RelativePath="..\src\ftdm_dso.c"
>
</File>
<File
RelativePath="..\src\ftdm_io.c"
>
</File>
<File
RelativePath="..\src\ftdm_queue.c"
>
</File>
<File
RelativePath="..\src\ftdm_threadmutex.c"
>
</File>
<File <File
RelativePath="..\src\g711.c" RelativePath="..\src\g711.c"
> >
@ -420,34 +452,6 @@
RelativePath="..\src\uart.c" RelativePath="..\src\uart.c"
> >
</File> </File>
<File
RelativePath="..\src\ftdm_buffer.c"
>
</File>
<File
RelativePath="..\src\ftdm_callerid.c"
>
</File>
<File
RelativePath="..\src\ftdm_config.c"
>
</File>
<File
RelativePath="..\src\ftdm_dso.c"
>
</File>
<File
RelativePath="..\src\ftdm_io.c"
>
</File>
<File
RelativePath="..\src\ftdm_queue.c"
>
</File>
<File
RelativePath="..\src\ftdm_threadmutex.c"
>
</File>
</Filter> </Filter>
</Files> </Files>
<Globals> <Globals>

View File

@ -0,0 +1,274 @@
/*
* Copyright (c) 2010, Sangoma Technologies
* Moises Silva <moy@sangoma.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Contributors:
* David Yat Sin <dyatsin@sangoma.com>
*
*/
#ifdef WIN32
#define _WIN32_WINNT 0x0501 // To make GetSystemTimes visible in windows.h
#include <windows.h>
#else /* LINUX */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#endif
#include "freetdm.h"
#include "ftdm_cpu_monitor.h"
struct ftdm_cpu_monitor_stats
{
/* bool, just used to retrieve the values for the first time and not calculate the percentage of idle time */
int valid_last_times;
/* last calculated percentage of idle time */
double last_percentage_of_idle_time;
#ifdef __linux__
/* all of these are the Linux jiffies last retrieved count */
unsigned long long last_user_time;
unsigned long long last_system_time;
unsigned long long last_idle_time;
unsigned long long last_nice_time;
unsigned long long last_irq_time;
unsigned long long last_soft_irq_time;
unsigned long long last_io_wait_time;
unsigned long long last_steal_time;
/* /proc/stat file descriptor used to retrieve the counters */
int procfd;
int initd;
#elif defined (WIN32) || defined (WIN64)
__int64 i64LastUserTime;
__int64 i64LastKernelTime;
__int64 i64LastIdleTime;
#else
/* Unsupported */
#endif
};
#ifdef __linux__
static ftdm_status_t ftdm_cpu_read_stats(struct ftdm_cpu_monitor_stats *p,
unsigned long long *user,
unsigned long long *nice,
unsigned long long *system,
unsigned long long *idle,
unsigned long long *iowait,
unsigned long long *irq,
unsigned long long *softirq,
unsigned long long *steal)
{
// the output of proc should not change that often from one kernel to other
// see fs/proc/proc_misc.c or fs/proc/stat.c in the Linux kernel for more details
// also man 5 proc is useful
#define CPU_ELEMENTS 8 // change this if you change the format string
#define CPU_INFO_FORMAT "cpu %Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu"
static const char procfile[] = "/proc/stat";
int rc = 0;
int myerrno = 0;
int elements = 0;
const char *cpustr = NULL;
char statbuff[1024];
if (!p->initd) {
p->procfd = open(procfile, O_RDONLY, 0);
if(p->procfd == -1) {
ftdm_log(FTDM_LOG_ERROR, "Failed to open CPU statistics file %s: %s\n", procfile, strerror(myerrno));
return FTDM_FAIL;
}
p->initd = 1;
} else {
lseek(p->procfd, 0L, SEEK_SET);
}
rc = read(p->procfd, statbuff, sizeof(statbuff) - 1);
if (rc <= 0) {
myerrno = errno;
ftdm_log(FTDM_LOG_ERROR, "Failed to read CPU statistics file %s: %s\n", procfile, strerror(myerrno));
return FTDM_FAIL;
}
cpustr = strstr(statbuff, "cpu ");
if (!cpustr) {
ftdm_log(FTDM_LOG_ERROR, "wrong format for Linux proc cpu statistics: missing cpu string\n");
return FTDM_FAIL;
}
elements = sscanf(cpustr, CPU_INFO_FORMAT, user, nice, system, idle, iowait, irq, softirq, steal);
if (elements != CPU_ELEMENTS) {
ftdm_log(FTDM_LOG_ERROR, "wrong format for Linux proc cpu statistics: expected %d elements, but just found %d\n", CPU_ELEMENTS, elements);
return FTDM_FAIL;
}
return FTDM_SUCCESS;
}
#endif
#ifdef __linux__
FT_DECLARE(ftdm_status_t) ftdm_cpu_get_system_idle_time (struct ftdm_cpu_monitor_stats *p, double *idle_percentage)
{
unsigned long long user, nice, system, idle, iowait, irq, softirq, steal;
unsigned long long usertime, kerneltime, idletime, totaltime, halftime;
if (ftdm_cpu_read_stats(p, &user, &nice, &system, &idle, &iowait, &irq, &softirq, &steal)) {
ftdm_log(FTDM_LOG_ERROR, "Failed to retrieve Linux CPU statistics\n");
return FTDM_FAIL;
}
if (!p->valid_last_times) {
// we dont strictly need to save all of them but I feel code is more clear if we do
p->valid_last_times = 1;
p->last_user_time = user;
p->last_nice_time = nice;
p->last_system_time = system;
p->last_irq_time = irq;
p->last_soft_irq_time = softirq;
p->last_io_wait_time = iowait;
p->last_steal_time = steal;
p->last_idle_time = idle;
p->last_percentage_of_idle_time = 100.0;
*idle_percentage = p->last_percentage_of_idle_time;
return FTDM_SUCCESS;
}
usertime = (user - p->last_user_time) + (nice - p->last_nice_time);
kerneltime = (system - p->last_system_time) + (irq - p->last_irq_time) + (softirq - p->last_soft_irq_time);
kerneltime += (iowait - p->last_io_wait_time);
kerneltime += (steal - p->last_steal_time);
idletime = (idle - p->last_idle_time);
totaltime = usertime + kerneltime + idletime;
if (totaltime <= 0) {
// this may happen if not enough time has elapsed and the jiffies counters are the same than the last time we checked
// jiffies depend on timer interrupts which depend on the number of HZ compile time setting of the kernel
// typical configs set HZ to 100 (that means, 100 jiffies updates per second, that is one each 10ms)
// avoid an arithmetic exception and return the same values
*idle_percentage = p->last_percentage_of_idle_time;
return FTDM_SUCCESS;
}
halftime = totaltime / 2UL;
p->last_percentage_of_idle_time = ((100 * idletime + halftime) / totaltime);
*idle_percentage = p->last_percentage_of_idle_time;
p->last_user_time = user;
p->last_nice_time = nice;
p->last_system_time = system;
p->last_irq_time = irq;
p->last_soft_irq_time = softirq;
p->last_io_wait_time = iowait;
p->last_steal_time = steal;
p->last_idle_time = idle;
return FTDM_SUCCESS;
}
#elif defined (__WINDOWS__)
FT_DECLARE(ftdm_status_t) ftdm_cpu_get_system_idle_time(struct ftdm_cpu_monitor_stats *p, double *idle_percentage)
{
FILETIME idleTime;
FILETIME kernelTime;
FILETIME userTime;
int64_t i64UserTime;
int64_t i64KernelTime;
int64_t i64IdleTime;
if (!GetSystemTimes(&idleTime, &kernelTime, &userTime)) {
return FTDM_FAIL;
}
i64UserTime = (int64_t)userTime.dwLowDateTime | ((int64_t)userTime.dwHighDateTime << 32);
i64KernelTime = (int64_t)kernelTime.dwLowDateTime | ((int64_t)kernelTime.dwHighDateTime << 32);
i64IdleTime = (int64_t)idleTime.dwLowDateTime | ((int64_t)idleTime.dwHighDateTime << 32);
if (p->valid_last_times) {
int64_t i64User = i64UserTime - p->i64LastUserTime;
int64_t i64Kernel = i64KernelTime - p->i64LastKernelTime;
int64_t i64Idle = i64IdleTime - p->i64LastIdleTime;
int64_t i64System = i64User + i64Kernel;
*idle_percentage = 100.0 * i64Idle / i64System;
} else {
*idle_percentage = 100.0;
p->valid_last_times = 1;
}
/* Remember current value for the next call */
p->i64LastUserTime = i64UserTime;
p->i64LastKernelTime = i64KernelTime;
p->i64LastIdleTime = i64IdleTime;
/* Success */
return FTDM_SUCCESS;
}
#else
/* Unsupported */
FT_DECLARE(ftdm_status_t) ftdm_cpu_get_system_idle_time(struct ftdm_cpu_monitor_stats *p, double *idle_percentage)
{
return FTDM_FAIL;
}
#endif
FT_DECLARE(struct ftdm_cpu_monitor_stats*) ftdm_new_cpu_monitor(void)
{
return calloc(1, sizeof(struct ftdm_cpu_monitor_stats));
}
FT_DECLARE(void) ftdm_delete_cpu_monitor(struct ftdm_cpu_monitor_stats *p)
{
#ifdef __linux__
close(p->procfd);
#endif
free(p);
}
/* For Emacs:
* Local Variables:
* mode:c
* indent-tabs-mode:t
* tab-width:4
* c-basic-offset:4
* End:
* For VIM:
* vim:set softtabstop=4 shiftwidth=4 tabstop=4:
*/

View File

@ -48,6 +48,7 @@
#ifdef FTDM_PIKA_SUPPORT #ifdef FTDM_PIKA_SUPPORT
#include "ftdm_pika.h" #include "ftdm_pika.h"
#endif #endif
#include "ftdm_cpu_monitor.h"
#define SPAN_PENDING_CHANS_QUEUE_SIZE 1000 #define SPAN_PENDING_CHANS_QUEUE_SIZE 1000
@ -80,6 +81,16 @@ FT_DECLARE(ftdm_time_t) ftdm_current_time_in_ms(void)
#endif #endif
} }
typedef struct {
uint8_t running;
uint8_t alarm;
uint32_t interval;
uint8_t alarm_action_flags;
uint8_t set_alarm_threshold;
uint8_t reset_alarm_threshold;
ftdm_interrupt_t *interrupt;
} cpu_monitor_t;
static struct { static struct {
ftdm_hash_t *interface_hash; ftdm_hash_t *interface_hash;
ftdm_hash_t *module_hash; ftdm_hash_t *module_hash;
@ -93,8 +104,16 @@ static struct {
uint32_t running; uint32_t running;
ftdm_span_t *spans; ftdm_span_t *spans;
ftdm_group_t *groups; ftdm_group_t *groups;
cpu_monitor_t cpu_monitor;
} globals; } globals;
static uint8_t ftdm_cpu_monitor_disabled = 0;
enum ftdm_enum_cpu_alarm_action_flags
{
FTDM_CPU_ALARM_ACTION_WARN = (1 << 0),
FTDM_CPU_ALARM_ACTION_REJECT = (1 << 1)
};
/* enum lookup funcs */ /* enum lookup funcs */
FTDM_ENUM_NAMES(TONEMAP_NAMES, TONEMAP_STRINGS) FTDM_ENUM_NAMES(TONEMAP_NAMES, TONEMAP_STRINGS)
@ -412,7 +431,9 @@ static ftdm_status_t ftdm_span_destroy(ftdm_span_t *span)
} }
/* destroy final basic resources of the span data structure */ /* destroy final basic resources of the span data structure */
ftdm_queue_destroy(&span->pendingchans); if (span->pendingchans) {
ftdm_queue_destroy(&span->pendingchans);
}
ftdm_mutex_unlock(span->mutex); ftdm_mutex_unlock(span->mutex);
ftdm_mutex_destroy(&span->mutex); ftdm_mutex_destroy(&span->mutex);
ftdm_safe_free(span->signal_data); ftdm_safe_free(span->signal_data);
@ -518,9 +539,6 @@ FT_DECLARE(ftdm_status_t) ftdm_span_create(ftdm_io_interface_t *fio, ftdm_span_t
status = ftdm_mutex_create(&new_span->mutex); status = ftdm_mutex_create(&new_span->mutex);
ftdm_assert(status == FTDM_SUCCESS, "mutex creation failed\n"); ftdm_assert(status == FTDM_SUCCESS, "mutex creation failed\n");
status = ftdm_queue_create(&new_span->pendingchans, SPAN_PENDING_CHANS_QUEUE_SIZE);
ftdm_assert(status == FTDM_SUCCESS, "span chans queue creation failed\n");
ftdm_set_flag(new_span, FTDM_SPAN_CONFIGURED); ftdm_set_flag(new_span, FTDM_SPAN_CONFIGURED);
new_span->span_id = ++globals.span_index; new_span->span_id = ++globals.span_index;
new_span->fio = fio; new_span->fio = fio;
@ -642,10 +660,10 @@ FT_DECLARE(ftdm_status_t) ftdm_span_load_tones(ftdm_span_t *span, const char *ma
#define FTDM_SLINEAR_MAX_VALUE 32767 #define FTDM_SLINEAR_MAX_VALUE 32767
#define FTDM_SLINEAR_MIN_VALUE -32767 #define FTDM_SLINEAR_MIN_VALUE -32767
static void reset_gain_table(unsigned char *gain_table, float new_gain, ftdm_codec_t codec_gain) static void reset_gain_table(uint8_t *gain_table, float new_gain, ftdm_codec_t codec_gain)
{ {
/* sample value */ /* sample value */
unsigned char sv = 0; uint8_t sv = 0;
/* linear gain factor */ /* linear gain factor */
float lingain = 0; float lingain = 0;
/* linear value for each table sample */ /* linear value for each table sample */
@ -1163,7 +1181,9 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_set_state(ftdm_channel_t *ftdmchan, ftdm_
ftdm_mutex_lock(ftdmchan->span->mutex); ftdm_mutex_lock(ftdmchan->span->mutex);
ftdm_set_flag(ftdmchan->span, FTDM_SPAN_STATE_CHANGE); ftdm_set_flag(ftdmchan->span, FTDM_SPAN_STATE_CHANGE);
ftdm_queue_enqueue(ftdmchan->span->pendingchans, ftdmchan); if (ftdmchan->span->pendingchans) {
ftdm_queue_enqueue(ftdmchan->span->pendingchans, ftdmchan);
}
ftdm_mutex_unlock(ftdmchan->span->mutex); ftdm_mutex_unlock(ftdmchan->span->mutex);
ftdmchan->last_state = ftdmchan->state; ftdmchan->last_state = ftdmchan->state;
@ -1329,7 +1349,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_span(uint32_t span_id, ftdm_direc
return FTDM_FAIL; return FTDM_FAIL;
} }
if (span->channel_request && !span->suggest_chan_id) { if (span->channel_request && !ftdm_test_flag(span, FTDM_SPAN_SUGGEST_CHAN_ID)) {
ftdm_set_caller_data(span, caller_data); ftdm_set_caller_data(span, caller_data);
return span->channel_request(span, 0, direction, caller_data, ftdmchan); return span->channel_request(span, 0, direction, caller_data, ftdmchan);
} }
@ -1469,6 +1489,14 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_chan(ftdm_channel_t *ftdmchan)
snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", "Channel is alarmed\n"); snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", "Channel is alarmed\n");
return FTDM_FAIL; return FTDM_FAIL;
} }
if (globals.cpu_monitor.alarm &&
globals.cpu_monitor.alarm_action_flags & FTDM_CPU_ALARM_ACTION_REJECT) {
snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", "CPU usage alarm is on - refusing to open channel\n");
ftdm_log(FTDM_LOG_WARNING, "CPU usage alarm is on - refusing to open channel\n");
ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_SWITCH_CONGESTION;
return FTDM_FAIL;
}
if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_READY) || (status = ftdm_mutex_trylock(ftdmchan->mutex)) != FTDM_SUCCESS) { if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_READY) || (status = ftdm_mutex_trylock(ftdmchan->mutex)) != FTDM_SUCCESS) {
snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Channel is not ready or is in use %d %d", ftdm_test_flag(ftdmchan, FTDM_CHANNEL_READY), status); snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Channel is not ready or is in use %d %d", ftdm_test_flag(ftdmchan, FTDM_CHANNEL_READY), status);
@ -2006,7 +2034,6 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co
} }
break; break;
/* FIXME: validate user gain values */
case FTDM_COMMAND_SET_RX_GAIN: case FTDM_COMMAND_SET_RX_GAIN:
{ {
ftdmchan->rxgain = FTDM_COMMAND_OBJ_FLOAT; ftdmchan->rxgain = FTDM_COMMAND_OBJ_FLOAT;
@ -2016,11 +2043,13 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co
} else { } else {
ftdm_set_flag(ftdmchan, FTDM_CHANNEL_USE_RX_GAIN); ftdm_set_flag(ftdmchan, FTDM_CHANNEL_USE_RX_GAIN);
} }
GOTO_STATUS(done, FTDM_SUCCESS);
} }
break; break;
case FTDM_COMMAND_GET_RX_GAIN: case FTDM_COMMAND_GET_RX_GAIN:
{ {
FTDM_COMMAND_OBJ_FLOAT = ftdmchan->rxgain; FTDM_COMMAND_OBJ_FLOAT = ftdmchan->rxgain;
GOTO_STATUS(done, FTDM_SUCCESS);
} }
break; break;
case FTDM_COMMAND_SET_TX_GAIN: case FTDM_COMMAND_SET_TX_GAIN:
@ -2032,11 +2061,13 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co
} else { } else {
ftdm_set_flag(ftdmchan, FTDM_CHANNEL_USE_TX_GAIN); ftdm_set_flag(ftdmchan, FTDM_CHANNEL_USE_TX_GAIN);
} }
GOTO_STATUS(done, FTDM_SUCCESS);
} }
break; break;
case FTDM_COMMAND_GET_TX_GAIN: case FTDM_COMMAND_GET_TX_GAIN:
{ {
FTDM_COMMAND_OBJ_FLOAT = ftdmchan->txgain; FTDM_COMMAND_OBJ_FLOAT = ftdmchan->txgain;
GOTO_STATUS(done, FTDM_SUCCESS);
} }
break; break;
default: default:
@ -2049,7 +2080,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co
GOTO_STATUS(done, FTDM_FAIL); GOTO_STATUS(done, FTDM_FAIL);
} }
status = ftdmchan->fio->command(ftdmchan, command, obj); status = ftdmchan->fio->command(ftdmchan, command, obj);
if (status == FTDM_NOTIMPL) { if (status == FTDM_NOTIMPL) {
snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "I/O command %d not implemented in backend", command); snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "I/O command %d not implemented in backend", command);
@ -2798,6 +2829,24 @@ FT_DECLARE(char *) ftdm_api_execute(const char *type, const char *cmd)
return rval; return rval;
} }
static void ftdm_set_channels_gains(ftdm_span_t *span, int currindex, float rxgain, float txgain)
{
unsigned chan_index = 0;
if (!span->chan_count) {
return;
}
for (chan_index = currindex+1; chan_index <= span->chan_count; chan_index++) {
if (!FTDM_IS_VOICE_CHANNEL(span->channels[chan_index])) {
continue;
}
ftdm_channel_command(span->channels[chan_index], FTDM_COMMAND_SET_RX_GAIN, &rxgain);
ftdm_channel_command(span->channels[chan_index], FTDM_COMMAND_SET_TX_GAIN, &txgain);
}
}
static ftdm_status_t ftdm_group_add_channels(const char* name, ftdm_span_t* span, int currindex); static ftdm_status_t ftdm_group_add_channels(const char* name, ftdm_span_t* span, int currindex);
static ftdm_status_t load_config(void) static ftdm_status_t load_config(void)
@ -2806,6 +2855,7 @@ static ftdm_status_t load_config(void)
ftdm_config_t cfg; ftdm_config_t cfg;
char *var, *val; char *var, *val;
int catno = -1; int catno = -1;
int intparam = 0;
int currindex = 0; int currindex = 0;
ftdm_span_t *span = NULL; ftdm_span_t *span = NULL;
unsigned configured = 0, d = 0; unsigned configured = 0, d = 0;
@ -2814,6 +2864,8 @@ static ftdm_status_t load_config(void)
char group_name[80] = "default"; char group_name[80] = "default";
ftdm_io_interface_t *fio = NULL; ftdm_io_interface_t *fio = NULL;
ftdm_analog_start_type_t tmp; ftdm_analog_start_type_t tmp;
float rxgain = 0.0;
float txgain = 0.0;
ftdm_size_t len = 0; ftdm_size_t len = 0;
if (!ftdm_config_open_file(&cfg, cfg_name)) { if (!ftdm_config_open_file(&cfg, cfg_name)) {
@ -2921,6 +2973,7 @@ static ftdm_status_t load_config(void)
if (span->trunk_type == FTDM_TRUNK_FXO) { if (span->trunk_type == FTDM_TRUNK_FXO) {
currindex = span->chan_count; currindex = span->chan_count;
configured += fio->configure_span(span, val, FTDM_CHAN_TYPE_FXO, name, number); configured += fio->configure_span(span, val, FTDM_CHAN_TYPE_FXO, name, number);
ftdm_set_channels_gains(span, currindex, rxgain, txgain);
ftdm_group_add_channels(group_name, span, currindex); ftdm_group_add_channels(group_name, span, currindex);
} else { } else {
ftdm_log(FTDM_LOG_WARNING, "Cannot add FXO channels to an FXS trunk!\n"); ftdm_log(FTDM_LOG_WARNING, "Cannot add FXO channels to an FXS trunk!\n");
@ -2934,6 +2987,7 @@ static ftdm_status_t load_config(void)
if (span->trunk_type == FTDM_TRUNK_FXS) { if (span->trunk_type == FTDM_TRUNK_FXS) {
currindex = span->chan_count; currindex = span->chan_count;
configured += fio->configure_span(span, val, FTDM_CHAN_TYPE_FXS, name, number); configured += fio->configure_span(span, val, FTDM_CHAN_TYPE_FXS, name, number);
ftdm_set_channels_gains(span, currindex, rxgain, txgain);
ftdm_group_add_channels(group_name, span, currindex); ftdm_group_add_channels(group_name, span, currindex);
} else { } else {
ftdm_log(FTDM_LOG_WARNING, "Cannot add FXS channels to an FXO trunk!\n"); ftdm_log(FTDM_LOG_WARNING, "Cannot add FXS channels to an FXO trunk!\n");
@ -2947,6 +3001,7 @@ static ftdm_status_t load_config(void)
if (span->trunk_type == FTDM_TRUNK_EM) { if (span->trunk_type == FTDM_TRUNK_EM) {
currindex = span->chan_count; currindex = span->chan_count;
configured += fio->configure_span(span, val, FTDM_CHAN_TYPE_EM, name, number); configured += fio->configure_span(span, val, FTDM_CHAN_TYPE_EM, name, number);
ftdm_set_channels_gains(span, currindex, rxgain, txgain);
ftdm_group_add_channels(group_name, span, currindex); ftdm_group_add_channels(group_name, span, currindex);
} else { } else {
ftdm_log(FTDM_LOG_WARNING, "Cannot add EM channels to a non-EM trunk!\n"); ftdm_log(FTDM_LOG_WARNING, "Cannot add EM channels to a non-EM trunk!\n");
@ -2954,6 +3009,7 @@ static ftdm_status_t load_config(void)
} else if (!strcasecmp(var, "b-channel")) { } else if (!strcasecmp(var, "b-channel")) {
currindex = span->chan_count; currindex = span->chan_count;
configured += fio->configure_span(span, val, FTDM_CHAN_TYPE_B, name, number); configured += fio->configure_span(span, val, FTDM_CHAN_TYPE_B, name, number);
ftdm_set_channels_gains(span, currindex, rxgain, txgain);
ftdm_group_add_channels(group_name, span, currindex); ftdm_group_add_channels(group_name, span, currindex);
} else if (!strcasecmp(var, "d-channel")) { } else if (!strcasecmp(var, "d-channel")) {
if (d) { if (d) {
@ -2972,10 +3028,19 @@ static ftdm_status_t load_config(void)
} else if (!strcasecmp(var, "cas-channel")) { } else if (!strcasecmp(var, "cas-channel")) {
currindex = span->chan_count; currindex = span->chan_count;
configured += fio->configure_span(span, val, FTDM_CHAN_TYPE_CAS, name, number); configured += fio->configure_span(span, val, FTDM_CHAN_TYPE_CAS, name, number);
ftdm_set_channels_gains(span, currindex, rxgain, txgain);
ftdm_group_add_channels(group_name, span, currindex); ftdm_group_add_channels(group_name, span, currindex);
} else if (!strcasecmp(var, "dtmf_hangup")) { } else if (!strcasecmp(var, "dtmf_hangup")) {
span->dtmf_hangup = ftdm_strdup(val); span->dtmf_hangup = ftdm_strdup(val);
span->dtmf_hangup_len = strlen(val); span->dtmf_hangup_len = strlen(val);
} else if (!strcasecmp(var, "txgain")) {
if (sscanf(val, "%f", &txgain) != 1) {
ftdm_log(FTDM_LOG_ERROR, "invalid txgain: '%s'\n", val);
}
} else if (!strcasecmp(var, "rxgain")) {
if (sscanf(val, "%f", &rxgain) != 1) {
ftdm_log(FTDM_LOG_ERROR, "invalid rxgain: '%s'\n", val);
}
} else if (!strcasecmp(var, "group")) { } else if (!strcasecmp(var, "group")) {
len = strlen(val); len = strlen(val);
if (len >= sizeof(group_name)) { if (len >= sizeof(group_name)) {
@ -2987,6 +3052,46 @@ static ftdm_status_t load_config(void)
} else { } else {
ftdm_log(FTDM_LOG_ERROR, "unknown span variable '%s'\n", var); ftdm_log(FTDM_LOG_ERROR, "unknown span variable '%s'\n", var);
} }
} else if (!strncasecmp(cfg.category, "general", 7)) {
if (!strncasecmp(var, "cpu_monitoring_interval", sizeof("cpu_monitoring_interval")-1)) {
if (atoi(val) > 0) {
globals.cpu_monitor.interval = atoi(val);
} else {
ftdm_log(FTDM_LOG_ERROR, "Invalid cpu monitoring interval %s\n", val);
}
} else if (!strncasecmp(var, "cpu_set_alarm_threshold", sizeof("cpu_set_alarm_threshold")-1)) {
intparam = atoi(val);
if (intparam > 0 && intparam < 100) {
globals.cpu_monitor.set_alarm_threshold = (uint8_t)intparam;
} else {
ftdm_log(FTDM_LOG_ERROR, "Invalid cpu alarm set threshold %s\n", val);
}
} else if (!strncasecmp(var, "cpu_reset_alarm_threshold", sizeof("cpu_reset_alarm_threshold")-1)) {
intparam = atoi(val);
if (intparam > 0 && intparam < 100) {
globals.cpu_monitor.reset_alarm_threshold = (uint8_t)intparam;
if (globals.cpu_monitor.reset_alarm_threshold > globals.cpu_monitor.set_alarm_threshold) {
globals.cpu_monitor.reset_alarm_threshold = globals.cpu_monitor.set_alarm_threshold - 10;
ftdm_log(FTDM_LOG_ERROR, "Cpu alarm reset threshold must be lower than set threshold"
", setting threshold to %d\n", globals.cpu_monitor.reset_alarm_threshold);
}
} else {
ftdm_log(FTDM_LOG_ERROR, "Invalid cpu alarm reset threshold %s\n", val);
}
} else if (!strncasecmp(var, "cpu_alarm_action", sizeof("cpu_alarm_action")-1)) {
char* p = val;
do {
if (!strncasecmp(p, "reject", sizeof("reject")-1)) {
globals.cpu_monitor.alarm_action_flags |= FTDM_CPU_ALARM_ACTION_REJECT;
} else if (!strncasecmp(p, "warn", sizeof("warn")-1)) {
globals.cpu_monitor.alarm_action_flags |= FTDM_CPU_ALARM_ACTION_WARN;
}
p = strchr(p, ',');
if (p) {
while(*p++) if (*p != 0x20) break;
}
} while (p);
}
} else { } else {
ftdm_log(FTDM_LOG_ERROR, "unknown param [%s] '%s' / '%s'\n", cfg.category, var, val); ftdm_log(FTDM_LOG_ERROR, "unknown param [%s] '%s' / '%s'\n", cfg.category, var, val);
} }
@ -3266,6 +3371,9 @@ FT_DECLARE(ftdm_status_t) ftdm_configure_span(const char *type, ftdm_span_t *spa
va_list ap; va_list ap;
va_start(ap, sig_cb); va_start(ap, sig_cb);
status = mod->sig_configure(span, sig_cb, ap); status = mod->sig_configure(span, sig_cb, ap);
if (status == FTDM_SUCCESS && ftdm_test_flag(span, FTDM_SPAN_USE_CHAN_QUEUE)) {
status = ftdm_queue_create(&span->pendingchans, SPAN_PENDING_CHANS_QUEUE_SIZE);
}
va_end(ap); va_end(ap);
} else { } else {
ftdm_log(FTDM_LOG_ERROR, "can't find '%s'\n", type); ftdm_log(FTDM_LOG_ERROR, "can't find '%s'\n", type);
@ -3512,6 +3620,88 @@ FT_DECLARE(ftdm_status_t) ftdm_span_send_signal(ftdm_span_t *span, ftdm_sigmsg_t
return status; return status;
} }
static void *ftdm_cpu_monitor_run(ftdm_thread_t *me, void *obj)
{
cpu_monitor_t *monitor = (cpu_monitor_t *)obj;
struct ftdm_cpu_monitor_stats *cpu_stats = ftdm_new_cpu_monitor();
if (!cpu_stats) {
return NULL;
}
monitor->running = 1;
while(ftdm_running()) {
double time;
if (ftdm_cpu_get_system_idle_time(cpu_stats, &time)) {
break;
}
if (monitor->alarm) {
if ((int)time >= (100 - monitor->set_alarm_threshold)) {
ftdm_log(FTDM_LOG_DEBUG, "CPU alarm OFF (idle:%d)\n", (int) time);
monitor->alarm = 0;
}
if (monitor->alarm_action_flags & FTDM_CPU_ALARM_ACTION_WARN) {
ftdm_log(FTDM_LOG_WARNING, "CPU alarm is ON (cpu usage:%d)\n", (int) (100-time));
}
} else {
if ((int)time <= (100-monitor->reset_alarm_threshold)) {
ftdm_log(FTDM_LOG_DEBUG, "CPU alarm ON (idle:%d)\n", (int) time);
monitor->alarm = 1;
}
}
ftdm_interrupt_wait(monitor->interrupt, monitor->interval);
}
ftdm_delete_cpu_monitor(cpu_stats);
monitor->running = 0;
return NULL;
#ifdef __WINDOWS__
UNREFERENCED_PARAMETER(me);
#endif
}
static ftdm_status_t ftdm_cpu_monitor_start(void)
{
if (ftdm_interrupt_create(&globals.cpu_monitor.interrupt, FTDM_INVALID_SOCKET) != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_CRIT, "Failed to create CPU monitor interrupt\n");
return FTDM_FAIL;
}
if (ftdm_thread_create_detached(ftdm_cpu_monitor_run, &globals.cpu_monitor) != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_CRIT, "Failed to create cpu monitor thread!!\n");
return FTDM_FAIL;
}
return FTDM_SUCCESS;
}
static void ftdm_cpu_monitor_stop(void)
{
if (!globals.cpu_monitor.interrupt) {
return;
}
if (!globals.cpu_monitor.running) {
return;
}
if (ftdm_interrupt_signal(globals.cpu_monitor.interrupt) != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_CRIT, "Failed to interrupt the CPU monitor\n");
return;
}
while (globals.cpu_monitor.running) {
ftdm_sleep(10);
}
ftdm_interrupt_destroy(&globals.cpu_monitor.interrupt);
}
FT_DECLARE(void) ftdm_cpu_monitor_disable(void)
{
ftdm_cpu_monitor_disabled = 1;
}
FT_DECLARE(ftdm_status_t) ftdm_global_init(void) FT_DECLARE(ftdm_status_t) ftdm_global_init(void)
{ {
memset(&globals, 0, sizeof(globals)); memset(&globals, 0, sizeof(globals));
@ -3534,14 +3724,34 @@ FT_DECLARE(ftdm_status_t) ftdm_global_init(void)
FT_DECLARE(ftdm_status_t) ftdm_global_configuration(void) FT_DECLARE(ftdm_status_t) ftdm_global_configuration(void)
{ {
int modcount = ftdm_load_modules(); int modcount = 0;
if (!globals.running) {
return FTDM_FAIL;
}
modcount = ftdm_load_modules();
ftdm_log(FTDM_LOG_NOTICE, "Modules configured: %d \n", modcount); ftdm_log(FTDM_LOG_NOTICE, "Modules configured: %d \n", modcount);
globals.cpu_monitor.interval = 1000;
globals.cpu_monitor.alarm_action_flags = FTDM_CPU_ALARM_ACTION_WARN | FTDM_CPU_ALARM_ACTION_REJECT;
globals.cpu_monitor.set_alarm_threshold = 80;
globals.cpu_monitor.reset_alarm_threshold = 70;
if (load_config() != FTDM_SUCCESS) { if (load_config() != FTDM_SUCCESS) {
globals.running = 0; globals.running = 0;
ftdm_log(FTDM_LOG_ERROR, "FreeTDM global configuration failed!\n"); ftdm_log(FTDM_LOG_ERROR, "FreeTDM global configuration failed!\n");
return FTDM_FAIL; return FTDM_FAIL;
} }
if (!ftdm_cpu_monitor_disabled) {
if (ftdm_cpu_monitor_start() != FTDM_SUCCESS) {
return FTDM_FAIL;
}
}
return FTDM_SUCCESS; return FTDM_SUCCESS;
} }
@ -3559,6 +3769,8 @@ FT_DECLARE(ftdm_status_t) ftdm_global_destroy(void)
globals.running = 0; globals.running = 0;
ftdm_cpu_monitor_stop();
globals.span_index = 0; globals.span_index = 0;
ftdm_span_close_all(); ftdm_span_close_all();

View File

@ -258,8 +258,8 @@ FT_DECLARE(ftdm_status_t) ftdm_interrupt_create(ftdm_interrupt_t **ininterrupt,
interrupt->device = device; interrupt->device = device;
#ifdef WIN32 #ifdef WIN32
interrupt->interrupt = CreateEvent(NULL, FALSE, FALSE, NULL); interrupt->event = CreateEvent(NULL, FALSE, FALSE, NULL);
if (!interrupt->interrupt) { if (!interrupt->event) {
ftdm_log(FTDM_LOG_ERROR, "Failed to allocate interrupt event\n"); ftdm_log(FTDM_LOG_ERROR, "Failed to allocate interrupt event\n");
goto failed; goto failed;
} }
@ -314,7 +314,7 @@ FT_DECLARE(ftdm_status_t) ftdm_interrupt_wait(ftdm_interrupt_t *interrupt, int m
num++; num++;
ints[1] = interrupt->device; ints[1] = interrupt->device;
} }
res = WaitForMultipleObjects(num, &ints, FALSE, ms >= 0 ? ms : INFINITE); res = WaitForMultipleObjects(num, ints, FALSE, ms >= 0 ? ms : INFINITE);
switch (res) { switch (res) {
case WAIT_TIMEOUT: case WAIT_TIMEOUT:
return FTDM_TIMEOUT; return FTDM_TIMEOUT;
@ -366,7 +366,7 @@ FT_DECLARE(ftdm_status_t) ftdm_interrupt_signal(ftdm_interrupt_t *interrupt)
{ {
ftdm_assert_return(interrupt != NULL, FTDM_FAIL, "Interrupt is null!\n"); ftdm_assert_return(interrupt != NULL, FTDM_FAIL, "Interrupt is null!\n");
#ifdef WIN32 #ifdef WIN32
if (!SetEvent(interrupt->interrupt)) { if (!SetEvent(interrupt->event)) {
ftdm_log(FTDM_LOG_ERROR, "Failed to signal interrupt\n"); ftdm_log(FTDM_LOG_ERROR, "Failed to signal interrupt\n");
return FTDM_FAIL; return FTDM_FAIL;
} }
@ -386,7 +386,7 @@ FT_DECLARE(ftdm_status_t) ftdm_interrupt_destroy(ftdm_interrupt_t **ininterrupt)
ftdm_assert_return(ininterrupt != NULL, FTDM_FAIL, "Interrupt null when destroying!\n"); ftdm_assert_return(ininterrupt != NULL, FTDM_FAIL, "Interrupt null when destroying!\n");
interrupt = *ininterrupt; interrupt = *ininterrupt;
#ifdef WIN32 #ifdef WIN32
CloseHandle(interrupt->interrupt); CloseHandle(interrupt->event);
#else #else
close(interrupt->readfd); close(interrupt->readfd);
close(interrupt->writefd); close(interrupt->writefd);
@ -400,10 +400,42 @@ FT_DECLARE(ftdm_status_t) ftdm_interrupt_destroy(ftdm_interrupt_t **ininterrupt)
FT_DECLARE(ftdm_status_t) ftdm_interrupt_multiple_wait(ftdm_interrupt_t *interrupts[], ftdm_size_t size, int ms) FT_DECLARE(ftdm_status_t) ftdm_interrupt_multiple_wait(ftdm_interrupt_t *interrupts[], ftdm_size_t size, int ms)
{ {
#ifndef WIN32
int i;
int res = 0;
int numdevices = 0; int numdevices = 0;
unsigned i;
#if defined(__WINDOWS__)
DWORD res = 0;
HANDLE ints[20];
if (size > (ftdm_array_len(ints)/2)) {
/* improve if needed: dynamically allocate the list of interrupts *only* when exceeding the default size */
ftdm_log(FTDM_LOG_CRIT, "Unsupported size of interrupts: %d, implement me!\n", size);
return FTDM_FAIL;
}
for (i = 0; i < size; i++) {
ints[i] = interrupts[i]->event;
if (interrupts[i]->device != FTDM_INVALID_SOCKET) {
ints[i+numdevices] = interrupts[i]->device;
numdevices++;
}
}
res = WaitForMultipleObjects(size+numdevices, ints, FALSE, ms >= 0 ? ms : INFINITE);
switch (res) {
case WAIT_TIMEOUT:
return FTDM_TIMEOUT;
case WAIT_FAILED:
case WAIT_ABANDONED: /* is it right to fail with abandoned? */
return FTDM_FAIL;
default:
if (res >= (size+numdevices)) {
ftdm_log(FTDM_LOG_ERROR, "Error waiting for freetdm interrupt event (WaitForSingleObject returned %d)\n", res);
return FTDM_FAIL;
}
/* fall-through to FTDM_SUCCESS at the end of the function */
}
#elif defined(__linux__)
int res = 0;
char pipebuf[255]; char pipebuf[255];
struct pollfd ints[size*2]; struct pollfd ints[size*2];
@ -432,6 +464,7 @@ FT_DECLARE(ftdm_status_t) ftdm_interrupt_multiple_wait(ftdm_interrupt_t *interru
return FTDM_TIMEOUT; return FTDM_TIMEOUT;
} }
/* check for events in the pipes, NOT in the devices */
for (i = 0; i < size; i++) { for (i = 0; i < size; i++) {
if (ints[i].revents & POLLIN) { if (ints[i].revents & POLLIN) {
res = read(ints[i].fd, pipebuf, sizeof(pipebuf)); res = read(ints[i].fd, pipebuf, sizeof(pipebuf));
@ -440,7 +473,7 @@ FT_DECLARE(ftdm_status_t) ftdm_interrupt_multiple_wait(ftdm_interrupt_t *interru
} }
} }
} }
#else
#endif #endif
return FTDM_SUCCESS; return FTDM_SUCCESS;
} }

View File

@ -2385,7 +2385,7 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_isdn_configure_span)
if ((isdn_data->opts & FTDM_ISDN_OPT_SUGGEST_CHANNEL)) { if ((isdn_data->opts & FTDM_ISDN_OPT_SUGGEST_CHANNEL)) {
span->channel_request = isdn_channel_request; span->channel_request = isdn_channel_request;
span->suggest_chan_id = 1; ftdm_set_flag(span, FTDM_SPAN_SUGGEST_CHAN_ID);
} }
span->state_map = &isdn_state_map; span->state_map = &isdn_state_map;

View File

@ -1331,7 +1331,7 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_libpri_configure_span)
if ((isdn_data->opts & FTMOD_LIBPRI_OPT_SUGGEST_CHANNEL)) { if ((isdn_data->opts & FTMOD_LIBPRI_OPT_SUGGEST_CHANNEL)) {
span->channel_request = isdn_channel_request; span->channel_request = isdn_channel_request;
span->suggest_chan_id = 1; ftdm_set_flag(span, FTDM_SPAN_SUGGEST_CHAN_ID);
} }
span->state_map = &isdn_state_map; span->state_map = &isdn_state_map;

View File

@ -60,6 +60,9 @@ static time_t congestion_timeouts[MAX_TRUNK_GROUPS];
static ftdm_sangoma_boost_trunkgroup_t *g_trunkgroups[MAX_TRUNK_GROUPS]; static ftdm_sangoma_boost_trunkgroup_t *g_trunkgroups[MAX_TRUNK_GROUPS];
static ftdm_io_interface_t ftdm_sangoma_boost_interface;
static ftdm_status_t ftdm_sangoma_boost_list_sigmods(ftdm_stream_handle_t *stream);
#define BOOST_QUEUE_SIZE 500 #define BOOST_QUEUE_SIZE 500
/* get freetdm span and chan depending on the span mode */ /* get freetdm span and chan depending on the span mode */
@ -880,8 +883,8 @@ static __inline__ void advance_chan_states(ftdm_channel_t *ftdmchan);
*/ */
static void handle_call_start(ftdm_span_t *span, sangomabc_connection_t *mcon, sangomabc_event_t *event) static void handle_call_start(ftdm_span_t *span, sangomabc_connection_t *mcon, sangomabc_event_t *event)
{ {
ftdm_channel_t *ftdmchan; ftdm_channel_t *ftdmchan = NULL;
int hangup_cause = FTDM_CAUSE_CALL_REJECTED;
if (!(ftdmchan = find_ftdmchan(span, (sangomabc_short_event_t*)event, 0))) { if (!(ftdmchan = find_ftdmchan(span, (sangomabc_short_event_t*)event, 0))) {
if ((ftdmchan = find_ftdmchan(span, (sangomabc_short_event_t*)event, 1))) { if ((ftdmchan = find_ftdmchan(span, (sangomabc_short_event_t*)event, 1))) {
int r; int r;
@ -896,7 +899,7 @@ static void handle_call_start(ftdm_span_t *span, sangomabc_connection_t *mcon, s
} }
ftdm_set_sflag(ftdmchan, SFLAG_SENT_FINAL_MSG); ftdm_set_sflag(ftdmchan, SFLAG_SENT_FINAL_MSG);
ftdmchan=NULL; ftdmchan = NULL;
} }
ftdm_log(FTDM_LOG_CRIT, "START CANT FIND CHAN %d:%d\n", event->span+1,event->chan+1); ftdm_log(FTDM_LOG_CRIT, "START CANT FIND CHAN %d:%d\n", event->span+1,event->chan+1);
goto error; goto error;
@ -953,12 +956,13 @@ static void handle_call_start(ftdm_span_t *span, sangomabc_connection_t *mcon, s
return; return;
error: error:
hangup_cause = ftdmchan ? ftdmchan->caller_data.hangup_cause : FTDM_CAUSE_REQUESTED_CHAN_UNAVAIL;
sangomabc_exec_command(mcon, sangomabc_exec_command(mcon,
event->span, event->span,
event->chan, event->chan,
0, 0,
SIGBOOST_EVENT_CALL_START_NACK, SIGBOOST_EVENT_CALL_START_NACK,
0, 0); hangup_cause, 0);
} }
@ -1761,6 +1765,81 @@ end:
return NULL; return NULL;
} }
#define FTDM_BOOST_SYNTAX "list sigmods | <sigmod_name> <command>"
/**
* \brief API function to kill or debug a sangoma_boost span
* \param stream API stream handler
* \param data String containing argurments
* \return Flags
*/
static FIO_API_FUNCTION(ftdm_sangoma_boost_api)
{
char *mycmd = NULL, *argv[10] = { 0 };
int argc = 0;
if (data) {
mycmd = ftdm_strdup(data);
argc = ftdm_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
}
if (argc > 1) {
if (!strcasecmp(argv[0], "list")) {
if (!strcasecmp(argv[1], "sigmods")) {
if (ftdm_sangoma_boost_list_sigmods(stream) != FTDM_SUCCESS) {
stream->write_function(stream, "%s: -ERR failed to execute cmd\n", __FILE__);
goto done;
}
goto done;
}
} else {
boost_sigmod_interface_t *sigmod_iface = NULL;
sigmod_iface = hashtable_search(g_boost_modules_hash, argv[0]);
if (sigmod_iface) {
char *p = strchr(data, ' ');
if (++p) {
char* mydup = strdup(p);
if(sigmod_iface->exec_api == NULL) {
stream->write_function(stream, "%s does not support api functions\n", sigmod_iface->name);
goto done;
}
//stream->write_function(stream, "sigmod:%s command:%s\n", sigmod_iface->name, mydup);
if (sigmod_iface->exec_api(stream, mydup) != FTDM_SUCCESS) {
stream->write_function(stream, "-ERR:failed to execute command:%s\n", mydup);
}
free(mydup);
}
goto done;
} else {
stream->write_function(stream, "-ERR: Could not find sigmod %s\n", argv[0]);
}
}
}
stream->write_function(stream, "-ERR: Usage: %s\n", FTDM_BOOST_SYNTAX);
done:
ftdm_safe_free(mycmd);
return FTDM_SUCCESS;
}
/**
* \brief Loads sangoma_boost IO module
* \param fio FreeTDM IO interface
* \return Success
*/
static FIO_IO_LOAD_FUNCTION(ftdm_sangoma_boost_io_init)
{
assert(fio != NULL);
memset(&ftdm_sangoma_boost_interface, 0, sizeof(ftdm_sangoma_boost_interface));
ftdm_sangoma_boost_interface.name = "boost";
ftdm_sangoma_boost_interface.api = ftdm_sangoma_boost_api;
*fio = &ftdm_sangoma_boost_interface;
return FTDM_SUCCESS;
}
/** /**
* \brief Loads sangoma boost signaling module * \brief Loads sangoma boost signaling module
* \param fio FreeTDM IO interface * \param fio FreeTDM IO interface
@ -2239,7 +2318,8 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_boost_configure_span)
span->get_span_sig_status = sangoma_boost_get_span_sig_status; span->get_span_sig_status = sangoma_boost_get_span_sig_status;
span->set_span_sig_status = sangoma_boost_set_span_sig_status; span->set_span_sig_status = sangoma_boost_set_span_sig_status;
span->state_map = &boost_state_map; span->state_map = &boost_state_map;
span->suggest_chan_id = 0; ftdm_clear_flag(span, FTDM_SPAN_SUGGEST_CHAN_ID);
ftdm_set_flag(span, FTDM_SPAN_USE_CHAN_QUEUE);
if (sigmod_iface) { if (sigmod_iface) {
/* the core will do the hunting */ /* the core will do the hunting */
span->channel_request = NULL; span->channel_request = NULL;
@ -2248,12 +2328,31 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_boost_configure_span)
return FTDM_SUCCESS; return FTDM_SUCCESS;
} }
static ftdm_status_t ftdm_sangoma_boost_list_sigmods(ftdm_stream_handle_t *stream)
{
ftdm_hash_iterator_t *i = NULL;
boost_sigmod_interface_t *sigmod_iface = NULL;
const void *key = NULL;
void *val = NULL;
stream->write_function(stream, "List of loaded sigmod modules:\n");
for (i = hashtable_first(g_boost_modules_hash); i; i = hashtable_next(i)) {
hashtable_this(i, &key, NULL, &val);
if (key && val) {
sigmod_iface = val;
stream->write_function(stream, " %s\n", sigmod_iface->name);
}
}
stream->write_function(stream, "\n");
return FTDM_SUCCESS;
}
/** /**
* \brief FreeTDM sangoma boost signaling module definition * \brief FreeTDM sangoma boost signaling module definition
*/ */
EX_DECLARE_DATA ftdm_module_t ftdm_module = { EX_DECLARE_DATA ftdm_module_t ftdm_module = {
/*.name =*/ "sangoma_boost", /*.name =*/ "sangoma_boost",
/*.io_load =*/ NULL, /*.io_load =*/ ftdm_sangoma_boost_io_init,
/*.io_unload =*/ NULL, /*.io_unload =*/ NULL,
/*.sig_load = */ ftdm_sangoma_boost_init, /*.sig_load = */ ftdm_sangoma_boost_init,
/*.sig_configure =*/ NULL, /*.sig_configure =*/ NULL,

View File

@ -37,7 +37,6 @@
#include "freetdm.h" #include "freetdm.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -180,6 +179,15 @@ typedef ftdm_status_t (*boost_on_load_func_t) BOOST_ON_LOAD_ARGS;
typedef ftdm_status_t (*boost_on_unload_func_t) BOOST_ON_UNLOAD_ARGS; typedef ftdm_status_t (*boost_on_unload_func_t) BOOST_ON_UNLOAD_ARGS;
#define BOOST_ON_UNLOAD_FUNCTION(name) ftdm_status_t name BOOST_ON_UNLOAD_ARGS #define BOOST_ON_UNLOAD_FUNCTION(name) ftdm_status_t name BOOST_ON_UNLOAD_ARGS
/*!
\brief Called when user wants to execute sigmod api function
\return FTDM_SUCCESS or FTDM_FAIL
*/
#define BOOST_API_ARGS (ftdm_stream_handle_t *stream, char *cmd)
typedef ftdm_status_t (*boost_api_func_t) BOOST_API_ARGS;
#define BOOST_API_FUNCTION(name) ftdm_status_t name BOOST_API_ARGS
/*! /*!
\brief The boost signaling module interface \brief The boost signaling module interface
*/ */
@ -212,6 +220,8 @@ typedef struct boost_sigmod_interface_s {
boost_on_load_func_t on_load; boost_on_load_func_t on_load;
/*! \brief the module is about to be unloaded */ /*! \brief the module is about to be unloaded */
boost_on_unload_func_t on_unload; boost_on_unload_func_t on_unload;
/*! \brief module api function */
boost_api_func_t exec_api;
/*! \brief private pointer for the interface user */ /*! \brief private pointer for the interface user */
void *pvt; void *pvt;
} boost_sigmod_interface_t; } boost_sigmod_interface_t;

View File

@ -101,8 +101,6 @@ static struct {
FIO_SPAN_POLL_EVENT_FUNCTION(wanpipe_poll_event); FIO_SPAN_POLL_EVENT_FUNCTION(wanpipe_poll_event);
FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_next_event); FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_next_event);
#define WP_INVALID_SOCKET -1
/** /**
* \brief Poll for event on a wanpipe socket * \brief Poll for event on a wanpipe socket
* \param fd Wanpipe socket descriptor * \param fd Wanpipe socket descriptor
@ -224,7 +222,7 @@ static unsigned wp_open_range(ftdm_span_t *span, unsigned spanno, unsigned start
} }
for(x = start; x < end; x++) { for(x = start; x < end; x++) {
ftdm_channel_t *chan; ftdm_channel_t *chan;
ftdm_socket_t sockfd = WP_INVALID_SOCKET; ftdm_socket_t sockfd = FTDM_INVALID_SOCKET;
const char *dtmf = "none"; const char *dtmf = "none";
if (!strncasecmp(span->name, "smg_prid_nfas", 8) && span->trunk_type == FTDM_TRUNK_T1 && x == 24) { if (!strncasecmp(span->name, "smg_prid_nfas", 8) && span->trunk_type == FTDM_TRUNK_T1 && x == 24) {
#ifdef LIBSANGOMA_VERSION #ifdef LIBSANGOMA_VERSION
@ -236,7 +234,7 @@ static unsigned wp_open_range(ftdm_span_t *span, unsigned spanno, unsigned start
sockfd = tdmv_api_open_span_chan(spanno, x); sockfd = tdmv_api_open_span_chan(spanno, x);
} }
if (sockfd == WP_INVALID_SOCKET) { if (sockfd == FTDM_INVALID_SOCKET) {
ftdm_log(FTDM_LOG_ERROR, "Failed to open wanpipe device span %d channel %d\n", spanno, x); ftdm_log(FTDM_LOG_ERROR, "Failed to open wanpipe device span %d channel %d\n", spanno, x);
continue; continue;
} }
@ -1166,9 +1164,8 @@ static FIO_CHANNEL_DESTROY_FUNCTION(wanpipe_channel_destroy)
} }
#endif #endif
if (ftdmchan->sockfd > -1) { if (ftdmchan->sockfd != FTDM_INVALID_SOCKET) {
close(ftdmchan->sockfd); sangoma_close(&ftdmchan->sockfd);
ftdmchan->sockfd = WP_INVALID_SOCKET;
} }
return FTDM_SUCCESS; return FTDM_SUCCESS;

View File

@ -542,29 +542,39 @@ static FIO_CONFIGURE_FUNCTION(zt_configure)
} else if (!strcasecmp(var, "echo_cancel_level")) { } else if (!strcasecmp(var, "echo_cancel_level")) {
num = atoi(val); num = atoi(val);
if (num < 0 || num > 256) { if (num < 0 || num > 256) {
ftdm_log(FTDM_LOG_WARNING, "invalid echo can val at line %d\n", lineno); ftdm_log(FTDM_LOG_WARNING, "invalid echo can val at line %d\n", lineno);
} else { } else {
zt_globals.eclevel = num; zt_globals.eclevel = num;
} }
} else if (!strcasecmp(var, "echo_train_level")) {
if (zt_globals.eclevel < 1) {
ftdm_log(FTDM_LOG_WARNING, "can't set echo train level without setting echo cancel level first at line %d\n", lineno);
} else {
num = atoi(val);
if (num < 0 || num > 256) {
ftdm_log(FTDM_LOG_WARNING, "invalid echo train val at line %d\n", lineno);
} else {
zt_globals.etlevel = num;
}
}
} else if (!strcasecmp(var, "rxgain")) { } else if (!strcasecmp(var, "rxgain")) {
fnum = (float)atof(val); fnum = (float)atof(val);
if (fnum < -100.0 || fnum > 100.0) { if (fnum < -100.0 || fnum > 100.0) {
ftdm_log(FTDM_LOG_WARNING, "invalid rxgain val at line %d\n", lineno); ftdm_log(FTDM_LOG_WARNING, "invalid rxgain val at line %d\n", lineno);
} else { } else {
zt_globals.rxgain = fnum; zt_globals.rxgain = fnum;
ftdm_log(FTDM_LOG_INFO, "Setting rxgain val to %f\n", fnum); ftdm_log(FTDM_LOG_INFO, "Setting rxgain val to %f\n", fnum);
} }
} else if (!strcasecmp(var, "txgain")) { } else if (!strcasecmp(var, "txgain")) {
fnum = (float)atof(val); fnum = (float)atof(val);
if (fnum < -100.0 || fnum > 100.0) { if (fnum < -100.0 || fnum > 100.0) {
ftdm_log(FTDM_LOG_WARNING, "invalid txgain val at line %d\n", lineno); ftdm_log(FTDM_LOG_WARNING, "invalid txgain val at line %d\n", lineno);
} else { } else {
zt_globals.txgain = fnum; zt_globals.txgain = fnum;
ftdm_log(FTDM_LOG_INFO, "Setting txgain val to %f\n", fnum); ftdm_log(FTDM_LOG_INFO, "Setting txgain val to %f\n", fnum);
} }
} else {
ftdm_log(FTDM_LOG_WARNING, "Ignoring unknown setting '%s'\n", var);
} }
} }
@ -601,51 +611,41 @@ static FIO_OPEN_FUNCTION(zt_open)
ftdm_log(FTDM_LOG_ERROR, "%s\n", ftdmchan->last_error); ftdm_log(FTDM_LOG_ERROR, "%s\n", ftdmchan->last_error);
return FTDM_FAIL; return FTDM_FAIL;
} }
} else if (ftdmchan->type == FTDM_CHAN_TYPE_FXS || ftdmchan->type == FTDM_CHAN_TYPE_FXO || ftdmchan->type == FTDM_CHAN_TYPE_EM) {
int len = zt_globals.eclevel;
if (ioctl(ftdmchan->sockfd, codes.ECHOCANCEL, &len)) {
ftdm_log(FTDM_LOG_WARNING, "Echo cancel not available for %d:%d\n", ftdmchan->span_id, ftdmchan->chan_id);
//snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno));
//ftdm_log(FTDM_LOG_ERROR, "%s\n", ftdmchan->last_error);
//return FTDM_FAIL;
} else {
len = zt_globals.etlevel;
if (ioctl(ftdmchan->sockfd, codes.ECHOTRAIN, &len)) {
ftdm_log(FTDM_LOG_WARNING, "Echo training not available for %d:%d\n", ftdmchan->span_id, ftdmchan->chan_id);
//snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno));
//ftdm_log(FTDM_LOG_ERROR, "%s\n", ftdmchan->last_error);
//return FTDM_FAIL;
}
}
} }
if(zt_globals.rxgain || zt_globals.txgain) { if (zt_globals.rxgain || zt_globals.txgain) {
struct zt_gains gains; struct zt_gains gains;
memset(&gains, 0, sizeof(gains)); memset(&gains, 0, sizeof(gains));
gains.chan_no = ftdmchan->physical_chan_id; gains.chan_no = ftdmchan->physical_chan_id;
zt_build_gains(&gains, zt_globals.rxgain, zt_globals.txgain, ftdmchan->native_codec); zt_build_gains(&gains, zt_globals.rxgain, zt_globals.txgain, ftdmchan->native_codec);
if(zt_globals.rxgain) if (zt_globals.rxgain)
ftdm_log(FTDM_LOG_INFO, "Setting rxgain to %f on channel %d\n", zt_globals.rxgain, gains.chan_no); ftdm_log(FTDM_LOG_INFO, "Setting rxgain to %f on channel %d\n", zt_globals.rxgain, gains.chan_no);
if(zt_globals.txgain) if (zt_globals.txgain)
ftdm_log(FTDM_LOG_INFO, "Setting txgain to %f on channel %d\n", zt_globals.txgain, gains.chan_no); ftdm_log(FTDM_LOG_INFO, "Setting txgain to %f on channel %d\n", zt_globals.txgain, gains.chan_no);
if (ioctl(ftdmchan->sockfd, codes.SETGAINS, &gains) < 0) { if (ioctl(ftdmchan->sockfd, codes.SETGAINS, &gains) < 0) {
ftdm_log(FTDM_LOG_ERROR, "failure configuring device %s as FreeTDM device %d:%d fd:%d\n", chanpath, ftdmchan->span_id, ftdmchan->chan_id, ftdmchan->sockfd); ftdm_log(FTDM_LOG_ERROR, "failure configuring device %s as FreeTDM device %d:%d fd:%d\n", chanpath, ftdmchan->span_id, ftdmchan->chan_id, ftdmchan->sockfd);
} }
} }
int len = zt_globals.eclevel; if (zt_globals.eclevel >= 0) {
ftdm_log(FTDM_LOG_INFO, "Setting echo cancel to %d taps for %d:%d\n", len, ftdmchan->span_id, ftdmchan->chan_id); int len = zt_globals.eclevel;
if (ioctl(ftdmchan->sockfd, codes.ECHOCANCEL, &len)) { if (len) {
ftdm_log(FTDM_LOG_WARNING, "Echo cancel not available for %d:%d\n", ftdmchan->span_id, ftdmchan->chan_id); ftdm_log(FTDM_LOG_INFO, "Setting echo cancel to %d taps for %d:%d\n", len, ftdmchan->span_id, ftdmchan->chan_id);
} else { } else {
len = zt_globals.etlevel; ftdm_log(FTDM_LOG_INFO, "Disable echo cancel for %d:%d\n", ftdmchan->span_id, ftdmchan->chan_id);
if (ioctl(ftdmchan->sockfd, codes.ECHOTRAIN, &len)) { }
ftdm_log(FTDM_LOG_WARNING, "Echo training not available for %d:%d\n", ftdmchan->span_id, ftdmchan->chan_id); if (ioctl(ftdmchan->sockfd, codes.ECHOCANCEL, &len)) {
} ftdm_log(FTDM_LOG_WARNING, "Echo cancel not available for %d:%d\n", ftdmchan->span_id, ftdmchan->chan_id);
} } else if (zt_globals.etlevel >= 0) {
len = zt_globals.etlevel;
if (ioctl(ftdmchan->sockfd, codes.ECHOTRAIN, &len)) {
ftdm_log(FTDM_LOG_WARNING, "Echo training not available for %d:%d\n", ftdmchan->span_id, ftdmchan->chan_id);
}
}
}
} }
return FTDM_SUCCESS; return FTDM_SUCCESS;
@ -1179,7 +1179,7 @@ static FIO_IO_LOAD_FUNCTION(zt_init)
zt_globals.codec_ms = 20; zt_globals.codec_ms = 20;
zt_globals.wink_ms = 150; zt_globals.wink_ms = 150;
zt_globals.flash_ms = 750; zt_globals.flash_ms = 750;
zt_globals.eclevel = 64; zt_globals.eclevel = 0;
zt_globals.etlevel = 0; zt_globals.etlevel = 0;
zt_interface.name = "zt"; zt_interface.name = "zt";

View File

@ -605,8 +605,8 @@ struct ftdm_channel {
ftdm_hash_t *variable_hash; ftdm_hash_t *variable_hash;
unsigned char rx_cas_bits; unsigned char rx_cas_bits;
uint32_t pre_buffer_size; uint32_t pre_buffer_size;
unsigned char rxgain_table[FTDM_GAINS_TABLE_SIZE]; uint8_t rxgain_table[FTDM_GAINS_TABLE_SIZE];
unsigned char txgain_table[FTDM_GAINS_TABLE_SIZE]; uint8_t txgain_table[FTDM_GAINS_TABLE_SIZE];
float rxgain; float rxgain;
float txgain; float txgain;
}; };
@ -654,7 +654,6 @@ struct ftdm_span {
char *type; char *type;
char *dtmf_hangup; char *dtmf_hangup;
size_t dtmf_hangup_len; size_t dtmf_hangup_len;
int suggest_chan_id;
ftdm_state_map_t *state_map; ftdm_state_map_t *state_map;
ftdm_caller_data_t default_caller_data; ftdm_caller_data_t default_caller_data;
ftdm_queue_t *pendingchans; ftdm_queue_t *pendingchans;
@ -825,6 +824,7 @@ FT_DECLARE(ftdm_status_t) ftdm_span_find_by_name(const char *name, ftdm_span_t *
FT_DECLARE(char *) ftdm_api_execute(const char *type, const char *cmd); FT_DECLARE(char *) ftdm_api_execute(const char *type, const char *cmd);
FT_DECLARE(int) ftdm_vasprintf(char **ret, const char *fmt, va_list ap); FT_DECLARE(int) ftdm_vasprintf(char **ret, const char *fmt, va_list ap);
FT_DECLARE(ftdm_status_t) ftdm_channel_set_caller_data(ftdm_channel_t *ftdmchan, ftdm_caller_data_t *caller_data); FT_DECLARE(ftdm_status_t) ftdm_channel_set_caller_data(ftdm_channel_t *ftdmchan, ftdm_caller_data_t *caller_data);
FT_DECLARE(void) ftdm_cpu_monitor_disable(void);
FIO_CODEC_FUNCTION(fio_slin2ulaw); FIO_CODEC_FUNCTION(fio_slin2ulaw);
FIO_CODEC_FUNCTION(fio_ulaw2slin); FIO_CODEC_FUNCTION(fio_ulaw2slin);

View File

@ -0,0 +1,75 @@
/*
* Copyright (c) 2010, Sangoma Technologies
* Moises Silva <moy@sangoma.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
* Contributors:
* David Yat Sin <dyatsin@sangoma.com>
*
*/
/*! \brief opaque cpu stats structure */
struct ftdm_cpu_monitor_stats;
/*!
* \brief create a new cpu monitor
* \return profile timer structure previously created with new_profile_timer, NULL on error
*/
FT_DECLARE(struct ftdm_cpu_monitor_stats*) ftdm_new_cpu_monitor(void);
/*!
* \brief Deletes cpu_monitor
*/
FT_DECLARE(void) ftdm_delete_cpu_monitor(struct ftdm_cpu_monitor_stats *p);
/*!
* \brief provides the percentage of idle system time
* \param p cpu_stats structure previously created with ftdm_new_cpu_monitor
* \param pointer to store the percentage of idle time
* \return -1 on error 0 for success
*/
FT_DECLARE(ftdm_status_t) ftdm_cpu_get_system_idle_time (struct ftdm_cpu_monitor_stats *p, double *idle_percentage);
/* For Emacs:
* Local Variables:
* mode:c
* indent-tabs-mode:t
* tab-width:4
* c-basic-offset:4
* End:
* For VIM:
* vim:set softtabstop=4 shiftwidth=4 tabstop=4:
*/

View File

@ -40,8 +40,8 @@
#define FTDM_TYPES_H #define FTDM_TYPES_H
#include "fsk.h" #include "fsk.h"
#define FTDM_INVALID_SOCKET -1
#ifdef WIN32 #ifdef WIN32
#define FTDM_INVALID_SOCKET INVALID_HANDLE_VALUE
#include <windows.h> #include <windows.h>
typedef HANDLE ftdm_socket_t; typedef HANDLE ftdm_socket_t;
typedef unsigned __int64 uint64_t; typedef unsigned __int64 uint64_t;
@ -55,6 +55,7 @@ typedef __int8 int8_t;
typedef intptr_t ftdm_ssize_t; typedef intptr_t ftdm_ssize_t;
typedef int ftdm_filehandle_t; typedef int ftdm_filehandle_t;
#else #else
#define FTDM_INVALID_SOCKET -1
#include <stdint.h> #include <stdint.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
@ -325,7 +326,9 @@ typedef enum {
FTDM_SPAN_STATE_CHANGE = (1 << 2), FTDM_SPAN_STATE_CHANGE = (1 << 2),
FTDM_SPAN_SUSPENDED = (1 << 3), FTDM_SPAN_SUSPENDED = (1 << 3),
FTDM_SPAN_IN_THREAD = (1 << 4), FTDM_SPAN_IN_THREAD = (1 << 4),
FTDM_SPAN_STOP_THREAD = (1 << 5) FTDM_SPAN_STOP_THREAD = (1 << 5),
FTDM_SPAN_USE_CHAN_QUEUE = (1 << 6),
FTDM_SPAN_SUGGEST_CHAN_ID = (1 << 7),
} ftdm_span_flag_t; } ftdm_span_flag_t;
typedef enum { typedef enum {

View File

@ -43,8 +43,6 @@
#include "libsangoma.h" #include "libsangoma.h"
#if defined(__WINDOWS__) #if defined(__WINDOWS__)
/* remove this when http://jira.freeswitch.org/browse/FSBUILD-259 wanpipe issue is fixed */
#define WINDOWS_BUILD_BROKEN 1
/*! Backward compatible defines - current code is all using the old names*/ /*! Backward compatible defines - current code is all using the old names*/
#define sangoma_open_tdmapi_span_chan sangoma_open_api_span_chan #define sangoma_open_tdmapi_span_chan sangoma_open_api_span_chan
#define sangoma_open_tdmapi_span sangoma_open_api_span #define sangoma_open_tdmapi_span sangoma_open_api_span
@ -96,8 +94,6 @@ static struct {
ZIO_SPAN_POLL_EVENT_FUNCTION(wanpipe_poll_event); ZIO_SPAN_POLL_EVENT_FUNCTION(wanpipe_poll_event);
ZIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_next_event); ZIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_next_event);
#define WP_INVALID_SOCKET -1
/** /**
* \brief Poll for event on a wanpipe socket * \brief Poll for event on a wanpipe socket
* \param fd Wanpipe socket descriptor * \param fd Wanpipe socket descriptor
@ -219,7 +215,7 @@ static unsigned wp_open_range(zap_span_t *span, unsigned spanno, unsigned start,
} }
for(x = start; x < end; x++) { for(x = start; x < end; x++) {
zap_channel_t *chan; zap_channel_t *chan;
zap_socket_t sockfd = WP_INVALID_SOCKET; zap_socket_t sockfd = ZAP_INVALID_SOCKET;
const char *dtmf = "none"; const char *dtmf = "none";
if (!strncasecmp(span->name, "smg_prid_nfas", 8) && span->trunk_type == ZAP_TRUNK_T1 && x == 24) { if (!strncasecmp(span->name, "smg_prid_nfas", 8) && span->trunk_type == ZAP_TRUNK_T1 && x == 24) {
#ifdef LIBSANGOMA_VERSION #ifdef LIBSANGOMA_VERSION
@ -231,7 +227,7 @@ static unsigned wp_open_range(zap_span_t *span, unsigned spanno, unsigned start,
sockfd = tdmv_api_open_span_chan(spanno, x); sockfd = tdmv_api_open_span_chan(spanno, x);
} }
if (sockfd == WP_INVALID_SOCKET) { if (sockfd == ZAP_INVALID_SOCKET) {
zap_log(ZAP_LOG_ERROR, "Failed to open wanpipe device span %d channel %d\n", spanno, x); zap_log(ZAP_LOG_ERROR, "Failed to open wanpipe device span %d channel %d\n", spanno, x);
continue; continue;
} }
@ -587,29 +583,24 @@ static ZIO_COMMAND_FUNCTION(wanpipe_command)
break; break;
case ZAP_COMMAND_ENABLE_ECHOCANCEL: case ZAP_COMMAND_ENABLE_ECHOCANCEL:
{ {
#ifndef WINDOWS_BUILD_BROKEN
err=sangoma_tdm_enable_hwec(zchan->sockfd, &tdm_api); err=sangoma_tdm_enable_hwec(zchan->sockfd, &tdm_api);
if (err) { if (err) {
snprintf(zchan->last_error, sizeof(zchan->last_error), "HWEC Enable Failed"); snprintf(zchan->last_error, sizeof(zchan->last_error), "HWEC Enable Failed");
return ZAP_FAIL; return ZAP_FAIL;
} }
#endif /* WINDOWS_BUILD_BROKEN */
} }
break; break;
case ZAP_COMMAND_DISABLE_ECHOCANCEL: case ZAP_COMMAND_DISABLE_ECHOCANCEL:
{ {
#ifndef WINDOWS_BUILD_BROKEN
err=sangoma_tdm_disable_hwec(zchan->sockfd, &tdm_api); err=sangoma_tdm_disable_hwec(zchan->sockfd, &tdm_api);
if (err) { if (err) {
snprintf(zchan->last_error, sizeof(zchan->last_error), "HWEC Disable Failed"); snprintf(zchan->last_error, sizeof(zchan->last_error), "HWEC Disable Failed");
return ZAP_FAIL; return ZAP_FAIL;
} }
#endif /* WINDOWS_BUILD_BROKEN */
} }
break; break;
case ZAP_COMMAND_ENABLE_LOOP: case ZAP_COMMAND_ENABLE_LOOP:
{ {
#ifndef WINDOWS_BUILD_BROKEN
#ifdef WP_API_FEATURE_LOOP #ifdef WP_API_FEATURE_LOOP
err=sangoma_tdm_enable_loop(zchan->sockfd, &tdm_api); err=sangoma_tdm_enable_loop(zchan->sockfd, &tdm_api);
if (err) { if (err) {
@ -617,11 +608,9 @@ static ZIO_COMMAND_FUNCTION(wanpipe_command)
return ZAP_FAIL; return ZAP_FAIL;
} }
#endif #endif
#endif /* WINDOWS_BUILD_BROKEN */
} }
case ZAP_COMMAND_DISABLE_LOOP: case ZAP_COMMAND_DISABLE_LOOP:
{ {
#ifndef WINDOWS_BUILD_BROKEN
#ifdef WP_API_FEATURE_LOOP #ifdef WP_API_FEATURE_LOOP
err=sangoma_tdm_disable_loop(zchan->sockfd, &tdm_api); err=sangoma_tdm_disable_loop(zchan->sockfd, &tdm_api);
if (err) { if (err) {
@ -629,7 +618,6 @@ static ZIO_COMMAND_FUNCTION(wanpipe_command)
return ZAP_FAIL; return ZAP_FAIL;
} }
#endif #endif
#endif /* WINDOWS_BUILD_BROKEN */
} }
case ZAP_COMMAND_SET_INTERVAL: case ZAP_COMMAND_SET_INTERVAL:
{ {
@ -1163,9 +1151,8 @@ static ZIO_CHANNEL_DESTROY_FUNCTION(wanpipe_channel_destroy)
} }
#endif #endif
if (zchan->sockfd > -1) { if (zchan->sockfd != ZAP_INVALID_SOCKET) {
close(zchan->sockfd); sangoma_close(&zchan->sockfd);
zchan->sockfd = WP_INVALID_SOCKET;
} }
return ZAP_SUCCESS; return ZAP_SUCCESS;

View File

@ -425,7 +425,7 @@ OZ_DECLARE(zap_status_t) zap_interrupt_multiple_wait(zap_interrupt_t *interrupts
return ZAP_TIMEOUT; return ZAP_TIMEOUT;
} }
for (i = size; i < zap_array_len(ints); i++) { for (i = 0; i < size; i++) {
if (ints[i].revents & POLLIN) { if (ints[i].revents & POLLIN) {
res = read(ints[0].fd, pipebuf, sizeof(pipebuf)); res = read(ints[0].fd, pipebuf, sizeof(pipebuf));
if (res == -1) { if (res == -1) {

View File

@ -1,4 +1 @@
.svn .svn
.gitignore
.update
configure.gnu

8
scripts/check-gitignore.sh Executable file
View File

@ -0,0 +1,8 @@
#!/bin/bash
## files we might want to ignore
git ls-files -o --exclude-standard | sed -e "s:.:\/\\0:"
## files we are accidentally ignoring
git ls-files -i --exclude-standard | sed -e "s:.:\!\/\\0:"

View File

@ -8,6 +8,5 @@ my $socket = IO::Socket::Multicast->new( LocalPort => $port, ReuseAddr => 1 );
$socket->mcast_add($ip); $socket->mcast_add($ip);
while($socket->recv($data,1024)) { while($socket->recv($data,1024)) {
$data =~ s/^.{8}//;
print $data; print $data;
} }

View File

@ -13,5 +13,5 @@ $/ = undef;
my $buf = <I>; my $buf = <I>;
close(I); close(I);
$socket->send("00000000$buf\n"); $socket->send("$buf\n");

View File

@ -62,10 +62,11 @@ rm -f docs/COPYING
rm -f docs/ChangeLog rm -f docs/ChangeLog
rm -rf .git rm -rf .git
cd .. cd ..
tar -czvf $dst_name.tar.gz $dst_dir tar -cvf $dst_name.tar $dst_dir
tar -cjvf $dst_name.tar.bz2 $dst_dir gzip -9 -c $dst_name.tar > $dst_name.tar.gz || echo "gzip not available"
tar -cJvf $dst_name.tar.xz $dst_dir || echo tar does not support -J bzip2 -z -k $dst_name.tar || echo "bzip2 not available"
rm -rf $dst_dir xz -z -9 -k $dst_name.tar || echo "xz / xz-utils not available"
rm -rf $dst_name.tar $dst_dir
cat 1>&2 <<EOF cat 1>&2 <<EOF
---------------------------------------------------------------------- ----------------------------------------------------------------------

18
src/.gitignore vendored
View File

@ -1,9 +1,9 @@
Makefile /Makefile
Makefile.in /Makefile.in
include/stamp-h1 /include/stamp-h1
include/switch_am_config.h /include/switch_am_config.h
include/switch_private.h /include/switch_private.h
include/switch_private.h.in /include/switch_private.h.in
include/switch_swigable_cpp.h /include/switch_swigable_cpp.h
include/switch_version.h /include/switch_version.h
include/switch_version.h.in /include/switch_version.h.in

View File

@ -1213,6 +1213,7 @@ SWITCH_DECLARE(switch_status_t) switch_mcast_join(switch_socket_t *sock, switch_
*/ */
SWITCH_DECLARE(switch_status_t) switch_mcast_hops(switch_socket_t *sock, uint8_t ttl); SWITCH_DECLARE(switch_status_t) switch_mcast_hops(switch_socket_t *sock, uint8_t ttl);
SWITCH_DECLARE(switch_status_t) switch_mcast_loopback(switch_socket_t *sock, uint8_t opt);
/** @} */ /** @} */

View File

@ -246,9 +246,11 @@ SWITCH_DECLARE(const char *) switch_channel_get_variable_partner(switch_channel_
#define switch_channel_set_variable_partner(_channel, _var, _val) switch_channel_set_variable_partner_var_check(_channel, _var, _val, SWITCH_TRUE) #define switch_channel_set_variable_partner(_channel, _var, _val) switch_channel_set_variable_partner_var_check(_channel, _var, _val, SWITCH_TRUE)
SWITCH_DECLARE(switch_status_t) switch_channel_export_variable_var_check(switch_channel_t *channel, const char *varname, const char *value, switch_bool_t var_check, switch_bool_t nolocal); SWITCH_DECLARE(switch_status_t) switch_channel_export_variable_var_check(switch_channel_t *channel, const char *varname, const char *value, switch_bool_t var_check);
#define switch_channel_export_variable(_channel, _varname, _value) switch_channel_export_variable_var_check(_channel, _varname, _value, SWITCH_TRUE)
SWITCH_DECLARE(switch_status_t) switch_channel_export_variable_printf(switch_channel_t *channel, const char *varname, const char *fmt, ...);
#define switch_channel_export_variable(_channel, _varname, _value, _nolocal) switch_channel_export_variable_var_check(_channel, _varname, _value, SWITCH_TRUE, _nolocal)
/*! /*!
\brief Retrieve a variable from a given channel \brief Retrieve a variable from a given channel

118
src/mod/.gitignore vendored
View File

@ -1,59 +1,59 @@
Makefile /Makefile
Makefile.in /Makefile.in
applications/mod_commands/Makefile /applications/mod_commands/Makefile
applications/mod_conference/Makefile /applications/mod_conference/Makefile
applications/mod_dptools/Makefile /applications/mod_dptools/Makefile
applications/mod_enum/Makefile /applications/mod_enum/Makefile
applications/mod_enum/Makefile.in /applications/mod_enum/Makefile.in
applications/mod_enum/mod_enum.log /applications/mod_enum/mod_enum.log
applications/mod_expr/Makefile /applications/mod_expr/Makefile
applications/mod_expr/Makefile.in /applications/mod_expr/Makefile.in
applications/mod_expr/mod_expr.log /applications/mod_expr/mod_expr.log
applications/mod_fifo/Makefile /applications/mod_fifo/Makefile
applications/mod_fsv/Makefile /applications/mod_fsv/Makefile
applications/mod_limit/Makefile /applications/mod_limit/Makefile
applications/mod_stress/Makefile /applications/mod_stress/Makefile
applications/mod_stress/Makefile.in /applications/mod_stress/Makefile.in
applications/mod_t38gateway/Makefile /applications/mod_t38gateway/Makefile
applications/mod_t38gateway/Makefile.in /applications/mod_t38gateway/Makefile.in
applications/mod_valet_parking/Makefile /applications/mod_valet_parking/Makefile
applications/mod_voicemail/Makefile /applications/mod_voicemail/Makefile
asr_tts/mod_unimrcp/Makefile /asr_tts/mod_unimrcp/Makefile
asr_tts/mod_unimrcp/Makefile.in /asr_tts/mod_unimrcp/Makefile.in
dialplans/mod_dialplan_asterisk/Makefile /dialplans/mod_dialplan_asterisk/Makefile
dialplans/mod_dialplan_xml/Makefile /dialplans/mod_dialplan_xml/Makefile
endpoints/mod_portaudio/Makefile /endpoints/mod_portaudio/Makefile
endpoints/mod_portaudio/Makefile.in /endpoints/mod_portaudio/Makefile.in
endpoints/mod_skinny/Makefile /endpoints/mod_skinny/Makefile
endpoints/mod_skinny/Makefile.in /endpoints/mod_skinny/Makefile.in
endpoints/mod_skypopen/Makefile /endpoints/mod_skypopen/Makefile
endpoints/mod_skypopen/Makefile.in /endpoints/mod_skypopen/Makefile.in
endpoints/mod_sofia/Makefile /endpoints/mod_sofia/Makefile
endpoints/mod_sofia/Makefile.in /endpoints/mod_sofia/Makefile.in
endpoints/mod_sofia/mod_sofia.log /endpoints/mod_sofia/mod_sofia.log
event_handlers/mod_erlang_event/Makefile /event_handlers/mod_erlang_event/Makefile
event_handlers/mod_event_socket/Makefile /event_handlers/mod_event_socket/Makefile
formats/mod_native_file/Makefile /formats/mod_native_file/Makefile
formats/mod_portaudio_stream/Makefile /formats/mod_portaudio_stream/Makefile
formats/mod_portaudio_stream/Makefile.in /formats/mod_portaudio_stream/Makefile.in
formats/mod_tone_stream/Makefile /formats/mod_tone_stream/Makefile
languages/mod_java/Makefile /languages/mod_java/Makefile
languages/mod_lua/Makefile /languages/mod_lua/Makefile
languages/mod_lua/Makefile.in /languages/mod_lua/Makefile.in
languages/mod_lua/mod_lua.log /languages/mod_lua/mod_lua.log
languages/mod_python/Makefile /languages/mod_python/Makefile
languages/mod_spidermonkey/Makefile /languages/mod_spidermonkey/Makefile
languages/mod_spidermonkey/Makefile.in /languages/mod_spidermonkey/Makefile.in
languages/mod_spidermonkey/mod_spidermonkey.log /languages/mod_spidermonkey/mod_spidermonkey.log
loggers/mod_console/Makefile /loggers/mod_console/Makefile
loggers/mod_logfile/Makefile /loggers/mod_logfile/Makefile
loggers/mod_syslog/Makefile /loggers/mod_syslog/Makefile
say/mod_say_en/Makefile /say/mod_say_en/Makefile
say/mod_say_ru/Makefile /say/mod_say_ru/Makefile
applications/mod_stress/mod_stress.log /applications/mod_stress/mod_stress.log
asr_tts/mod_unimrcp/mod_unimrcp.log /asr_tts/mod_unimrcp/mod_unimrcp.log
endpoints/mod_portaudio/mod_portaudio.log /endpoints/mod_portaudio/mod_portaudio.log
endpoints/mod_skypopen/mod_skypopen.log /endpoints/mod_skypopen/mod_skypopen.log
formats/mod_portaudio_stream/mod_portaudio_stream.log /formats/mod_portaudio_stream/mod_portaudio_stream.log
languages/mod_java/freeswitch.jar /languages/mod_java/freeswitch.jar
languages/mod_managed/freeswitch_wrap.cpp /languages/mod_managed/freeswitch_wrap.cpp

View File

@ -25,7 +25,7 @@
* *
* Rupa Schomaker <rupa@rupa.com> * Rupa Schomaker <rupa@rupa.com>
* *
* mod_cidlookup.c -- API for querying cid->name services * mod_cidlookup.c -- API for querying cid->name services and local data
* *
*/ */

View File

@ -3231,6 +3231,8 @@ SWITCH_STANDARD_API(show_function)
char *command = NULL, *as = NULL; char *command = NULL, *as = NULL;
switch_core_flag_t cflags = switch_core_flags(); switch_core_flag_t cflags = switch_core_flags();
switch_status_t status = SWITCH_STATUS_SUCCESS; switch_status_t status = SWITCH_STATUS_SUCCESS;
char hostname[256] = "";
gethostname(hostname, sizeof(hostname));
if (switch_core_db_handle(&db) != SWITCH_STATUS_SUCCESS) { if (switch_core_db_handle(&db) != SWITCH_STATUS_SUCCESS) {
stream->write_function(stream, "%s", "-ERR Databse Error!\n"); stream->write_function(stream, "%s", "-ERR Databse Error!\n");
@ -3283,29 +3285,30 @@ SWITCH_STANDARD_API(show_function)
if (end_of(command) == 's') { if (end_of(command) == 's') {
end_of(command) = '\0'; end_of(command) = '\0';
} }
sprintf(sql, "select type, name, ikey from interfaces where type = '%s' order by type,name", command); sprintf(sql, "select type, name, ikey from interfaces where hostname='%s' and type = '%s' order by type,name", hostname, command);
} else if (!strncasecmp(command, "module", 6)) { } else if (!strncasecmp(command, "module", 6)) {
if (argv[1]) { if (argv[1]) {
sprintf(sql, "select distinct type, name, ikey, filename from interfaces where ikey = '%s' order by type,name", argv[1]); sprintf(sql, "select distinct type, name, ikey, filename from interfaces where hostname='%s' and ikey = '%s' order by type,name",
hostname, argv[1]);
} else { } else {
sprintf(sql, "select distinct type, name, ikey, filename from interfaces order by type,name"); sprintf(sql, "select distinct type, name, ikey, filename from interfaces where hostname='%s' order by type,name", hostname);
} }
} else if (!strcasecmp(command, "interfaces")) { } else if (!strcasecmp(command, "interfaces")) {
sprintf(sql, "select type, name, ikey from interfaces order by type,name"); sprintf(sql, "select type, name, ikey from interfaces where hostname='%s' order by type,name", hostname);
} else if (!strcasecmp(command, "interface_types")) { } else if (!strcasecmp(command, "interface_types")) {
sprintf(sql, "select type,count(type) as total from interfaces group by type order by type"); sprintf(sql, "select type,count(type) as total from interfaces where hostname='%s' group by type order by type", hostname);
} else if (!strcasecmp(command, "tasks")) { } else if (!strcasecmp(command, "tasks")) {
sprintf(sql, "select * from %s", command); sprintf(sql, "select * from %s where hostname='%s'", command, hostname);
} else if (!strcasecmp(command, "application") || !strcasecmp(command, "api")) { } else if (!strcasecmp(command, "application") || !strcasecmp(command, "api")) {
if (argv[1] && strcasecmp(argv[1], "as")) { if (argv[1] && strcasecmp(argv[1], "as")) {
sprintf(sql, sprintf(sql,
"select name, description, syntax, ikey from interfaces where type = '%s' and description != '' and name = '%s' order by type,name", "select name, description, syntax, ikey from interfaces where hostname='%s' and type = '%s' and description != '' and name = '%s' order by type,name",
command, argv[1]); hostname, command, argv[1]);
} else { } else {
sprintf(sql, "select name, description, syntax, ikey from interfaces where type = '%s' and description != '' order by type,name", command); sprintf(sql, "select name, description, syntax, ikey from interfaces where hostname='%s' and type = '%s' and description != '' order by type,name", hostname, command);
} }
} else if (!strcasecmp(command, "calls")) { } else if (!strcasecmp(command, "calls")) {
sprintf(sql, "select * from calls order by call_created_epoch"); sprintf(sql, "select * from calls where hostname='%s' order by call_created_epoch", hostname);
if (argv[1] && !strcasecmp(argv[1], "count")) { if (argv[1] && !strcasecmp(argv[1], "count")) {
holder.justcount = 1; holder.justcount = 1;
if (argv[3] && !strcasecmp(argv[2], "as")) { if (argv[3] && !strcasecmp(argv[2], "as")) {
@ -3322,12 +3325,12 @@ SWITCH_STANDARD_API(show_function)
} }
if (strchr(argv[2], '%')) { if (strchr(argv[2], '%')) {
sprintf(sql, sprintf(sql,
"select * from channels where uuid like '%s' or name like '%s' or cid_name like '%s' or cid_num like '%s' order by created_epoch", "select * from channels where hostname='%s' and uuid like '%s' or name like '%s' or cid_name like '%s' or cid_num like '%s' order by created_epoch",
argv[2], argv[2], argv[2], argv[2]); hostname, argv[2], argv[2], argv[2], argv[2]);
} else { } else {
sprintf(sql, sprintf(sql,
"select * from channels where uuid like '%%%s%%' or name like '%%%s%%' or cid_name like '%%%s%%' or cid_num like '%%%s%%' order by created_epoch", "select * from channels where hostname='%s' and uuid like '%%%s%%' or name like '%%%s%%' or cid_name like '%%%s%%' or cid_num like '%%%s%%' order by created_epoch",
argv[2], argv[2], argv[2], argv[2]); hostname, argv[2], argv[2], argv[2], argv[2]);
} }
@ -3335,10 +3338,10 @@ SWITCH_STANDARD_API(show_function)
as = argv[4]; as = argv[4];
} }
} else { } else {
sprintf(sql, "select * from channels order by created_epoch"); sprintf(sql, "select * from channels where hostname='%s' order by created_epoch", hostname);
} }
} else if (!strcasecmp(command, "channels")) { } else if (!strcasecmp(command, "channels")) {
sprintf(sql, "select * from channels order by created_epoch"); sprintf(sql, "select * from channels where hostname='%s' order by created_epoch", hostname);
if (argv[1] && !strcasecmp(argv[1], "count")) { if (argv[1] && !strcasecmp(argv[1], "count")) {
holder.justcount = 1; holder.justcount = 1;
if (argv[3] && !strcasecmp(argv[2], "as")) { if (argv[3] && !strcasecmp(argv[2], "as")) {
@ -3347,14 +3350,14 @@ SWITCH_STANDARD_API(show_function)
} }
} else if (!strcasecmp(command, "distinct_channels")) { } else if (!strcasecmp(command, "distinct_channels")) {
sprintf(sql, "select * from channels left join calls on " sprintf(sql, "select * from channels left join calls on "
"channels.uuid=calls.caller_uuid where channels.uuid not in (select callee_uuid from calls) order by created_epoch"); "channels.uuid=calls.caller_uuid where channels.hostname='%s' channels.uuid not in (select callee_uuid from calls where hostname='%s') order by created_epoch", hostname, hostname);
if (argv[2] && !strcasecmp(argv[1], "as")) { if (argv[2] && !strcasecmp(argv[1], "as")) {
as = argv[2]; as = argv[2];
} }
} else if (!strcasecmp(command, "aliases")) { } else if (!strcasecmp(command, "aliases")) {
sprintf(sql, "select * from aliases order by alias"); sprintf(sql, "select * from aliases where hostname='%s' order by alias", hostname);
} else if (!strcasecmp(command, "complete")) { } else if (!strcasecmp(command, "complete")) {
sprintf(sql, "select * from complete order by a1,a2,a3,a4,a5,a6,a7,a8,a9,a10"); sprintf(sql, "select * from complete where hostname='%s' order by a1,a2,a3,a4,a5,a6,a7,a8,a9,a10", hostname);
} else if (!strncasecmp(command, "help", 4)) { } else if (!strncasecmp(command, "help", 4)) {
char *cmdname = NULL; char *cmdname = NULL;
@ -3363,9 +3366,10 @@ SWITCH_STANDARD_API(show_function)
if ((cmdname = strchr(command, ' ')) && strcasecmp(cmdname, "as")) { if ((cmdname = strchr(command, ' ')) && strcasecmp(cmdname, "as")) {
*cmdname++ = '\0'; *cmdname++ = '\0';
switch_snprintf(sql, sizeof(sql) - 1, switch_snprintf(sql, sizeof(sql) - 1,
"select name, syntax, description, ikey from interfaces where type = 'api' and name = '%s' order by name", cmdname); "select name, syntax, description, ikey from interfaces where hostname='%s' and type = 'api' and name = '%s' order by name",
hostname, cmdname);
} else { } else {
switch_snprintf(sql, sizeof(sql) - 1, "select name, syntax, description, ikey from interfaces where type = 'api' order by name"); switch_snprintf(sql, sizeof(sql) - 1, "select name, syntax, description, ikey from interfaces where hostname='%s' and type = 'api' order by name", hostname);
} }
} else if (!strcasecmp(command, "nat_map")) { } else if (!strcasecmp(command, "nat_map")) {
switch_snprintf(sql, sizeof(sql) - 1, switch_snprintf(sql, sizeof(sql) - 1,
@ -3373,7 +3377,7 @@ SWITCH_STANDARD_API(show_function)
" CASE proto " " CASE proto "
" WHEN 0 THEN 'udp' " " WHEN 0 THEN 'udp' "
" WHEN 1 THEN 'tcp' " " WHEN 1 THEN 'tcp' "
" ELSE 'unknown' " " END AS proto, " " proto AS proto_num, " " sticky " " FROM nat ORDER BY port, proto"); " ELSE 'unknown' " " END AS proto, " " proto AS proto_num, " " sticky " " FROM nat where hostname='%s' ORDER BY port, proto", hostname);
} else { } else {
stream->write_function(stream, "-USAGE: %s\n", SHOW_SYNTAX); stream->write_function(stream, "-USAGE: %s\n", SHOW_SYNTAX);
goto end; goto end;

View File

@ -0,0 +1 @@
Makefile

View File

@ -0,0 +1 @@
Makefile

View File

@ -0,0 +1 @@
Makefile

View File

@ -0,0 +1 @@
Makefile

View File

@ -0,0 +1,2 @@
!/gsmlib/gsmlib-*/aclocal.m4
!/gsmlib/gsmlib-*/configure

View File

@ -2,6 +2,6 @@ include $(top_srcdir)/build/modmake.rulesam
MODNAME=mod_skypopen MODNAME=mod_skypopen
mod_LTLIBRARIES = mod_skypopen.la mod_LTLIBRARIES = mod_skypopen.la
mod_skypopen_la_SOURCES = mod_skypopen.c skypopen_protocol.c mod_skypopen_la_SOURCES = mod_skypopen.c skypopen_protocol.c
mod_skypopen_la_CFLAGS = $(AM_CFLAGS) -DSKYPOPEN_SVN_VERSION=\"`cat $(switch_builddir)/.version`\" -I../../../../libs/spandsp/src -I../../../..//libs/tiff-3.8.2/libtiff mod_skypopen_la_CFLAGS = $(AM_CFLAGS) -DSKYPOPEN_SVN_VERSION=\"`git describe`\" -I../../../../libs/spandsp/src -I../../../..//libs/tiff-3.8.2/libtiff
mod_skypopen_la_LIBADD = $(switch_builddir)/libfreeswitch.la mod_skypopen_la_LIBADD = $(switch_builddir)/libfreeswitch.la
mod_skypopen_la_LDFLAGS = -L../../../../libs/spandsp/src -avoid-version -module -no-undefined -shared -lX11 -lspandsp mod_skypopen_la_LDFLAGS = -L../../../../libs/spandsp/src -avoid-version -module -no-undefined -shared -lX11 -lspandsp

View File

@ -236,7 +236,7 @@ static void snd_card_dummy_pcm_timer_function(unsigned long data)
giovatimer.expires = 1 + jiffies; giovatimer.expires = 1 + jiffies;
add_timer(&giovatimer); add_timer(&giovatimer);
spin_lock_bh(&giovalock); //spin_lock_bh(&giovalock);
for (i = 0; i < giovaindex + 1; i++) { for (i = 0; i < giovaindex + 1; i++) {
if (i > MAX_PCM_SUBSTREAMS || giovaindex > MAX_PCM_SUBSTREAMS) { if (i > MAX_PCM_SUBSTREAMS || giovaindex > MAX_PCM_SUBSTREAMS) {
@ -262,7 +262,7 @@ static void snd_card_dummy_pcm_timer_function(unsigned long data)
//spin_unlock_bh(&dpcm->lock); //spin_unlock_bh(&dpcm->lock);
} }
} }
spin_unlock_bh(&giovalock); //spin_unlock_bh(&giovalock);
for (i = 0; i < giovaindex + 1; i++) { for (i = 0; i < giovaindex + 1; i++) {
if (i > MAX_PCM_SUBSTREAMS || giovaindex > MAX_PCM_SUBSTREAMS) { if (i > MAX_PCM_SUBSTREAMS || giovaindex > MAX_PCM_SUBSTREAMS) {
@ -774,7 +774,7 @@ static int __init alsa_card_dummy_init(void)
giovatimer.function = snd_card_dummy_pcm_timer_function; giovatimer.function = snd_card_dummy_pcm_timer_function;
giovatimer.expires = 1 + jiffies; giovatimer.expires = 1 + jiffies;
add_timer(&giovatimer); add_timer(&giovatimer);
printk("snd-dummy skypopen driver version: 5, %s:%d working on a machine with %dHZ kernel\n", __FILE__, __LINE__, HZ); printk("snd-dummy skypopen driver version: 6, %s:%d working on a machine with %dHZ kernel\n", __FILE__, __LINE__, HZ);
spin_unlock_bh(&giovalock); spin_unlock_bh(&giovalock);
} }

View File

@ -151,6 +151,7 @@ static struct {
char *report_incoming_chatmessages; char *report_incoming_chatmessages;
char *silent_mode; char *silent_mode;
char *write_silence_when_idle; char *write_silence_when_idle;
char *setsockopt;
int calls; int calls;
int real_interfaces; int real_interfaces;
int next_interface; int next_interface;
@ -171,6 +172,7 @@ SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_skype_user, globals.skype_user);
SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_report_incoming_chatmessages, globals.report_incoming_chatmessages); SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_report_incoming_chatmessages, globals.report_incoming_chatmessages);
SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_silent_mode, globals.silent_mode); SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_silent_mode, globals.silent_mode);
SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_write_silence_when_idle, globals.write_silence_when_idle); SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_write_silence_when_idle, globals.write_silence_when_idle);
SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_setsockopt, globals.setsockopt);
static switch_status_t interface_exists(char *the_interface); static switch_status_t interface_exists(char *the_interface);
static switch_status_t remove_interface(char *the_interface); static switch_status_t remove_interface(char *the_interface);
@ -1241,6 +1243,9 @@ static switch_status_t load_config(int reload_type)
} else if (!strcmp(var, "write_silence_when_idle")) { } else if (!strcmp(var, "write_silence_when_idle")) {
set_global_write_silence_when_idle(val); set_global_write_silence_when_idle(val);
DEBUGA_SKYPE("globals.write_silence_when_idle=%s\n", SKYPOPEN_P_LOG, globals.write_silence_when_idle); DEBUGA_SKYPE("globals.write_silence_when_idle=%s\n", SKYPOPEN_P_LOG, globals.write_silence_when_idle);
} else if (!strcmp(var, "setsockopt")) {
set_global_setsockopt(val);
DEBUGA_SKYPE("globals.setsockopt=%s\n", SKYPOPEN_P_LOG, globals.setsockopt);
} }
} }
@ -1261,6 +1266,7 @@ static switch_status_t load_config(int reload_type)
char *report_incoming_chatmessages = "true"; char *report_incoming_chatmessages = "true";
char *silent_mode = "false"; char *silent_mode = "false";
char *write_silence_when_idle = "true"; char *write_silence_when_idle = "true";
char *setsockopt = "false";
uint32_t interface_id = 0; uint32_t interface_id = 0;
if(globals.context) if(globals.context)
@ -1277,6 +1283,8 @@ static switch_status_t load_config(int reload_type)
silent_mode=globals.silent_mode; silent_mode=globals.silent_mode;
if(globals.write_silence_when_idle) if(globals.write_silence_when_idle)
write_silence_when_idle=globals.write_silence_when_idle; write_silence_when_idle=globals.write_silence_when_idle;
if(globals.setsockopt)
setsockopt=globals.setsockopt;
tech_pvt = NULL; tech_pvt = NULL;
@ -1298,6 +1306,8 @@ static switch_status_t load_config(int reload_type)
silent_mode = val; silent_mode = val;
} else if (!strcasecmp(var, "write_silence_when_idle")) { } else if (!strcasecmp(var, "write_silence_when_idle")) {
write_silence_when_idle = val; write_silence_when_idle = val;
} else if (!strcasecmp(var, "setsockopt")) {
setsockopt = val;
} else if (!strcasecmp(var, "X11-display") || !strcasecmp(var, "X11_display")) { } else if (!strcasecmp(var, "X11-display") || !strcasecmp(var, "X11_display")) {
X11_display = val; X11_display = val;
} }
@ -1397,6 +1407,13 @@ static switch_status_t load_config(int reload_type)
} }
if (!strcmp(setsockopt, "true") || !strcmp(setsockopt, "1")) {
globals.SKYPOPEN_INTERFACES[interface_id].setsockopt = 1;
} else {
globals.SKYPOPEN_INTERFACES[interface_id].setsockopt = 0; //redundant, just in case
}
DEBUGA_SKYPE("interface_id=%d globals.SKYPOPEN_INTERFACES[interface_id].name=%s\n", DEBUGA_SKYPE("interface_id=%d globals.SKYPOPEN_INTERFACES[interface_id].name=%s\n",
SKYPOPEN_P_LOG, interface_id, globals.SKYPOPEN_INTERFACES[interface_id].name); SKYPOPEN_P_LOG, interface_id, globals.SKYPOPEN_INTERFACES[interface_id].name);
DEBUGA_SKYPE DEBUGA_SKYPE
@ -1423,6 +1440,9 @@ static switch_status_t load_config(int reload_type)
DEBUGA_SKYPE DEBUGA_SKYPE
("interface_id=%d globals.SKYPOPEN_INTERFACES[interface_id].write_silence_when_idle=%d\n", ("interface_id=%d globals.SKYPOPEN_INTERFACES[interface_id].write_silence_when_idle=%d\n",
SKYPOPEN_P_LOG, interface_id, globals.SKYPOPEN_INTERFACES[interface_id].write_silence_when_idle); SKYPOPEN_P_LOG, interface_id, globals.SKYPOPEN_INTERFACES[interface_id].write_silence_when_idle);
DEBUGA_SKYPE
("interface_id=%d globals.SKYPOPEN_INTERFACES[interface_id].setsockopt=%d\n",
SKYPOPEN_P_LOG, interface_id, globals.SKYPOPEN_INTERFACES[interface_id].setsockopt);
WARNINGA("STARTING interface_id=%d\n", SKYPOPEN_P_LOG, interface_id); WARNINGA("STARTING interface_id=%d\n", SKYPOPEN_P_LOG, interface_id);
@ -1532,6 +1552,7 @@ static switch_status_t load_config(int reload_type)
globals.SKYPOPEN_INTERFACES[i].report_incoming_chatmessages); globals.SKYPOPEN_INTERFACES[i].report_incoming_chatmessages);
DEBUGA_SKYPE("i=%d globals.SKYPOPEN_INTERFACES[%d].silent_mode=%d\n", SKYPOPEN_P_LOG, i, i, globals.SKYPOPEN_INTERFACES[i].silent_mode); DEBUGA_SKYPE("i=%d globals.SKYPOPEN_INTERFACES[%d].silent_mode=%d\n", SKYPOPEN_P_LOG, i, i, globals.SKYPOPEN_INTERFACES[i].silent_mode);
DEBUGA_SKYPE("i=%d globals.SKYPOPEN_INTERFACES[%d].write_silence_when_idle=%d\n", SKYPOPEN_P_LOG, i, i, globals.SKYPOPEN_INTERFACES[i].write_silence_when_idle); DEBUGA_SKYPE("i=%d globals.SKYPOPEN_INTERFACES[%d].write_silence_when_idle=%d\n", SKYPOPEN_P_LOG, i, i, globals.SKYPOPEN_INTERFACES[i].write_silence_when_idle);
DEBUGA_SKYPE("i=%d globals.SKYPOPEN_INTERFACES[%d].setsockopt=%d\n", SKYPOPEN_P_LOG, i, i, globals.SKYPOPEN_INTERFACES[i].setsockopt);
} }
} }
} }
@ -1775,6 +1796,7 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_skypopen_shutdown)
switch_safe_free(globals.report_incoming_chatmessages); switch_safe_free(globals.report_incoming_chatmessages);
switch_safe_free(globals.silent_mode); switch_safe_free(globals.silent_mode);
switch_safe_free(globals.write_silence_when_idle); switch_safe_free(globals.write_silence_when_idle);
switch_safe_free(globals.setsockopt);
return SWITCH_STATUS_SUCCESS; return SWITCH_STATUS_SUCCESS;
} }

View File

@ -287,6 +287,7 @@ struct private_object {
switch_buffer_t *read_buffer; switch_buffer_t *read_buffer;
int silent_mode; int silent_mode;
int write_silence_when_idle; int write_silence_when_idle;
int setsockopt;
}; };

View File

@ -103,7 +103,9 @@ int skypopen_socket_create_and_bind(private_t * tech_pvt, unsigned short *which_
sockbufsize = SAMPLES_PER_FRAME * 8; sockbufsize = SAMPLES_PER_FRAME * 8;
#endif //WIN32 #endif //WIN32
size = sizeof(int); size = sizeof(int);
setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *) &sockbufsize, size); if(tech_pvt->setsockopt){
setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *) &sockbufsize, size);
}
sockbufsize = 0; sockbufsize = 0;
size = sizeof(int); size = sizeof(int);
@ -120,7 +122,9 @@ int skypopen_socket_create_and_bind(private_t * tech_pvt, unsigned short *which_
sockbufsize = SAMPLES_PER_FRAME * 8; sockbufsize = SAMPLES_PER_FRAME * 8;
#endif //WIN32 #endif //WIN32
size = sizeof(int); size = sizeof(int);
setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *) &sockbufsize, size); if(tech_pvt->setsockopt){
setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *) &sockbufsize, size);
}
sockbufsize = 0; sockbufsize = 0;
size = sizeof(int); size = sizeof(int);
@ -131,7 +135,9 @@ int skypopen_socket_create_and_bind(private_t * tech_pvt, unsigned short *which_
getsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, &size); getsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, &size);
DEBUGA_SKYPE("TCP_NODELAY is %d\n", SKYPOPEN_P_LOG, flag); DEBUGA_SKYPE("TCP_NODELAY is %d\n", SKYPOPEN_P_LOG, flag);
flag = 1; flag = 1;
setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, size); if(tech_pvt->setsockopt){
setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, size);
}
flag = 0; flag = 0;
getsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, &size); getsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, &size);
DEBUGA_SKYPE("TCP_NODELAY is %d\n", SKYPOPEN_P_LOG, flag); DEBUGA_SKYPE("TCP_NODELAY is %d\n", SKYPOPEN_P_LOG, flag);
@ -1563,6 +1569,7 @@ void *skypopen_do_skypeapi_thread_func(void *obj)
Window root = -1; Window root = -1;
Window win = -1; Window win = -1;
int xfd; int xfd;
fd_set xfds;
if (!strlen(tech_pvt->X11_display)) if (!strlen(tech_pvt->X11_display))
strcpy(tech_pvt->X11_display, getenv("DISPLAY")); strcpy(tech_pvt->X11_display, getenv("DISPLAY"));
@ -1623,6 +1630,7 @@ void *skypopen_do_skypeapi_thread_func(void *obj)
int i; int i;
int continue_is_broken = 0; int continue_is_broken = 0;
int there_were_continues = 0; int there_were_continues = 0;
struct timeval tv;
Atom atom_begin = XInternAtom(disp, "SKYPECONTROLAPI_MESSAGE_BEGIN", False); Atom atom_begin = XInternAtom(disp, "SKYPECONTROLAPI_MESSAGE_BEGIN", False);
Atom atom_continue = XInternAtom(disp, "SKYPECONTROLAPI_MESSAGE", False); Atom atom_continue = XInternAtom(disp, "SKYPECONTROLAPI_MESSAGE", False);
@ -1631,6 +1639,22 @@ void *skypopen_do_skypeapi_thread_func(void *obj)
b = buffer; b = buffer;
while (running && tech_pvt->running) { while (running && tech_pvt->running) {
FD_ZERO(&xfds);
FD_SET(xfd, &xfds);
tv.tv_usec = 100000;
tv.tv_sec = 0;
if (select(xfd+1, &xfds, 0, 0, &tv)){
while(XPending(disp)){
XNextEvent(disp, &an_event); XNextEvent(disp, &an_event);
if (!(running && tech_pvt->running)) if (!(running && tech_pvt->running))
break; break;
@ -1664,7 +1688,7 @@ void *skypopen_do_skypeapi_thread_func(void *obj)
} }
if (an_event.xclient.message_type == atom_continue) { if (an_event.xclient.message_type == atom_continue) {
if (!strlen(buffer)) { if (!strlen(buffer)) {
DEBUGA_SKYPE WARNINGA
("Got a 'continue' XAtom without a previous 'begin'. It's value (between vertical bars) is=|||%s|||, let's store it and hope next 'begin' will be the good one\n", ("Got a 'continue' XAtom without a previous 'begin'. It's value (between vertical bars) is=|||%s|||, let's store it and hope next 'begin' will be the good one\n",
SKYPOPEN_P_LOG, buf); SKYPOPEN_P_LOG, buf);
strcat(continuebuffer, buf); strcat(continuebuffer, buf);
@ -1703,8 +1727,16 @@ void *skypopen_do_skypeapi_thread_func(void *obj)
default: default:
skypopen_sleep(1000); //0.1 msec skypopen_sleep(1000); //0.1 msec
break; break;
} } //switch event.type
} } //while XPending
} // if select
} //while running
} }
} else { } else {
ERRORA("Skype is not running, maybe crashed. Please run/restart Skype and relaunch Skypopen\n", SKYPOPEN_P_LOG); ERRORA("Skype is not running, maybe crashed. Please run/restart Skype and relaunch Skypopen\n", SKYPOPEN_P_LOG);

View File

@ -52,7 +52,6 @@ static struct {
char *bindings; char *bindings;
uint32_t key_count; uint32_t key_count;
char hostname[80]; char hostname[80];
uint64_t host_hash;
switch_port_t port; switch_port_t port;
switch_sockaddr_t *addr; switch_sockaddr_t *addr;
switch_socket_t *udp_socket; switch_socket_t *udp_socket;
@ -295,36 +294,35 @@ static void event_handler(switch_event_t *event)
switch_uuid_get(&uuid); switch_uuid_get(&uuid);
switch_uuid_format(uuid_str, &uuid); switch_uuid_format(uuid_str, &uuid);
len = strlen(packet) + sizeof(globals.host_hash) + SWITCH_UUID_FORMATTED_LENGTH + EVP_MAX_IV_LENGTH + strlen((char *) MAGIC); len = strlen(packet) + SWITCH_UUID_FORMATTED_LENGTH + EVP_MAX_IV_LENGTH + strlen((char *) MAGIC);
#else #else
len = strlen(packet) + sizeof(globals.host_hash) + strlen((char *) MAGIC); len = strlen(packet) + strlen((char *) MAGIC);
#endif #endif
buf = malloc(len + 1); buf = malloc(len + 1);
memset(buf, 0, len + 1); memset(buf, 0, len + 1);
switch_assert(buf); switch_assert(buf);
memcpy(buf, &globals.host_hash, sizeof(globals.host_hash));
#ifdef HAVE_OPENSSL #ifdef HAVE_OPENSSL
if (globals.psk) { if (globals.psk) {
switch_copy_string(buf + sizeof(globals.host_hash), uuid_str, SWITCH_UUID_FORMATTED_LENGTH); switch_copy_string(buf, uuid_str, SWITCH_UUID_FORMATTED_LENGTH);
EVP_CIPHER_CTX_init(&ctx); EVP_CIPHER_CTX_init(&ctx);
EVP_EncryptInit(&ctx, EVP_bf_cbc(), NULL, NULL); EVP_EncryptInit(&ctx, EVP_bf_cbc(), NULL, NULL);
EVP_CIPHER_CTX_set_key_length(&ctx, strlen(globals.psk)); EVP_CIPHER_CTX_set_key_length(&ctx, strlen(globals.psk));
EVP_EncryptInit(&ctx, NULL, (unsigned char *) globals.psk, (unsigned char *) uuid_str); EVP_EncryptInit(&ctx, NULL, (unsigned char *) globals.psk, (unsigned char *) uuid_str);
EVP_EncryptUpdate(&ctx, (unsigned char *) buf + sizeof(globals.host_hash) + SWITCH_UUID_FORMATTED_LENGTH, EVP_EncryptUpdate(&ctx, (unsigned char *) buf + SWITCH_UUID_FORMATTED_LENGTH,
&outlen, (unsigned char *) packet, (int) strlen(packet)); &outlen, (unsigned char *) packet, (int) strlen(packet));
EVP_EncryptUpdate(&ctx, (unsigned char *) buf + sizeof(globals.host_hash) + SWITCH_UUID_FORMATTED_LENGTH + outlen, EVP_EncryptUpdate(&ctx, (unsigned char *) buf + SWITCH_UUID_FORMATTED_LENGTH + outlen,
&tmplen, (unsigned char *) MAGIC, (int) strlen((char *) MAGIC)); &tmplen, (unsigned char *) MAGIC, (int) strlen((char *) MAGIC));
outlen += tmplen; outlen += tmplen;
EVP_EncryptFinal(&ctx, (unsigned char *) buf + sizeof(globals.host_hash) + SWITCH_UUID_FORMATTED_LENGTH + outlen, &tmplen); EVP_EncryptFinal(&ctx, (unsigned char *) buf + SWITCH_UUID_FORMATTED_LENGTH + outlen, &tmplen);
outlen += tmplen; outlen += tmplen;
len = (size_t) outlen + sizeof(globals.host_hash) + SWITCH_UUID_FORMATTED_LENGTH; len = (size_t) outlen + SWITCH_UUID_FORMATTED_LENGTH;
*(buf + sizeof(globals.host_hash) + SWITCH_UUID_FORMATTED_LENGTH + outlen) = '\0'; *(buf + SWITCH_UUID_FORMATTED_LENGTH + outlen) = '\0';
} else { } else {
#endif #endif
switch_copy_string(buf + sizeof(globals.host_hash), packet, len - sizeof(globals.host_hash)); switch_copy_string(buf, packet, len);
switch_copy_string(buf + sizeof(globals.host_hash) + strlen(packet), (char *) MAGIC, strlen((char *) MAGIC) + 1); switch_copy_string(buf + strlen(packet), (char *) MAGIC, strlen((char *) MAGIC) + 1);
#ifdef HAVE_OPENSSL #ifdef HAVE_OPENSSL
} }
#endif #endif
@ -369,7 +367,6 @@ SWITCH_STANDARD_API(multicast_peers)
SWITCH_MODULE_LOAD_FUNCTION(mod_event_multicast_load) SWITCH_MODULE_LOAD_FUNCTION(mod_event_multicast_load)
{ {
switch_api_interface_t *api_interface; switch_api_interface_t *api_interface;
switch_ssize_t hlen = -1;
switch_status_t status = SWITCH_STATUS_GENERR; switch_status_t status = SWITCH_STATUS_GENERR;
memset(&globals, 0, sizeof(globals)); memset(&globals, 0, sizeof(globals));
@ -381,7 +378,6 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_event_multicast_load)
switch_core_hash_init(&globals.peer_hash, module_pool); switch_core_hash_init(&globals.peer_hash, module_pool);
gethostname(globals.hostname, sizeof(globals.hostname)); gethostname(globals.hostname, sizeof(globals.hostname));
globals.host_hash = switch_hashfunc_default(globals.hostname, &hlen);
globals.key_count = 0; globals.key_count = 0;
if (load_config() != SWITCH_STATUS_SUCCESS) { if (load_config() != SWITCH_STATUS_SUCCESS) {
@ -414,6 +410,11 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_event_multicast_load)
switch_goto_status(SWITCH_STATUS_TERM, fail); switch_goto_status(SWITCH_STATUS_TERM, fail);
} }
if (switch_mcast_loopback(globals.udp_socket, 0) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to disable loopback\n");
switch_goto_status(SWITCH_STATUS_TERM, fail);
}
if (switch_socket_bind(globals.udp_socket, globals.addr) != SWITCH_STATUS_SUCCESS) { if (switch_socket_bind(globals.udp_socket, globals.addr) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Bind Error\n"); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Bind Error\n");
switch_goto_status(SWITCH_STATUS_TERM, fail); switch_goto_status(SWITCH_STATUS_TERM, fail);
@ -501,7 +502,6 @@ SWITCH_MODULE_RUNTIME_FUNCTION(mod_event_multicast_runtime)
char *myaddr; char *myaddr;
size_t len = MULTICAST_BUFFSIZE; size_t len = MULTICAST_BUFFSIZE;
char *packet; char *packet;
uint64_t host_hash = 0;
switch_status_t status; switch_status_t status;
memset(buf, 0, len); memset(buf, 0, len);
@ -520,12 +520,8 @@ SWITCH_MODULE_RUNTIME_FUNCTION(mod_event_multicast_runtime)
} }
#endif #endif
memcpy(&host_hash, buf, sizeof(host_hash)); packet = buf;
packet = buf + sizeof(host_hash);
if (host_hash == globals.host_hash) {
continue;
}
#ifdef HAVE_OPENSSL #ifdef HAVE_OPENSSL
if (globals.psk) { if (globals.psk) {
char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1]; char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
@ -533,7 +529,7 @@ SWITCH_MODULE_RUNTIME_FUNCTION(mod_event_multicast_runtime)
int outl, tmplen; int outl, tmplen;
EVP_CIPHER_CTX ctx; EVP_CIPHER_CTX ctx;
len -= sizeof(host_hash) + SWITCH_UUID_FORMATTED_LENGTH; len -= SWITCH_UUID_FORMATTED_LENGTH;
tmp = malloc(len); tmp = malloc(len);

View File

@ -0,0 +1 @@
Makefile

View File

@ -768,6 +768,10 @@ SWITCH_DECLARE(switch_status_t) switch_mcast_hops(switch_socket_t *sock, uint8_t
return apr_mcast_hops(sock, ttl); return apr_mcast_hops(sock, ttl);
} }
SWITCH_DECLARE(switch_status_t) switch_mcast_loopback(switch_socket_t *sock, uint8_t opt)
{
return apr_mcast_loopback(sock, opt);
}
/* socket functions */ /* socket functions */

View File

@ -737,34 +737,49 @@ SWITCH_DECLARE(switch_status_t) switch_channel_set_profile_var(switch_channel_t
return status; return status;
} }
SWITCH_DECLARE(switch_status_t) switch_channel_export_variable_var_check(switch_channel_t *channel, const char *varname, const char *value, switch_bool_t var_check, switch_bool_t nolocal) SWITCH_DECLARE(switch_status_t) switch_channel_export_variable_var_check(switch_channel_t *channel, const char *varname, const char *value, switch_bool_t var_check)
{ {
const char *exports, *exports_varname = varname; const char *exports;
switch_status_t status; switch_status_t status = SWITCH_STATUS_FALSE;
exports = switch_channel_get_variable(channel, SWITCH_EXPORT_VARS_VARIABLE); exports = switch_channel_get_variable(channel, SWITCH_EXPORT_VARS_VARIABLE);
if (nolocal) { if ((status = switch_channel_set_variable_var_check(channel, varname, value, var_check)) != SWITCH_STATUS_SUCCESS) {
exports_varname = switch_mprintf("nolocal:%s", varname); return status;
}
if ((status = switch_channel_set_variable_var_check(channel, exports_varname, value, var_check)) != SWITCH_STATUS_SUCCESS) {
goto done;
} }
if (varname && value) { if (varname && value) {
if (exports) { if (exports) {
switch_channel_set_variable_printf(channel, SWITCH_EXPORT_VARS_VARIABLE, "%s,%s", exports, exports_varname); switch_channel_set_variable_printf(channel, SWITCH_EXPORT_VARS_VARIABLE, "%s,%s", exports, varname);
} else { } else {
switch_channel_set_variable(channel, SWITCH_EXPORT_VARS_VARIABLE, exports_varname); switch_channel_set_variable(channel, SWITCH_EXPORT_VARS_VARIABLE, varname);
} }
} }
done: return status;
if (exports_varname != varname) { }
free((char*)exports_varname);
SWITCH_DECLARE(switch_status_t) switch_channel_export_variable_printf(switch_channel_t *channel, const char *varname, const char *fmt, ...)
{
switch_status_t status = SWITCH_STATUS_FALSE;
char *data = NULL;
va_list ap;
int ret;
switch_assert(channel != NULL);
va_start(ap, fmt);
ret = switch_vasprintf(&data, fmt, ap);
va_end(ap);
if (ret == -1) {
return SWITCH_STATUS_FALSE;
} }
status = switch_channel_export_variable(channel, varname, data);
free(data);
return status; return status;
} }

View File

@ -304,6 +304,7 @@ static int switch_console_process(char *xcmd)
switch_stream_handle_t stream = { 0 }; switch_stream_handle_t stream = { 0 };
switch_status_t status; switch_status_t status;
FILE *handle = switch_core_get_console(); FILE *handle = switch_core_get_console();
int r = 1;
SWITCH_STANDARD_STREAM(stream); SWITCH_STANDARD_STREAM(stream);
switch_assert(stream.data); switch_assert(stream.data);
@ -316,6 +317,9 @@ static int switch_console_process(char *xcmd)
fflush(handle); fflush(handle);
} }
} else { } else {
if (!strcasecmp(xcmd, "...") || !strcasecmp(xcmd, "shutdown")) {
r = 0;
}
if (handle) { if (handle) {
fprintf(handle, "Unknown Command: %s\n", xcmd); fprintf(handle, "Unknown Command: %s\n", xcmd);
fflush(handle); fflush(handle);
@ -324,7 +328,7 @@ static int switch_console_process(char *xcmd)
switch_safe_free(stream.data); switch_safe_free(stream.data);
return 1; return r;
} }

View File

@ -128,17 +128,20 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_get_partner(switch_core_sess
} }
struct str_node {
char *str;
struct str_node *next;
};
SWITCH_DECLARE(void) switch_core_session_hupall_matching_var(const char *var_name, const char *var_val, switch_call_cause_t cause) SWITCH_DECLARE(void) switch_core_session_hupall_matching_var(const char *var_name, const char *var_val, switch_call_cause_t cause)
{ {
switch_hash_index_t *hi; switch_hash_index_t *hi;
void *val; void *val;
switch_core_session_t *session; switch_core_session_t *session;
switch_memory_pool_t *pool; switch_memory_pool_t *pool;
switch_queue_t *queue; struct str_node *head = NULL, *np;
void *pop;
switch_core_new_memory_pool(&pool); switch_core_new_memory_pool(&pool);
switch_queue_create(&queue, 250000, pool);
if (!var_val) if (!var_val)
return; return;
@ -152,7 +155,10 @@ SWITCH_DECLARE(void) switch_core_session_hupall_matching_var(const char *var_nam
if (switch_core_session_read_lock(session) == SWITCH_STATUS_SUCCESS) { if (switch_core_session_read_lock(session) == SWITCH_STATUS_SUCCESS) {
if (switch_channel_up(session->channel) && if (switch_channel_up(session->channel) &&
(this_val = switch_channel_get_variable(session->channel, var_name)) && (!strcmp(this_val, var_val))) { (this_val = switch_channel_get_variable(session->channel, var_name)) && (!strcmp(this_val, var_val))) {
switch_queue_push(queue, switch_core_strdup(pool, session->uuid_str)); np = switch_core_alloc(pool, sizeof(*np));
np->str = switch_core_strdup(pool, session->uuid_str);
np->next = head;
head = np;
} }
switch_core_session_rwunlock(session); switch_core_session_rwunlock(session);
} }
@ -160,10 +166,8 @@ SWITCH_DECLARE(void) switch_core_session_hupall_matching_var(const char *var_nam
} }
switch_mutex_unlock(runtime.session_hash_mutex); switch_mutex_unlock(runtime.session_hash_mutex);
while (switch_queue_trypop(queue, &pop) == SWITCH_STATUS_SUCCESS && pop) { for(np = head; np; np = np->next) {
char *uuid = (char *) pop; if ((session = switch_core_session_locate(np->str))) {
if ((session = switch_core_session_locate(uuid))) {
switch_channel_hangup(session->channel, cause); switch_channel_hangup(session->channel, cause);
switch_core_session_rwunlock(session); switch_core_session_rwunlock(session);
} }
@ -179,12 +183,10 @@ SWITCH_DECLARE(void) switch_core_session_hupall_endpoint(const switch_endpoint_i
void *val; void *val;
switch_core_session_t *session; switch_core_session_t *session;
switch_memory_pool_t *pool; switch_memory_pool_t *pool;
switch_queue_t *queue; struct str_node *head = NULL, *np;
void *pop;
switch_core_new_memory_pool(&pool); switch_core_new_memory_pool(&pool);
switch_queue_create(&queue, 250000, pool);
switch_mutex_lock(runtime.session_hash_mutex); switch_mutex_lock(runtime.session_hash_mutex);
for (hi = switch_hash_first(NULL, session_manager.session_table); hi; hi = switch_hash_next(hi)) { for (hi = switch_hash_first(NULL, session_manager.session_table); hi; hi = switch_hash_next(hi)) {
switch_hash_this(hi, NULL, NULL, &val); switch_hash_this(hi, NULL, NULL, &val);
@ -192,7 +194,10 @@ SWITCH_DECLARE(void) switch_core_session_hupall_endpoint(const switch_endpoint_i
session = (switch_core_session_t *) val; session = (switch_core_session_t *) val;
if (switch_core_session_read_lock(session) == SWITCH_STATUS_SUCCESS) { if (switch_core_session_read_lock(session) == SWITCH_STATUS_SUCCESS) {
if (session->endpoint_interface == endpoint_interface) { if (session->endpoint_interface == endpoint_interface) {
switch_queue_push(queue, switch_core_strdup(pool, session->uuid_str)); np = switch_core_alloc(pool, sizeof(*np));
np->str = switch_core_strdup(pool, session->uuid_str);
np->next = head;
head = np;
} }
switch_core_session_rwunlock(session); switch_core_session_rwunlock(session);
} }
@ -200,10 +205,8 @@ SWITCH_DECLARE(void) switch_core_session_hupall_endpoint(const switch_endpoint_i
} }
switch_mutex_unlock(runtime.session_hash_mutex); switch_mutex_unlock(runtime.session_hash_mutex);
while (switch_queue_trypop(queue, &pop) == SWITCH_STATUS_SUCCESS && pop) { for(np = head; np; np = np->next) {
char *uuid = (char *) pop; if ((session = switch_core_session_locate(np->str))) {
if ((session = switch_core_session_locate(uuid))) {
switch_channel_hangup(session->channel, cause); switch_channel_hangup(session->channel, cause);
switch_core_session_rwunlock(session); switch_core_session_rwunlock(session);
} }
@ -219,11 +222,10 @@ SWITCH_DECLARE(void) switch_core_session_hupall(switch_call_cause_t cause)
void *val; void *val;
switch_core_session_t *session; switch_core_session_t *session;
switch_memory_pool_t *pool; switch_memory_pool_t *pool;
switch_queue_t *queue; struct str_node *head = NULL, *np;
void *pop;
switch_core_new_memory_pool(&pool); switch_core_new_memory_pool(&pool);
switch_queue_create(&queue, 250000, pool);
switch_mutex_lock(runtime.session_hash_mutex); switch_mutex_lock(runtime.session_hash_mutex);
for (hi = switch_hash_first(NULL, session_manager.session_table); hi; hi = switch_hash_next(hi)) { for (hi = switch_hash_first(NULL, session_manager.session_table); hi; hi = switch_hash_next(hi)) {
@ -231,17 +233,18 @@ SWITCH_DECLARE(void) switch_core_session_hupall(switch_call_cause_t cause)
if (val) { if (val) {
session = (switch_core_session_t *) val; session = (switch_core_session_t *) val;
if (switch_core_session_read_lock(session) == SWITCH_STATUS_SUCCESS) { if (switch_core_session_read_lock(session) == SWITCH_STATUS_SUCCESS) {
switch_queue_push(queue, switch_core_strdup(pool, session->uuid_str)); np = switch_core_alloc(pool, sizeof(*np));
np->str = switch_core_strdup(pool, session->uuid_str);
np->next = head;
head = np;
switch_core_session_rwunlock(session); switch_core_session_rwunlock(session);
} }
} }
} }
switch_mutex_unlock(runtime.session_hash_mutex); switch_mutex_unlock(runtime.session_hash_mutex);
while (switch_queue_trypop(queue, &pop) == SWITCH_STATUS_SUCCESS && pop) { for(np = head; np; np = np->next) {
char *uuid = (char *) pop; if ((session = switch_core_session_locate(np->str))) {
if ((session = switch_core_session_locate(uuid))) {
switch_channel_hangup(session->channel, cause); switch_channel_hangup(session->channel, cause);
switch_core_session_rwunlock(session); switch_core_session_rwunlock(session);
} }

View File

@ -633,6 +633,7 @@ SWITCH_MODULE_LOAD_FUNCTION(core_pcm_load)
mod_g711_load(module_interface, pool); mod_g711_load(module_interface, pool);
return SWITCH_STATUS_SUCCESS; return SWITCH_STATUS_SUCCESS;
//return SWITCH_STATUS_NOUNLOAD;
} }
SWITCH_MODULE_SHUTDOWN_FUNCTION(core_pcm_shutdown) SWITCH_MODULE_SHUTDOWN_FUNCTION(core_pcm_shutdown)