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

View File

@ -470,6 +470,7 @@ update: is-scm
echo Updating... ; \
svn update ; \
elif test -d .git ; then \
test ! -f .version || rm -f .version ; \
echo "Pulling updates..." ; \
git pull ; \
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/accountdialog.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 \
fshost.h \
call.h \
@ -41,9 +46,17 @@ HEADERS += mainwindow.h \
preferences/prefsofia.h \
preferences/accountdialog.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 \
preferences/prefdialog.ui \
preferences/accountdialog.ui
preferences/accountdialog.ui \
widgets/codecwidget.ui \
debugtools/consolewindow.ui \
debugtools/statedebugdialog.ui
RESOURCES += resources.qrc
OTHER_FILES += conf/freeswitch.xml

View File

@ -33,16 +33,28 @@
Call::Call()
{
_answeredEpoch = 0;
}
Call::Call(int call_id, QString cid_name, QString cid_number, fscomm_call_direction_t direction, QString uuid) :
_call_id(call_id),
_cid_name(cid_name),
_cid_number(cid_number),
_direction(direction),
_uuid (uuid)
switch_status_t Call::toggleHold(bool holdPressed)
{
_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)
@ -56,14 +68,14 @@ switch_status_t Call::toggleRecord(bool startRecord)
_recording_filename = QString("%1/.fscomm/recordings/%2_%3.wav").arg(
conf_dir.absolutePath(),
QDateTime::currentDateTime().toString("yyyyMMddhhmmss"),
_cid_number);
status = g_FSHost.sendCmd("uuid_record", QString("%1 start %2").arg(_uuid, _recording_filename).toAscii().data(),&result);
getCidNumber());
status = g_FSHost.sendCmd("uuid_record", QString("%1 start %2").arg(getUuid(), _recording_filename).toAscii().data(),&result);
}
else
{
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Stopping call recording on call [%s]\n",
_uuid.toAscii().data());
status = g_FSHost.sendCmd("uuid_record", QString("%1 stop %2").arg(_uuid, _recording_filename).toAscii().data(),&result);
getUuid().toAscii().data());
status = g_FSHost.sendCmd("uuid_record", QString("%1 stop %2").arg(getUuid(), _recording_filename).toAscii().data(),&result);
}
return status;
@ -74,13 +86,29 @@ void Call::sendDTMF(QString digit)
QString result;
QString dtmf_string = QString("dtmf %1").arg(digit);
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);
}
}
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");
}

View File

@ -32,6 +32,7 @@
#include <QtCore>
#include <QString>
#include <switch.h>
#include "channel.h"
typedef enum {
FSCOMM_CALL_STATE_RINGING = 0,
@ -48,36 +49,44 @@ typedef enum {
class Call {
public:
Call();
Call(int call_id, QString cid_name, QString cid_number, fscomm_call_direction_t direction, QString uuid);
QString getCidName(void) { return _cid_name; }
QString getCidNumber(void) { return _cid_number; }
int getCallID(void) { return _call_id; }
QString getUUID(void) { return _uuid; }
void setbUUID(QString uuid) { _buuid = uuid; }
/* Needs rework */
QString getCidName(void) { return (_direction == FSCOMM_CALL_DIRECTION_INBOUND) ? _otherLegChannel.data()->getCidName() : _channel.data()->getCidName(); }
QString getCidNumber(void) { return (_direction == FSCOMM_CALL_DIRECTION_INBOUND) ? _otherLegChannel.data()->getCidNumber() : _channel.data()->getCidNumber(); }
QString getDestinationNumber(void) { return _otherLegChannel.data()->getDestinationNumber(); }
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_state_t getState() { return _state; }
void setState(fscomm_call_state_t state) { _state = state; }
void setCause(QString cause) { _cause = cause; }
QString getCause() { return _cause; }
void setCause(QString cause) { _cause = cause; qDebug()<<cause; }
QString getCause() { return _cause; qDebug() << _cause; }
void setActive(bool isActive) { _isActive = isActive; }
bool isActive() { return _isActive == true; }
switch_status_t toggleRecord(bool);
switch_status_t toggleHold(bool);
void sendDTMF(QString digit);
void setAnsweredEpoch(qulonglong time) { _answered_epoch = time/1000000; }
void setAnsweredEpoch(qulonglong time) { _answeredEpoch = time/1000000; }
QTime getCurrentStateTime();
private:
int _call_id;
QString _cid_name;
QString _cid_number;
QSharedPointer<Channel> _channel; /* This should be our portaudio channel */
QSharedPointer<Channel> _otherLegChannel;
QString _cause;
fscomm_call_direction_t _direction;
QString _uuid;
QString _buuid;
bool _isActive;
QString _recording_filename;
fscomm_call_state_t _state;
qulonglong _answered_epoch;
qulonglong _answeredEpoch;
};
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_speex"/>
<load module="mod_celt"/>
<load module="mod_silk"/>
<load module="mod_siren"/>
<load module="mod_sndfile"/>
<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();
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>");
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)
{
switch_core_flag_t flags = SCF_USE_SQL | SCF_USE_AUTO_NAT;
@ -149,6 +158,7 @@ void FSHost::run(void)
emit coreLoadingError(err);
}
switch_log_bind_logger(loggerHandler, SWITCH_LOG_DEBUG, SWITCH_FALSE);
emit ready();
/* 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;
QSharedPointer<Call> call = _active_calls.value(uuid);
QString uuid = switch_event_get_header_nil(event.data(), "Unique-ID");
if (call.isNull())
{
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;
}
emit newEvent(event);
/* Inbound call */
if (call.data()->getDirection() == FSCOMM_CALL_DIRECTION_INBOUND)
{
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)
switch(event.data()->event_id) {
case SWITCH_EVENT_CHANNEL_CREATE: /*1A - 17B*/
{
case SWITCH_EVENT_CHANNEL_BRIDGE:
{
_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"));
eventChannelCreate(event, uuid);
break;
}
}
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: /*2A - 31B*/
{
case SWITCH_EVENT_CHANNEL_ANSWER:
{
/* 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"));
eventChannelAnswer(event, uuid);
break;
}
}
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)
case SWITCH_EVENT_CODEC:/*3/4A - 24/25B*/
{
return;
eventCodec(event, uuid);
break;
}
}
if (_active_calls.contains(uuid))
{
if (processAlegEvent(event, uuid) == SWITCH_STATUS_SUCCESS)
case SWITCH_EVENT_CHANNEL_STATE:/*6/7/8/37/44/46A - 20/21/22/28/38/40/42B*/
{
return;
eventChannelState(event, uuid);
break;
}
}
/* This is how we identify new calls, inbound and outbound */
switch(event->event_id) {
case SWITCH_EVENT_CUSTOM:
case SWITCH_EVENT_CHANNEL_EXECUTE:/*9/11/13/15A*/
{
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")),
switch_event_get_header_nil(event, "Caller-Caller-ID-Name"),
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");
QString state = switch_event_get_header_nil(event.data(), "State");
QString gw = switch_event_get_header_nil(event.data(), "Gateway");
QSharedPointer<Account> acc = _accounts.value(gw);
if (acc.isNull())
return;
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);
emit accountStateChange(acc);
} 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);
emit accountStateChange(acc);
} 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);
emit accountStateChange(acc);
} 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);
emit accountStateChange(acc);
} 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);
emit accountStateChange(acc);
} 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);
emit accountStateChange(acc);
} else if (state == "FAIL_WAIT") {
acc.data()->setState(FSCOMM_GW_STATE_FAIL_WAIT);
emit accountStateChange(acc);
} 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);
emit accountStateChange(acc);
} 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);
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);
QSharedPointer<Account> acc = QSharedPointer<Account>(accPtr);
acc.data()->setState(FSCOMM_GW_STATE_NOAVAIL);
_accounts.insert(gw, 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())
emit delAccount(acc);
}
else
{
printEventHeaders(event);
//printEventHeaders(event);
}
break;
}
case SWITCH_EVENT_MODULE_LOAD:
{
QString modType = switch_event_get_header_nil(event, "type");
QString modName = switch_event_get_header_nil(event, "name");
QString modKey = switch_event_get_header_nil(event, "key");
emit loadedModule(modType, modName, modKey);
QString modType = switch_event_get_header_nil(event.data(), "type");
QString modKey = switch_event_get_header_nil(event.data(), "key");
emit loadedModule(modType, modKey);
break;
}
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")
{
@ -501,11 +529,11 @@ QSharedPointer<Call> FSHost::getCurrentActiveCall()
return QSharedPointer<Call>();
}
void FSHost::printEventHeaders(switch_event_t *event)
void FSHost::printEventHeaders(QSharedPointer<switch_event_t>event)
{
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"));
for (hp = event->headers; hp; hp = hp->next) {
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.data()->headers; hp; hp = hp->next) {
qDebug() << hp->name << "=" << hp->value;
}
qDebug() << "\n\n";

View File

@ -35,6 +35,7 @@
#include <QSharedPointer>
#include <switch.h>
#include "call.h"
#include "channel.h"
#include "account.h"
class FSHost : public QThread
@ -43,7 +44,8 @@ Q_OBJECT
public:
explicit FSHost(QObject *parent = 0);
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> getCurrentActiveCall();
QList<QSharedPointer<Account> > getAccounts() { return _accounts.values(); }
@ -57,15 +59,25 @@ protected:
void run(void);
signals:
/* Status signals */
void coreLoadingError(QString);
void loadingModules(QString, int, QColor);
void loadedModule(QString, QString, QString);
void loadedModule(QString, QString);
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 answered(QSharedPointer<Call>);
void newOutgoingCall(QSharedPointer<Call>);
void callFailed(QSharedPointer<Call>);
void hungup(QSharedPointer<Call>);
/* Account signals */
void accountStateChange(QSharedPointer<Account>);
void newAccount(QSharedPointer<Account>);
void delAccount(QSharedPointer<Account>);
@ -73,16 +85,39 @@ signals:
private slots:
/* We need to wait for the gateway deletion before reloading it */
void accountReloadSlot(QSharedPointer<Account>);
void minimalModuleLoaded(QString, QString, QString);
void minimalModuleLoaded(QString, QString);
private:
switch_status_t processBlegEvent(switch_event_t *, QString);
switch_status_t processAlegEvent(switch_event_t *, QString);
/* Helper methods */
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<Account> > _accounts;
QHash<QString, QString> _bleg_uuids;
QHash<QString, QSharedPointer<Channel> > _channels;
QList<QString> _reloading_Accounts;
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
method callback to make use of the signal/slot infrastructure.
*/
*/
static void eventHandlerCallback(switch_event_t *event)
{
switch_event_t *clone = NULL;
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

View File

@ -36,7 +36,10 @@
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow),
preferences(NULL)
preferences(NULL),
_consoleWindow(NULL),
_stateDebugDialog(NULL)
{
ui->setupUi(this);
@ -97,9 +100,12 @@ MainWindow::MainWindow(QWidget *parent) :
connect(ui->answerBtn, SIGNAL(clicked()), this, SLOT(paAnswer()));
connect(ui->hangupBtn, SIGNAL(clicked()), this, SLOT(paHangup()));
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->action_Preferences, SIGNAL(triggered()), this, SLOT(prefTriggered()));
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->actionSetDefaultAccount, SIGNAL(triggered(bool)), this, SLOT(setDefaultAccount()));
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());
QTime time = call.data()->getCurrentStateTime();
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();
}
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()
{
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_num", cidNum.toAscii().data());
qDebug() << "Name:" << cidName << "Num:" << cidNum;
}
if (ok && !dialstring.isEmpty())
@ -337,16 +364,35 @@ void MainWindow::paHangup()
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)
{
QSharedPointer<Call> call = g_FSHost.getCurrentActiveCall();
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");
return;
}
@ -357,26 +403,26 @@ void MainWindow::recordCall(bool pressed)
tr("<p>Could not get active call to start/stop recording."
"<p>Please report this bug."),
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;
}
}
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);
QTableWidgetItem *item0 = new QTableWidgetItem(QString("%1 (%2)").arg(call.data()->getCidName(), call.data()->getCidNumber()));
item0->setData(Qt::UserRole, call.data()->getUUID());
QTableWidgetItem *item0 = new QTableWidgetItem(QString("%1").arg(call.data()->getDestinationNumber()));
item0->setData(Qt::UserRole, call.data()->getUuid());
ui->tableCalls->setItem(ui->tableCalls->rowCount()-1,0,item0);
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);
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->resizeColumnsToContents();
@ -393,27 +439,33 @@ void MainWindow::ringing(QSharedPointer<Call> call)
for (int i=0; i<ui->tableCalls->rowCount(); i++)
{
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"));
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;
}
}
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);
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);
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);
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->resizeColumnsToContents();
@ -429,7 +481,7 @@ void MainWindow::answered(QSharedPointer<Call> call)
for (int i=0; i<ui->tableCalls->rowCount(); i++)
{
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"));
ui->tableCalls->resizeColumnsToContents();
@ -440,6 +492,9 @@ void MainWindow::answered(QSharedPointer<Call> call)
}
ui->recoredCallBtn->setEnabled(true);
ui->recoredCallBtn->setChecked(false);
ui->btnHold->setEnabled(true);
ui->btnHold->setChecked(false);
ui->btnTransfer->setEnabled(true);
ui->dtmf0Btn->setEnabled(true);
ui->dtmf1Btn->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++)
{
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->resizeColumnsToContents();
@ -472,13 +527,26 @@ void MainWindow::callFailed(QSharedPointer<Call> call)
break;
}
}
ui->textEdit->setText(tr("Call with %1 (%2) failed with reason %3.").arg(call.data()->getCidName(),
call.data()->getCidNumber(),
call.data()->getCause()));
if (call.data()->getDirection() == FSCOMM_CALL_DIRECTION_INBOUND)
{
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);
/* TODO: Will cause problems if 2 calls are received at the same time */
ui->recoredCallBtn->setEnabled(false);
ui->recoredCallBtn->setChecked(false);
ui->btnHold->setEnabled(false);
ui->btnHold->setChecked(false);
ui->btnTransfer->setEnabled(false);
ui->answerBtn->setEnabled(false);
ui->hangupBtn->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++)
{
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->resizeColumnsToContents();
@ -515,10 +583,20 @@ void MainWindow::hungup(QSharedPointer<Call> call)
}
}
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 */
ui->recoredCallBtn->setEnabled(false);
ui->recoredCallBtn->setChecked(false);
ui->btnHold->setEnabled(false);
ui->btnHold->setChecked(false);
ui->btnTransfer->setEnabled(false);
ui->answerBtn->setEnabled(false);
ui->hangupBtn->setEnabled(false);
ui->dtmf0Btn->setEnabled(false);

View File

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

View File

@ -14,28 +14,250 @@
<string>FSComm - A FreeSWITCH Communicator</string>
</property>
<widget class="QWidget" name="centralWidget">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QTextEdit" name="textEdit">
<property name="enabled">
<bool>false</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QTextEdit" name="textEdit">
<property name="enabled">
<bool>false</bool>
</property>
<property name="readOnly">
<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>
<layout class="QHBoxLayout" name="horizontalLayout">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QPushButton" name="newCallBtn">
<widget class="QPushButton" name="btnTransfer">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>New Call</string>
<string>Transfer</string>
</property>
</widget>
</item>
@ -47,200 +269,6 @@
<property name="text">
<string>Record</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>
@ -375,7 +403,21 @@
</property>
<addaction name="actionAbout"/>
</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="menuTools"/>
<addaction name="menuHelp"/>
</widget>
<widget class="QToolBar" name="mainToolBar">
@ -410,6 +452,16 @@
<string>Set the default account for dialing out.</string>
</property>
</action>
<action name="actionConsole">
<property name="text">
<string>Console</string>
</property>
</action>
<action name="actionEvents">
<property name="text">
<string>Events</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>

View File

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

View File

@ -42,7 +42,7 @@ void PrefSofia::readConfig()
_ui->sofiaSipPortSpin->setValue(settings.value("sip-port").toInt());
_ui->sofiaDialplanEdit->setText(settings.value("dialplan").toString());
_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->sofiaRtpTimerNameEdit->setText(settings.value("rtp-timer-name").toString());
_ui->sofiaRtpIpEdit->setText(settings.value("rtp-ip").toString());
@ -68,15 +68,6 @@ void PrefSofia::readConfig()
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()
@ -110,7 +101,7 @@ void PrefSofia::writeConfig()
settings.setValue("sip-port", _ui->sofiaSipPortSpin->value());
settings.setValue("dialplan", _ui->sofiaDialplanEdit->text());
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("rtp-timer-name", _ui->sofiaRtpTimerNameEdit->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)/ftdm_buffer.c \
$(SRC)/ftdm_threadmutex.c \
$(SRC)/ftdm_dso.c
$(SRC)/ftdm_dso.c \
$(SRC)/ftdm_cpu_monitor.c
library_include_HEADERS = \
$(SRC)/include/fsk.h \
@ -90,7 +91,8 @@ $(SRC)/include/ftdm_buffer.h \
$(SRC)/include/ftdm_config.h \
$(SRC)/include/ftdm_threadmutex.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
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);
}
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) {
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"
"state: %s\n"
"last_state: %s\n"
"txgain: %3.2f\n"
"rxgain: %3.2f\n"
"cid_date: %s\n"
"cid_name: %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_channel_state2str(span->channels[chan_id]->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_name,
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"
" <state>%s</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-name>%s</cid-name>\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_channel_state2str(span->channels[chan_id]->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_name,
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)
{
char *mycmd = NULL, *argv[10] = { 0 };
@ -3142,6 +3159,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_freetdm_load)
module_pool = pool;
ftdm_global_set_logger(ftdm_logger);
ftdm_cpu_monitor_disable();
if (ftdm_global_init() != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_ERROR, "Error loading FreeTDM\n");

View File

@ -326,10 +326,34 @@
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath="..\src\include\freetdm.h"
>
</File>
<File
RelativePath="..\src\include\fsk.h"
>
</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
RelativePath="..\src\include\g711.h"
>
@ -358,34 +382,10 @@
RelativePath="..\src\include\libteletone_generate.h"
>
</File>
<File
RelativePath="..\src\include\freetdm.h"
>
</File>
<File
RelativePath="..\src\include\uart.h"
>
</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
Name="Source Files"
@ -396,6 +396,38 @@
RelativePath="..\src\fsk.c"
>
</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
RelativePath="..\src\g711.c"
>
@ -420,34 +452,6 @@
RelativePath="..\src\uart.c"
>
</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>
</Files>
<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
#include "ftdm_pika.h"
#endif
#include "ftdm_cpu_monitor.h"
#define SPAN_PENDING_CHANS_QUEUE_SIZE 1000
@ -80,6 +81,16 @@ FT_DECLARE(ftdm_time_t) ftdm_current_time_in_ms(void)
#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 {
ftdm_hash_t *interface_hash;
ftdm_hash_t *module_hash;
@ -93,8 +104,16 @@ static struct {
uint32_t running;
ftdm_span_t *spans;
ftdm_group_t *groups;
cpu_monitor_t cpu_monitor;
} 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 */
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 */
ftdm_queue_destroy(&span->pendingchans);
if (span->pendingchans) {
ftdm_queue_destroy(&span->pendingchans);
}
ftdm_mutex_unlock(span->mutex);
ftdm_mutex_destroy(&span->mutex);
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);
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);
new_span->span_id = ++globals.span_index;
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_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 */
unsigned char sv = 0;
uint8_t sv = 0;
/* linear gain factor */
float lingain = 0;
/* 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_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);
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;
}
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);
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");
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) {
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;
/* FIXME: validate user gain values */
case FTDM_COMMAND_SET_RX_GAIN:
{
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 {
ftdm_set_flag(ftdmchan, FTDM_CHANNEL_USE_RX_GAIN);
}
GOTO_STATUS(done, FTDM_SUCCESS);
}
break;
case FTDM_COMMAND_GET_RX_GAIN:
{
FTDM_COMMAND_OBJ_FLOAT = ftdmchan->rxgain;
GOTO_STATUS(done, FTDM_SUCCESS);
}
break;
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 {
ftdm_set_flag(ftdmchan, FTDM_CHANNEL_USE_TX_GAIN);
}
GOTO_STATUS(done, FTDM_SUCCESS);
}
break;
case FTDM_COMMAND_GET_TX_GAIN:
{
FTDM_COMMAND_OBJ_FLOAT = ftdmchan->txgain;
GOTO_STATUS(done, FTDM_SUCCESS);
}
break;
default:
@ -2049,7 +2080,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_co
GOTO_STATUS(done, FTDM_FAIL);
}
status = ftdmchan->fio->command(ftdmchan, command, obj);
status = ftdmchan->fio->command(ftdmchan, command, obj);
if (status == FTDM_NOTIMPL) {
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;
}
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 load_config(void)
@ -2806,6 +2855,7 @@ static ftdm_status_t load_config(void)
ftdm_config_t cfg;
char *var, *val;
int catno = -1;
int intparam = 0;
int currindex = 0;
ftdm_span_t *span = NULL;
unsigned configured = 0, d = 0;
@ -2814,6 +2864,8 @@ static ftdm_status_t load_config(void)
char group_name[80] = "default";
ftdm_io_interface_t *fio = NULL;
ftdm_analog_start_type_t tmp;
float rxgain = 0.0;
float txgain = 0.0;
ftdm_size_t len = 0;
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) {
currindex = span->chan_count;
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);
} else {
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) {
currindex = span->chan_count;
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);
} else {
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) {
currindex = span->chan_count;
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);
} else {
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")) {
currindex = span->chan_count;
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);
} else if (!strcasecmp(var, "d-channel")) {
if (d) {
@ -2972,10 +3028,19 @@ static ftdm_status_t load_config(void)
} else if (!strcasecmp(var, "cas-channel")) {
currindex = span->chan_count;
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);
} else if (!strcasecmp(var, "dtmf_hangup")) {
span->dtmf_hangup = ftdm_strdup(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")) {
len = strlen(val);
if (len >= sizeof(group_name)) {
@ -2987,6 +3052,46 @@ static ftdm_status_t load_config(void)
} else {
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 {
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_start(ap, sig_cb);
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);
} else {
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;
}
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)
{
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)
{
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);
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) {
globals.running = 0;
ftdm_log(FTDM_LOG_ERROR, "FreeTDM global configuration failed!\n");
return FTDM_FAIL;
}
if (!ftdm_cpu_monitor_disabled) {
if (ftdm_cpu_monitor_start() != FTDM_SUCCESS) {
return FTDM_FAIL;
}
}
return FTDM_SUCCESS;
}
@ -3559,6 +3769,8 @@ FT_DECLARE(ftdm_status_t) ftdm_global_destroy(void)
globals.running = 0;
ftdm_cpu_monitor_stop();
globals.span_index = 0;
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;
#ifdef WIN32
interrupt->interrupt = CreateEvent(NULL, FALSE, FALSE, NULL);
if (!interrupt->interrupt) {
interrupt->event = CreateEvent(NULL, FALSE, FALSE, NULL);
if (!interrupt->event) {
ftdm_log(FTDM_LOG_ERROR, "Failed to allocate interrupt event\n");
goto failed;
}
@ -314,7 +314,7 @@ FT_DECLARE(ftdm_status_t) ftdm_interrupt_wait(ftdm_interrupt_t *interrupt, int m
num++;
ints[1] = interrupt->device;
}
res = WaitForMultipleObjects(num, &ints, FALSE, ms >= 0 ? ms : INFINITE);
res = WaitForMultipleObjects(num, ints, FALSE, ms >= 0 ? ms : INFINITE);
switch (res) {
case WAIT_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");
#ifdef WIN32
if (!SetEvent(interrupt->interrupt)) {
if (!SetEvent(interrupt->event)) {
ftdm_log(FTDM_LOG_ERROR, "Failed to signal interrupt\n");
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");
interrupt = *ininterrupt;
#ifdef WIN32
CloseHandle(interrupt->interrupt);
CloseHandle(interrupt->event);
#else
close(interrupt->readfd);
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)
{
#ifndef WIN32
int i;
int res = 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];
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;
}
/* check for events in the pipes, NOT in the devices */
for (i = 0; i < size; i++) {
if (ints[i].revents & POLLIN) {
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
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)) {
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;

View File

@ -1331,7 +1331,7 @@ static FIO_SIG_CONFIGURE_FUNCTION(ftdm_libpri_configure_span)
if ((isdn_data->opts & FTMOD_LIBPRI_OPT_SUGGEST_CHANNEL)) {
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;

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_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
/* 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)
{
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, 1))) {
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);
ftdmchan=NULL;
ftdmchan = NULL;
}
ftdm_log(FTDM_LOG_CRIT, "START CANT FIND CHAN %d:%d\n", event->span+1,event->chan+1);
goto error;
@ -953,12 +956,13 @@ static void handle_call_start(ftdm_span_t *span, sangomabc_connection_t *mcon, s
return;
error:
hangup_cause = ftdmchan ? ftdmchan->caller_data.hangup_cause : FTDM_CAUSE_REQUESTED_CHAN_UNAVAIL;
sangomabc_exec_command(mcon,
event->span,
event->chan,
0,
SIGBOOST_EVENT_CALL_START_NACK,
0, 0);
hangup_cause, 0);
}
@ -1761,6 +1765,81 @@ end:
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
* \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->set_span_sig_status = sangoma_boost_set_span_sig_status;
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) {
/* the core will do the hunting */
span->channel_request = NULL;
@ -2248,12 +2328,31 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_boost_configure_span)
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
*/
EX_DECLARE_DATA ftdm_module_t ftdm_module = {
/*.name =*/ "sangoma_boost",
/*.io_load =*/ NULL,
/*.io_load =*/ ftdm_sangoma_boost_io_init,
/*.io_unload =*/ NULL,
/*.sig_load = */ ftdm_sangoma_boost_init,
/*.sig_configure =*/ NULL,

View File

@ -37,7 +37,6 @@
#include "freetdm.h"
#ifdef __cplusplus
extern "C" {
#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;
#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
*/
@ -212,6 +220,8 @@ typedef struct boost_sigmod_interface_s {
boost_on_load_func_t on_load;
/*! \brief the module is about to be unloaded */
boost_on_unload_func_t on_unload;
/*! \brief module api function */
boost_api_func_t exec_api;
/*! \brief private pointer for the interface user */
void *pvt;
} boost_sigmod_interface_t;

View File

@ -101,8 +101,6 @@ static struct {
FIO_SPAN_POLL_EVENT_FUNCTION(wanpipe_poll_event);
FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_next_event);
#define WP_INVALID_SOCKET -1
/**
* \brief Poll for event on a wanpipe socket
* \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++) {
ftdm_channel_t *chan;
ftdm_socket_t sockfd = WP_INVALID_SOCKET;
ftdm_socket_t sockfd = FTDM_INVALID_SOCKET;
const char *dtmf = "none";
if (!strncasecmp(span->name, "smg_prid_nfas", 8) && span->trunk_type == FTDM_TRUNK_T1 && x == 24) {
#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);
}
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);
continue;
}
@ -1166,9 +1164,8 @@ static FIO_CHANNEL_DESTROY_FUNCTION(wanpipe_channel_destroy)
}
#endif
if (ftdmchan->sockfd > -1) {
close(ftdmchan->sockfd);
ftdmchan->sockfd = WP_INVALID_SOCKET;
if (ftdmchan->sockfd != FTDM_INVALID_SOCKET) {
sangoma_close(&ftdmchan->sockfd);
}
return FTDM_SUCCESS;

View File

@ -542,29 +542,39 @@ static FIO_CONFIGURE_FUNCTION(zt_configure)
} else if (!strcasecmp(var, "echo_cancel_level")) {
num = atoi(val);
if (num < 0 || num > 256) {
ftdm_log(FTDM_LOG_WARNING, "invalid echo can val at line %d\n", lineno);
} else {
zt_globals.eclevel = num;
}
ftdm_log(FTDM_LOG_WARNING, "invalid echo can val at line %d\n", lineno);
} else {
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")) {
fnum = (float)atof(val);
if (fnum < -100.0 || fnum > 100.0) {
ftdm_log(FTDM_LOG_WARNING, "invalid rxgain val at line %d\n", lineno);
} else {
zt_globals.rxgain = fnum;
ftdm_log(FTDM_LOG_INFO, "Setting rxgain val to %f\n", fnum);
}
ftdm_log(FTDM_LOG_WARNING, "invalid rxgain val at line %d\n", lineno);
} else {
zt_globals.rxgain = fnum;
ftdm_log(FTDM_LOG_INFO, "Setting rxgain val to %f\n", fnum);
}
} else if (!strcasecmp(var, "txgain")) {
fnum = (float)atof(val);
if (fnum < -100.0 || fnum > 100.0) {
ftdm_log(FTDM_LOG_WARNING, "invalid txgain val at line %d\n", lineno);
} else {
zt_globals.txgain = fnum;
ftdm_log(FTDM_LOG_INFO, "Setting txgain val to %f\n", fnum);
}
ftdm_log(FTDM_LOG_WARNING, "invalid txgain val at line %d\n", lineno);
} else {
zt_globals.txgain = 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);
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) {
struct zt_gains gains;
memset(&gains, 0, sizeof(gains));
if (zt_globals.rxgain || zt_globals.txgain) {
struct zt_gains gains;
memset(&gains, 0, sizeof(gains));
gains.chan_no = ftdmchan->physical_chan_id;
zt_build_gains(&gains, zt_globals.rxgain, zt_globals.txgain, ftdmchan->native_codec);
gains.chan_no = ftdmchan->physical_chan_id;
zt_build_gains(&gains, zt_globals.rxgain, zt_globals.txgain, ftdmchan->native_codec);
if(zt_globals.rxgain)
ftdm_log(FTDM_LOG_INFO, "Setting rxgain to %f on channel %d\n", zt_globals.rxgain, gains.chan_no);
if (zt_globals.rxgain)
ftdm_log(FTDM_LOG_INFO, "Setting rxgain to %f on channel %d\n", zt_globals.rxgain, gains.chan_no);
if(zt_globals.txgain)
ftdm_log(FTDM_LOG_INFO, "Setting txgain to %f on channel %d\n", zt_globals.txgain, gains.chan_no);
if (zt_globals.txgain)
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) {
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;
ftdm_log(FTDM_LOG_INFO, "Setting echo cancel to %d taps for %d:%d\n", len, 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 {
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);
}
}
if (zt_globals.eclevel >= 0) {
int len = zt_globals.eclevel;
if (len) {
ftdm_log(FTDM_LOG_INFO, "Setting echo cancel to %d taps for %d:%d\n", len, ftdmchan->span_id, ftdmchan->chan_id);
} else {
ftdm_log(FTDM_LOG_INFO, "Disable echo cancel 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;
@ -1179,7 +1179,7 @@ static FIO_IO_LOAD_FUNCTION(zt_init)
zt_globals.codec_ms = 20;
zt_globals.wink_ms = 150;
zt_globals.flash_ms = 750;
zt_globals.eclevel = 64;
zt_globals.eclevel = 0;
zt_globals.etlevel = 0;
zt_interface.name = "zt";

View File

@ -605,8 +605,8 @@ struct ftdm_channel {
ftdm_hash_t *variable_hash;
unsigned char rx_cas_bits;
uint32_t pre_buffer_size;
unsigned char rxgain_table[FTDM_GAINS_TABLE_SIZE];
unsigned char txgain_table[FTDM_GAINS_TABLE_SIZE];
uint8_t rxgain_table[FTDM_GAINS_TABLE_SIZE];
uint8_t txgain_table[FTDM_GAINS_TABLE_SIZE];
float rxgain;
float txgain;
};
@ -654,7 +654,6 @@ struct ftdm_span {
char *type;
char *dtmf_hangup;
size_t dtmf_hangup_len;
int suggest_chan_id;
ftdm_state_map_t *state_map;
ftdm_caller_data_t default_caller_data;
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(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(void) ftdm_cpu_monitor_disable(void);
FIO_CODEC_FUNCTION(fio_slin2ulaw);
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
#include "fsk.h"
#define FTDM_INVALID_SOCKET -1
#ifdef WIN32
#define FTDM_INVALID_SOCKET INVALID_HANDLE_VALUE
#include <windows.h>
typedef HANDLE ftdm_socket_t;
typedef unsigned __int64 uint64_t;
@ -55,6 +55,7 @@ typedef __int8 int8_t;
typedef intptr_t ftdm_ssize_t;
typedef int ftdm_filehandle_t;
#else
#define FTDM_INVALID_SOCKET -1
#include <stdint.h>
#include <sys/types.h>
#include <sys/ioctl.h>
@ -325,7 +326,9 @@ typedef enum {
FTDM_SPAN_STATE_CHANGE = (1 << 2),
FTDM_SPAN_SUSPENDED = (1 << 3),
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;
typedef enum {

View File

@ -43,8 +43,6 @@
#include "libsangoma.h"
#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*/
#define sangoma_open_tdmapi_span_chan sangoma_open_api_span_chan
#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_NEXT_EVENT_FUNCTION(wanpipe_next_event);
#define WP_INVALID_SOCKET -1
/**
* \brief Poll for event on a wanpipe socket
* \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++) {
zap_channel_t *chan;
zap_socket_t sockfd = WP_INVALID_SOCKET;
zap_socket_t sockfd = ZAP_INVALID_SOCKET;
const char *dtmf = "none";
if (!strncasecmp(span->name, "smg_prid_nfas", 8) && span->trunk_type == ZAP_TRUNK_T1 && x == 24) {
#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);
}
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);
continue;
}
@ -587,29 +583,24 @@ static ZIO_COMMAND_FUNCTION(wanpipe_command)
break;
case ZAP_COMMAND_ENABLE_ECHOCANCEL:
{
#ifndef WINDOWS_BUILD_BROKEN
err=sangoma_tdm_enable_hwec(zchan->sockfd, &tdm_api);
if (err) {
snprintf(zchan->last_error, sizeof(zchan->last_error), "HWEC Enable Failed");
return ZAP_FAIL;
}
#endif /* WINDOWS_BUILD_BROKEN */
}
break;
case ZAP_COMMAND_DISABLE_ECHOCANCEL:
{
#ifndef WINDOWS_BUILD_BROKEN
err=sangoma_tdm_disable_hwec(zchan->sockfd, &tdm_api);
if (err) {
snprintf(zchan->last_error, sizeof(zchan->last_error), "HWEC Disable Failed");
return ZAP_FAIL;
}
#endif /* WINDOWS_BUILD_BROKEN */
}
break;
case ZAP_COMMAND_ENABLE_LOOP:
{
#ifndef WINDOWS_BUILD_BROKEN
#ifdef WP_API_FEATURE_LOOP
err=sangoma_tdm_enable_loop(zchan->sockfd, &tdm_api);
if (err) {
@ -617,11 +608,9 @@ static ZIO_COMMAND_FUNCTION(wanpipe_command)
return ZAP_FAIL;
}
#endif
#endif /* WINDOWS_BUILD_BROKEN */
}
case ZAP_COMMAND_DISABLE_LOOP:
{
#ifndef WINDOWS_BUILD_BROKEN
#ifdef WP_API_FEATURE_LOOP
err=sangoma_tdm_disable_loop(zchan->sockfd, &tdm_api);
if (err) {
@ -629,7 +618,6 @@ static ZIO_COMMAND_FUNCTION(wanpipe_command)
return ZAP_FAIL;
}
#endif
#endif /* WINDOWS_BUILD_BROKEN */
}
case ZAP_COMMAND_SET_INTERVAL:
{
@ -1163,9 +1151,8 @@ static ZIO_CHANNEL_DESTROY_FUNCTION(wanpipe_channel_destroy)
}
#endif
if (zchan->sockfd > -1) {
close(zchan->sockfd);
zchan->sockfd = WP_INVALID_SOCKET;
if (zchan->sockfd != ZAP_INVALID_SOCKET) {
sangoma_close(&zchan->sockfd);
}
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;
}
for (i = size; i < zap_array_len(ints); i++) {
for (i = 0; i < size; i++) {
if (ints[i].revents & POLLIN) {
res = read(ints[0].fd, pipebuf, sizeof(pipebuf));
if (res == -1) {

View File

@ -1,4 +1 @@
.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);
while($socket->recv($data,1024)) {
$data =~ s/^.{8}//;
print $data;
}

View File

@ -13,5 +13,5 @@ $/ = undef;
my $buf = <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 -rf .git
cd ..
tar -czvf $dst_name.tar.gz $dst_dir
tar -cjvf $dst_name.tar.bz2 $dst_dir
tar -cJvf $dst_name.tar.xz $dst_dir || echo tar does not support -J
rm -rf $dst_dir
tar -cvf $dst_name.tar $dst_dir
gzip -9 -c $dst_name.tar > $dst_name.tar.gz || echo "gzip not available"
bzip2 -z -k $dst_name.tar || echo "bzip2 not available"
xz -z -9 -k $dst_name.tar || echo "xz / xz-utils not available"
rm -rf $dst_name.tar $dst_dir
cat 1>&2 <<EOF
----------------------------------------------------------------------

18
src/.gitignore vendored
View File

@ -1,9 +1,9 @@
Makefile
Makefile.in
include/stamp-h1
include/switch_am_config.h
include/switch_private.h
include/switch_private.h.in
include/switch_swigable_cpp.h
include/switch_version.h
include/switch_version.h.in
/Makefile
/Makefile.in
/include/stamp-h1
/include/switch_am_config.h
/include/switch_private.h
/include/switch_private.h.in
/include/switch_swigable_cpp.h
/include/switch_version.h
/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_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)
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

118
src/mod/.gitignore vendored
View File

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

View File

@ -25,7 +25,7 @@
*
* 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;
switch_core_flag_t cflags = switch_core_flags();
switch_status_t status = SWITCH_STATUS_SUCCESS;
char hostname[256] = "";
gethostname(hostname, sizeof(hostname));
if (switch_core_db_handle(&db) != SWITCH_STATUS_SUCCESS) {
stream->write_function(stream, "%s", "-ERR Databse Error!\n");
@ -3283,29 +3285,30 @@ SWITCH_STANDARD_API(show_function)
if (end_of(command) == 's') {
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)) {
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 {
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")) {
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")) {
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")) {
sprintf(sql, "select * from %s", command);
sprintf(sql, "select * from %s where hostname='%s'", command, hostname);
} else if (!strcasecmp(command, "application") || !strcasecmp(command, "api")) {
if (argv[1] && strcasecmp(argv[1], "as")) {
sprintf(sql,
"select name, description, syntax, ikey from interfaces where type = '%s' and description != '' and name = '%s' order by type,name",
command, argv[1]);
"select name, description, syntax, ikey from interfaces where hostname='%s' and type = '%s' and description != '' and name = '%s' order by type,name",
hostname, command, argv[1]);
} 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")) {
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")) {
holder.justcount = 1;
if (argv[3] && !strcasecmp(argv[2], "as")) {
@ -3322,12 +3325,12 @@ SWITCH_STANDARD_API(show_function)
}
if (strchr(argv[2], '%')) {
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",
argv[2], argv[2], argv[2], argv[2]);
"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",
hostname, argv[2], argv[2], argv[2], argv[2]);
} else {
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",
argv[2], argv[2], argv[2], argv[2]);
"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",
hostname, argv[2], argv[2], argv[2], argv[2]);
}
@ -3335,10 +3338,10 @@ SWITCH_STANDARD_API(show_function)
as = argv[4];
}
} 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")) {
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")) {
holder.justcount = 1;
if (argv[3] && !strcasecmp(argv[2], "as")) {
@ -3347,14 +3350,14 @@ SWITCH_STANDARD_API(show_function)
}
} else if (!strcasecmp(command, "distinct_channels")) {
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")) {
as = argv[2];
}
} 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")) {
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)) {
char *cmdname = NULL;
@ -3363,9 +3366,10 @@ SWITCH_STANDARD_API(show_function)
if ((cmdname = strchr(command, ' ')) && strcasecmp(cmdname, "as")) {
*cmdname++ = '\0';
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 {
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")) {
switch_snprintf(sql, sizeof(sql) - 1,
@ -3373,7 +3377,7 @@ SWITCH_STANDARD_API(show_function)
" CASE proto "
" WHEN 0 THEN 'udp' "
" 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 {
stream->write_function(stream, "-USAGE: %s\n", SHOW_SYNTAX);
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
mod_LTLIBRARIES = mod_skypopen.la
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_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;
add_timer(&giovatimer);
spin_lock_bh(&giovalock);
//spin_lock_bh(&giovalock);
for (i = 0; i < giovaindex + 1; i++) {
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(&giovalock);
//spin_unlock_bh(&giovalock);
for (i = 0; i < giovaindex + 1; i++) {
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.expires = 1 + jiffies;
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);
}

View File

@ -151,6 +151,7 @@ static struct {
char *report_incoming_chatmessages;
char *silent_mode;
char *write_silence_when_idle;
char *setsockopt;
int calls;
int real_interfaces;
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_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_setsockopt, globals.setsockopt);
static switch_status_t interface_exists(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")) {
set_global_write_silence_when_idle(val);
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 *silent_mode = "false";
char *write_silence_when_idle = "true";
char *setsockopt = "false";
uint32_t interface_id = 0;
if(globals.context)
@ -1277,6 +1283,8 @@ static switch_status_t load_config(int reload_type)
silent_mode=globals.silent_mode;
if(globals.write_silence_when_idle)
write_silence_when_idle=globals.write_silence_when_idle;
if(globals.setsockopt)
setsockopt=globals.setsockopt;
tech_pvt = NULL;
@ -1298,6 +1306,8 @@ static switch_status_t load_config(int reload_type)
silent_mode = val;
} else if (!strcasecmp(var, "write_silence_when_idle")) {
write_silence_when_idle = val;
} else if (!strcasecmp(var, "setsockopt")) {
setsockopt = val;
} else if (!strcasecmp(var, "X11-display") || !strcasecmp(var, "X11_display")) {
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",
SKYPOPEN_P_LOG, interface_id, globals.SKYPOPEN_INTERFACES[interface_id].name);
DEBUGA_SKYPE
@ -1423,6 +1440,9 @@ static switch_status_t load_config(int reload_type)
DEBUGA_SKYPE
("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);
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);
@ -1532,6 +1552,7 @@ static switch_status_t load_config(int reload_type)
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].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.silent_mode);
switch_safe_free(globals.write_silence_when_idle);
switch_safe_free(globals.setsockopt);
return SWITCH_STATUS_SUCCESS;
}

View File

@ -287,6 +287,7 @@ struct private_object {
switch_buffer_t *read_buffer;
int silent_mode;
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;
#endif //WIN32
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;
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;
#endif //WIN32
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;
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);
DEBUGA_SKYPE("TCP_NODELAY is %d\n", SKYPOPEN_P_LOG, flag);
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;
getsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, &size);
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 win = -1;
int xfd;
fd_set xfds;
if (!strlen(tech_pvt->X11_display))
strcpy(tech_pvt->X11_display, getenv("DISPLAY"));
@ -1623,6 +1630,7 @@ void *skypopen_do_skypeapi_thread_func(void *obj)
int i;
int continue_is_broken = 0;
int there_were_continues = 0;
struct timeval tv;
Atom atom_begin = XInternAtom(disp, "SKYPECONTROLAPI_MESSAGE_BEGIN", False);
Atom atom_continue = XInternAtom(disp, "SKYPECONTROLAPI_MESSAGE", False);
@ -1631,6 +1639,22 @@ void *skypopen_do_skypeapi_thread_func(void *obj)
b = buffer;
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);
if (!(running && tech_pvt->running))
break;
@ -1664,7 +1688,7 @@ void *skypopen_do_skypeapi_thread_func(void *obj)
}
if (an_event.xclient.message_type == atom_continue) {
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",
SKYPOPEN_P_LOG, buf);
strcat(continuebuffer, buf);
@ -1703,8 +1727,16 @@ void *skypopen_do_skypeapi_thread_func(void *obj)
default:
skypopen_sleep(1000); //0.1 msec
break;
}
}
} //switch event.type
} //while XPending
} // if select
} //while running
}
} else {
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;
uint32_t key_count;
char hostname[80];
uint64_t host_hash;
switch_port_t port;
switch_sockaddr_t *addr;
switch_socket_t *udp_socket;
@ -295,36 +294,35 @@ static void event_handler(switch_event_t *event)
switch_uuid_get(&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
len = strlen(packet) + sizeof(globals.host_hash) + strlen((char *) MAGIC);
len = strlen(packet) + strlen((char *) MAGIC);
#endif
buf = malloc(len + 1);
memset(buf, 0, len + 1);
switch_assert(buf);
memcpy(buf, &globals.host_hash, sizeof(globals.host_hash));
#ifdef HAVE_OPENSSL
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_EncryptInit(&ctx, EVP_bf_cbc(), NULL, NULL);
EVP_CIPHER_CTX_set_key_length(&ctx, strlen(globals.psk));
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));
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));
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;
len = (size_t) outlen + sizeof(globals.host_hash) + SWITCH_UUID_FORMATTED_LENGTH;
*(buf + sizeof(globals.host_hash) + SWITCH_UUID_FORMATTED_LENGTH + outlen) = '\0';
len = (size_t) outlen + SWITCH_UUID_FORMATTED_LENGTH;
*(buf + SWITCH_UUID_FORMATTED_LENGTH + outlen) = '\0';
} else {
#endif
switch_copy_string(buf + sizeof(globals.host_hash), packet, len - sizeof(globals.host_hash));
switch_copy_string(buf + sizeof(globals.host_hash) + strlen(packet), (char *) MAGIC, strlen((char *) MAGIC) + 1);
switch_copy_string(buf, packet, len);
switch_copy_string(buf + strlen(packet), (char *) MAGIC, strlen((char *) MAGIC) + 1);
#ifdef HAVE_OPENSSL
}
#endif
@ -369,7 +367,6 @@ SWITCH_STANDARD_API(multicast_peers)
SWITCH_MODULE_LOAD_FUNCTION(mod_event_multicast_load)
{
switch_api_interface_t *api_interface;
switch_ssize_t hlen = -1;
switch_status_t status = SWITCH_STATUS_GENERR;
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);
gethostname(globals.hostname, sizeof(globals.hostname));
globals.host_hash = switch_hashfunc_default(globals.hostname, &hlen);
globals.key_count = 0;
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);
}
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) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Bind Error\n");
switch_goto_status(SWITCH_STATUS_TERM, fail);
@ -501,7 +502,6 @@ SWITCH_MODULE_RUNTIME_FUNCTION(mod_event_multicast_runtime)
char *myaddr;
size_t len = MULTICAST_BUFFSIZE;
char *packet;
uint64_t host_hash = 0;
switch_status_t status;
memset(buf, 0, len);
@ -520,12 +520,8 @@ SWITCH_MODULE_RUNTIME_FUNCTION(mod_event_multicast_runtime)
}
#endif
memcpy(&host_hash, buf, sizeof(host_hash));
packet = buf + sizeof(host_hash);
packet = buf;
if (host_hash == globals.host_hash) {
continue;
}
#ifdef HAVE_OPENSSL
if (globals.psk) {
char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
@ -533,7 +529,7 @@ SWITCH_MODULE_RUNTIME_FUNCTION(mod_event_multicast_runtime)
int outl, tmplen;
EVP_CIPHER_CTX ctx;
len -= sizeof(host_hash) + SWITCH_UUID_FORMATTED_LENGTH;
len -= SWITCH_UUID_FORMATTED_LENGTH;
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);
}
SWITCH_DECLARE(switch_status_t) switch_mcast_loopback(switch_socket_t *sock, uint8_t opt)
{
return apr_mcast_loopback(sock, opt);
}
/* socket functions */

View File

@ -737,34 +737,49 @@ SWITCH_DECLARE(switch_status_t) switch_channel_set_profile_var(switch_channel_t
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;
switch_status_t status;
const char *exports;
switch_status_t status = SWITCH_STATUS_FALSE;
exports = switch_channel_get_variable(channel, SWITCH_EXPORT_VARS_VARIABLE);
if (nolocal) {
exports_varname = switch_mprintf("nolocal:%s", varname);
}
if ((status = switch_channel_set_variable_var_check(channel, exports_varname, value, var_check)) != SWITCH_STATUS_SUCCESS) {
goto done;
if ((status = switch_channel_set_variable_var_check(channel, varname, value, var_check)) != SWITCH_STATUS_SUCCESS) {
return status;
}
if (varname && value) {
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 {
switch_channel_set_variable(channel, SWITCH_EXPORT_VARS_VARIABLE, exports_varname);
switch_channel_set_variable(channel, SWITCH_EXPORT_VARS_VARIABLE, varname);
}
}
done:
if (exports_varname != varname) {
free((char*)exports_varname);
return status;
}
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;
}

View File

@ -304,6 +304,7 @@ static int switch_console_process(char *xcmd)
switch_stream_handle_t stream = { 0 };
switch_status_t status;
FILE *handle = switch_core_get_console();
int r = 1;
SWITCH_STANDARD_STREAM(stream);
switch_assert(stream.data);
@ -316,6 +317,9 @@ static int switch_console_process(char *xcmd)
fflush(handle);
}
} else {
if (!strcasecmp(xcmd, "...") || !strcasecmp(xcmd, "shutdown")) {
r = 0;
}
if (handle) {
fprintf(handle, "Unknown Command: %s\n", xcmd);
fflush(handle);
@ -324,7 +328,7 @@ static int switch_console_process(char *xcmd)
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_hash_index_t *hi;
void *val;
switch_core_session_t *session;
switch_memory_pool_t *pool;
switch_queue_t *queue;
void *pop;
struct str_node *head = NULL, *np;
switch_core_new_memory_pool(&pool);
switch_queue_create(&queue, 250000, pool);
if (!var_val)
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_channel_up(session->channel) &&
(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);
}
@ -160,10 +166,8 @@ SWITCH_DECLARE(void) switch_core_session_hupall_matching_var(const char *var_nam
}
switch_mutex_unlock(runtime.session_hash_mutex);
while (switch_queue_trypop(queue, &pop) == SWITCH_STATUS_SUCCESS && pop) {
char *uuid = (char *) pop;
if ((session = switch_core_session_locate(uuid))) {
for(np = head; np; np = np->next) {
if ((session = switch_core_session_locate(np->str))) {
switch_channel_hangup(session->channel, cause);
switch_core_session_rwunlock(session);
}
@ -179,12 +183,10 @@ SWITCH_DECLARE(void) switch_core_session_hupall_endpoint(const switch_endpoint_i
void *val;
switch_core_session_t *session;
switch_memory_pool_t *pool;
switch_queue_t *queue;
void *pop;
struct str_node *head = NULL, *np;
switch_core_new_memory_pool(&pool);
switch_queue_create(&queue, 250000, pool);
switch_mutex_lock(runtime.session_hash_mutex);
for (hi = switch_hash_first(NULL, session_manager.session_table); hi; hi = switch_hash_next(hi)) {
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;
if (switch_core_session_read_lock(session) == SWITCH_STATUS_SUCCESS) {
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);
}
@ -200,10 +205,8 @@ SWITCH_DECLARE(void) switch_core_session_hupall_endpoint(const switch_endpoint_i
}
switch_mutex_unlock(runtime.session_hash_mutex);
while (switch_queue_trypop(queue, &pop) == SWITCH_STATUS_SUCCESS && pop) {
char *uuid = (char *) pop;
if ((session = switch_core_session_locate(uuid))) {
for(np = head; np; np = np->next) {
if ((session = switch_core_session_locate(np->str))) {
switch_channel_hangup(session->channel, cause);
switch_core_session_rwunlock(session);
}
@ -219,11 +222,10 @@ SWITCH_DECLARE(void) switch_core_session_hupall(switch_call_cause_t cause)
void *val;
switch_core_session_t *session;
switch_memory_pool_t *pool;
switch_queue_t *queue;
void *pop;
struct str_node *head = NULL, *np;
switch_core_new_memory_pool(&pool);
switch_queue_create(&queue, 250000, pool);
switch_mutex_lock(runtime.session_hash_mutex);
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) {
session = (switch_core_session_t *) val;
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_mutex_unlock(runtime.session_hash_mutex);
while (switch_queue_trypop(queue, &pop) == SWITCH_STATUS_SUCCESS && pop) {
char *uuid = (char *) pop;
if ((session = switch_core_session_locate(uuid))) {
for(np = head; np; np = np->next) {
if ((session = switch_core_session_locate(np->str))) {
switch_channel_hangup(session->channel, cause);
switch_core_session_rwunlock(session);
}

View File

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