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

This commit is contained in:
Giovanni 2010-04-06 17:55:58 +02:00
commit 1d993d3aa2
90 changed files with 5353 additions and 3410 deletions

89
.gitignore vendored
View File

@ -8,36 +8,65 @@
.deps .deps
.\#* .\#*
\#* \#*
.version /Debug/
AUTHORS /Release/
COPYING /All/
ChangeLog /bin/
Makefile *.user
Makefile.in *.suo
NEWS *.ncb
README *.pdb
*.map
*.lib
*.obj
*.idb
*.res
*.exp
*.exe
*.manifest
*.dep
*.dll
/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 aclocal.m4
build/Makefile autom4te.cache
build/Makefile.in /build/Makefile
build/config/compile /build/Makefile.in
build/config/config.guess /build/config/compile
build/config/depcomp /build/config/config.guess
build/config/install-sh /build/config/depcomp
build/config/ltmain.sh /build/config/install-sh
build/config/missing /build/config/ltmain.sh
build/freeswitch.pc /build/config/missing
build/getlib.sh /build/freeswitch.pc
build/getsounds.sh /build/getlib.sh
build/modmake.rules /build/getsounds.sh
/build/modmake.rules
config.cache
config.log config.log
config.status config.status
configure /configure
freeswitch configure.lineno
fs_cli /freeswitch
fs_ivrd /fs_cli
libtool /fs_ivrd
modules.conf /libtool
quiet_libtool /modules.conf
scripts/fsxs /quiet_libtool
scripts/gentls_cert /scripts/fsxs
a.out.dSYM /scripts/gentls_cert
/a.out.dSYM
/freeswitch-sounds-*

View File

@ -349,7 +349,21 @@ src/include/switch_version.h: src/include/switch_version.h.in .version $(libfree
cat src/include/switch_version.h.in > src/include/switch_version.h ; \ cat src/include/switch_version.h.in > src/include/switch_version.h ; \
touch .version ; \ touch .version ; \
else \ else \
version=`svnversion . -n || echo hacked` ; \ if [ -d .git ] ; then \
version=`git log --format="%h %ci" -1 HEAD | head -1 || echo hacked` ; \
if [ "x$$version" == "xhacked" ] ; then \
version="hacked-`date -u +%Y%m%dT%H%M%SZ`" ; \
else \
version="git-$$version" ; \
fi ;\
else \
version=`svnversion . -n || echo hacked` ; \
if [ "x$$version" == "xhacked" ] ; then \
version="hacked-`date -u +%Y%m%dT%H%M%SZ`" ; \
else \
version="svn-$$version" ; \
fi ;\
fi ; \
oldversion=`cat .version 2>/dev/null || echo "0"` ; \ oldversion=`cat .version 2>/dev/null || echo "0"` ; \
if test "$$oldversion" != "$$version" || test $$force = 1 ; then \ if test "$$oldversion" != "$$version" || test $$force = 1 ; then \
cat src/include/switch_version.h.in | sed "s/@SWITCH_VERSION_REVISION@/$$version/g" > src/include/switch_version.h ; \ cat src/include/switch_version.h.in | sed "s/@SWITCH_VERSION_REVISION@/$$version/g" > src/include/switch_version.h ; \
@ -437,23 +451,30 @@ install-data-local:
test -d $(DESTDIR)$(sysconfdir) || $(MAKE) samples-conf test -d $(DESTDIR)$(sysconfdir) || $(MAKE) samples-conf
test -d $(DESTDIR)$(htdocsdir) || $(MAKE) samples-htdocs test -d $(DESTDIR)$(htdocsdir) || $(MAKE) samples-htdocs
is-svn: is-scm:
@if [ ! -d .svn ] ; then \ @if [ ! -d .svn -a ! -d .git ] ; then \
echo ; echo ; \ echo ; echo ; \
echo "**************************************************************************************************" ; \ echo "*****************************************************************************************************" ; \
echo "You can not update a release tarball or without a svn working copy, please checkout fresh from svn" ; \ echo "You can not update a release tarball or without a git or svn working copy please clone our git tree: " ; \
echo "**************************************************************************************************" ; \ echo "git clone git://git.freeswitch.org/freeswitch.git " ; \
echo "or check out our read only svn mirror: " ; \
echo "svn checkout http://svn.freeswitch.org/svn/freeswitch/trunk " ; \
echo "*****************************************************************************************************" ; \
echo ; echo ; \ echo ; echo ; \
exit 1; \ exit 1; \
fi fi
update: is-svn update: is-scm
@if test -d .svn ; then \ @if test -d .svn ; then \
test ! -f .version || rm -f .version ; \ test ! -f .version || rm -f .version ; \
echo Updating... ; \ echo Updating... ; \
svn update ; \ svn update ; \
elif test -d .git ; then \
test ! -f .version || rm -f .version ; \
echo "Pulling updates..." ; \
git pull ; \
else \ else \
echo "This source directory is not an svn working copy" ; \ echo "This source directory is not a git tree or svn working copy" ; \
fi fi
.nodepends: .nodepends:
@ -483,18 +504,18 @@ core_install: install_core
everything: install everything: install
up: is-svn clean up: is-scm clean
svn update $(MAKE) update
$(MAKE) -j core $(MAKE) -j core
$(MAKE) -j modules $(MAKE) -j modules
$(MAKE) install $(MAKE) install
sync: is-svn sync: is-scm
svn update $(MAKE) update
$(MAKE) install $(MAKE) install
speedy-sync: is-svn speedy-sync: is-scm
svn update $(MAKE) update
$(MAKE) -j install $(MAKE) -j install
libs/openzap/Makefile: libs/openzap/Makefile:
@ -570,15 +591,15 @@ cluecon:
@echo @echo
@echo http://www.cluecon.com @echo http://www.cluecon.com
@sleep 5 @sleep 5
current: cluecon is-svn update-clean current: cluecon update-clean is-scm
svn update $(MAKE) update
$(MAKE) all $(MAKE) all
$(MAKE) install $(MAKE) install
installall: current installall: current
speedy-current: is-svn update-clean speedy-current: update-clean is-scm
svn update $(MAKE) update
$(MAKE) speedy-sure $(MAKE) speedy-sure
$(MAKE) install $(MAKE) install

View File

@ -1,6 +1,6 @@
cd src/mod/languages/mod_lua cd src/mod/languages/mod_lua
make swigclean make swigclean
make mod_lua_wrap.cpp make lua_wrap
cd ../../../.. cd ../../../..
cd src/mod/languages/mod_perl cd src/mod/languages/mod_perl

View File

@ -3,11 +3,11 @@
# Must change all of the below together # Must change all of the below together
# For a release, set revision for that tagged release as well and uncomment # For a release, set revision for that tagged release as well and uncomment
AC_INIT([freeswitch], [1.0.trunk], BUG-REPORT-ADDRESS) AC_INIT([freeswitch], [1.0.head], BUG-REPORT-ADDRESS)
AC_SUBST(SWITCH_VERSION_MAJOR, [1]) AC_SUBST(SWITCH_VERSION_MAJOR, [1])
AC_SUBST(SWITCH_VERSION_MINOR, [0]) AC_SUBST(SWITCH_VERSION_MINOR, [0])
AC_SUBST(SWITCH_VERSION_MICRO, [trunk]) AC_SUBST(SWITCH_VERSION_MICRO, [head])
#AC_SUBST(SWITCH_VERSION_REVISION, [svn-revision-here]) #AC_SUBST(SWITCH_VERSION_REVISION, [])
AC_CONFIG_FILES([src/include/switch_version.h.in:src/include/switch_version.h.template]) AC_CONFIG_FILES([src/include/switch_version.h.in:src/include/switch_version.h.template])
AC_CONFIG_FILES([.version:.version.in]) AC_CONFIG_FILES([.version:.version.in])

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,9 @@ SOURCES += main.cpp \
preferences/prefsofia.cpp \ preferences/prefsofia.cpp \
preferences/accountdialog.cpp \ preferences/accountdialog.cpp \
preferences/prefaccounts.cpp \ preferences/prefaccounts.cpp \
account.cpp account.cpp \
widgets/codecwidget.cpp \
channel.cpp
HEADERS += mainwindow.h \ HEADERS += mainwindow.h \
fshost.h \ fshost.h \
call.h \ call.h \
@ -41,9 +43,12 @@ HEADERS += mainwindow.h \
preferences/prefsofia.h \ preferences/prefsofia.h \
preferences/accountdialog.h \ preferences/accountdialog.h \
preferences/prefaccounts.h \ preferences/prefaccounts.h \
account.h account.h \
widgets/codecwidget.h \
channel.h
FORMS += mainwindow.ui \ FORMS += mainwindow.ui \
preferences/prefdialog.ui \ preferences/prefdialog.ui \
preferences/accountdialog.ui preferences/accountdialog.ui \
widgets/codecwidget.ui
RESOURCES += resources.qrc RESOURCES += resources.qrc
OTHER_FILES += conf/freeswitch.xml OTHER_FILES += conf/freeswitch.xml

View File

@ -33,16 +33,7 @@
Call::Call() 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)
{
_isActive = false;
} }
switch_status_t Call::toggleRecord(bool startRecord) switch_status_t Call::toggleRecord(bool startRecord)
@ -56,14 +47,14 @@ switch_status_t Call::toggleRecord(bool startRecord)
_recording_filename = QString("%1/.fscomm/recordings/%2_%3.wav").arg( _recording_filename = QString("%1/.fscomm/recordings/%2_%3.wav").arg(
conf_dir.absolutePath(), conf_dir.absolutePath(),
QDateTime::currentDateTime().toString("yyyyMMddhhmmss"), QDateTime::currentDateTime().toString("yyyyMMddhhmmss"),
_cid_number); getCidNumber());
status = g_FSHost.sendCmd("uuid_record", QString("%1 start %2").arg(_uuid, _recording_filename).toAscii().data(),&result); status = g_FSHost.sendCmd("uuid_record", QString("%1 start %2").arg(getUuid(), _recording_filename).toAscii().data(),&result);
} }
else else
{ {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Stopping call recording on call [%s]\n", switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Stopping call recording on call [%s]\n",
_uuid.toAscii().data()); getUuid().toAscii().data());
status = g_FSHost.sendCmd("uuid_record", QString("%1 stop %2").arg(_uuid, _recording_filename).toAscii().data(),&result); status = g_FSHost.sendCmd("uuid_record", QString("%1 stop %2").arg(getUuid(), _recording_filename).toAscii().data(),&result);
} }
return status; return status;
@ -74,13 +65,30 @@ void Call::sendDTMF(QString digit)
QString result; QString result;
QString dtmf_string = QString("dtmf %1").arg(digit); QString dtmf_string = QString("dtmf %1").arg(digit);
if (g_FSHost.sendCmd("pa", dtmf_string.toAscii(), &result) == SWITCH_STATUS_FALSE) { if (g_FSHost.sendCmd("pa", dtmf_string.toAscii(), &result) == SWITCH_STATUS_FALSE) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not send DTMF digit %s on call[%s]", digit.toAscii().data(), _uuid.toAscii().data()); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not send DTMF digit %s on call[%s]", digit.toAscii().data(), getUuid().toAscii().data());
QMessageBox::critical(0, QWidget::tr("DTMF Error"), QWidget::tr("There was an error sending DTMF, please report this bug."), QMessageBox::Ok); QMessageBox::critical(0, QWidget::tr("DTMF Error"), QWidget::tr("There was an error sending DTMF, please report this bug."), QMessageBox::Ok);
} }
} }
QTime Call::getCurrentStateTime() QTime Call::getCurrentStateTime()
{ {
int now = QDateTime::fromTime_t(_answered_epoch).secsTo(QDateTime::currentDateTime()); qulonglong time = 0;
if (_state == FSCOMM_CALL_STATE_ANSWERED)
{
time = _answeredEpoch;
}
else if(_state == FSCOMM_CALL_STATE_RINGING)
{
if (_direction == FSCOMM_CALL_DIRECTION_INBOUND)
{
/* TODO: DOESNT WORK - How do I get what time it started to ring? */
_channel.data()->getProgressEpoch() == 0 ? time = _channel.data()->getProgressMediaEpoch() : time = _channel.data()->getProgressEpoch();
}
else
_otherLegChannel.data()->getProgressEpoch() == 0 ? time = _otherLegChannel.data()->getProgressMediaEpoch() : time = _otherLegChannel.data()->getProgressEpoch();
}
int now = QDateTime::fromTime_t(time).secsTo(QDateTime::currentDateTime());
return QTime::fromString(QString::number(now), "s"); return QTime::fromString(QString::number(now), "s");
} }

View File

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

8
fscomm/channel.cpp Normal file
View File

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

39
fscomm/channel.h Normal file
View File

@ -0,0 +1,39 @@
#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; }
private:
QString _uuid;
QString _cidName;
QString _cidNumber;
QString _destinationNumber;
int _paCallId;
qulonglong _progressEpoch;
qulonglong _progressMediaEpoch;
};
Q_DECLARE_METATYPE(Channel)
#endif // CHANNEL_H

View File

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

View File

@ -43,9 +43,10 @@ FSHost::FSHost(QObject *parent) :
switch_core_set_globals(); switch_core_set_globals();
qRegisterMetaType<QSharedPointer<Call> >("QSharedPointer<Call>"); qRegisterMetaType<QSharedPointer<Call> >("QSharedPointer<Call>");
qRegisterMetaType<QSharedPointer<Call> >("QSharedPointer<Channel>");
qRegisterMetaType<QSharedPointer<Account> >("QSharedPointer<Account>"); qRegisterMetaType<QSharedPointer<Account> >("QSharedPointer<Account>");
connect(this, SIGNAL(loadedModule(QString,QString,QString)), this, SLOT(minimalModuleLoaded(QString,QString,QString))); connect(this, SIGNAL(loadedModule(QString,QString)), this, SLOT(minimalModuleLoaded(QString,QString)));
} }
@ -167,261 +168,170 @@ void FSHost::run(void)
} }
} }
switch_status_t FSHost::processAlegEvent(switch_event_t * event, QString uuid) void FSHost::generalEventHandler(QSharedPointer<switch_event_t>event)
{ {
switch_status_t status = SWITCH_STATUS_SUCCESS; QString uuid = switch_event_get_header_nil(event.data(), "Unique-ID");
QSharedPointer<Call> call = _active_calls.value(uuid);
if (call.isNull()) switch(event.data()->event_id) {
{ case SWITCH_EVENT_CHANNEL_CREATE: /*1A - 17B*/
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "We don't have a call object for A leg on event %s.\n", switch_event_name(event->event_id));
qDebug() << _active_calls.keys();
printEventHeaders(event);
return SWITCH_STATUS_FALSE;
}
/* Inbound call */
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)
{ {
case SWITCH_EVENT_CHANNEL_BRIDGE: eventChannelCreate(event, uuid);
{
_active_calls.value(uuid).data()->setbUUID(switch_event_get_header_nil(event, "Other-Leg-Unique-ID"));
_bleg_uuids.insert(switch_event_get_header_nil(event, "Other-Leg-Unique-ID"), uuid);
break;
}
case SWITCH_EVENT_CHANNEL_HANGUP_COMPLETE:
{
if (call.data()->getState() == FSCOMM_CALL_STATE_TRYING)
{
QString cause = switch_event_get_header_nil(event, "Hangup-Cause");
call.data()->setState(FSCOMM_CALL_STATE_FAILED);
call.data()->setCause(cause);
emit callFailed(call);
_active_calls.take(uuid);
}
break;
}
default:
qDebug() << QString("A leg: %1(%2)\n").arg(switch_event_name(event->event_id), switch_event_get_header_nil(event, "Event-Subclass"));
break; break;
} }
} case SWITCH_EVENT_CHANNEL_ANSWER: /*2A - 31B*/
return status;
}
switch_status_t FSHost::processBlegEvent(switch_event_t * event, QString buuid)
{
QString uuid = _bleg_uuids.value(buuid);
switch_status_t status = SWITCH_STATUS_SUCCESS;
QSharedPointer<Call> call = _active_calls.value(uuid);
if (call.isNull())
{
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "We don't have a call object for B leg on event %s.\n", switch_event_name(event->event_id));
qDebug() << _active_calls.keys();
printEventHeaders(event);
return SWITCH_STATUS_FALSE;
}
/* Inbound call */
if (call.data()->getDirection() == FSCOMM_CALL_DIRECTION_INBOUND)
{
qDebug() << " Inbound call";
}
/* Outbound call */
else
{
switch(event->event_id)
{ {
case SWITCH_EVENT_CHANNEL_ANSWER: eventChannelAnswer(event, uuid);
{
/* When do we get here? */
QString answeredEpoch = switch_event_get_header_nil(event, "Caller-Channel-Answered-Time");
call.data()->setAnsweredEpoch(answeredEpoch.toULongLong());
emit answered(call);
break;
}
case SWITCH_EVENT_CHANNEL_HANGUP_COMPLETE:
{
_active_calls.take(uuid);
emit hungup(call);
_bleg_uuids.take(buuid);
break;
}
case SWITCH_EVENT_CHANNEL_STATE:
{
if (QString(switch_event_get_header_nil(event, "Answer-State")) == "early")
{
call.data()->setState(FSCOMM_CALL_STATE_RINGING);
emit ringing(call);
}
else if (QString(switch_event_get_header_nil(event, "Answer-State")) == "answered")
{
call.data()->setState(FSCOMM_CALL_STATE_ANSWERED);
emit answered(call);
}
break;
}
default:
qDebug() << QString("B leg: %1(%2)\n").arg(switch_event_name(event->event_id), switch_event_get_header_nil(event, "Event-Subclass"));
break; break;
} }
} case SWITCH_EVENT_CODEC:/*3/4A - 24/25B*/
return status;
}
void FSHost::generalEventHandler(switch_event_t *event)
{
/*printEventHeaders(event);*/
QString uuid = switch_event_get_header_nil(event, "Unique-ID");
if (_bleg_uuids.contains(uuid))
{
if (processBlegEvent(event, uuid) == SWITCH_STATUS_SUCCESS)
{ {
return; eventCodec(event, uuid);
break;
} }
} case SWITCH_EVENT_CHANNEL_STATE:/*6/7/8/37/44/46A - 20/21/22/28/38/40/42B*/
if (_active_calls.contains(uuid))
{
if (processAlegEvent(event, uuid) == SWITCH_STATUS_SUCCESS)
{ {
return; eventChannelState(event, uuid);
break;
} }
} case SWITCH_EVENT_CHANNEL_EXECUTE:/*9/11/13/15A*/
/* This is how we identify new calls, inbound and outbound */
switch(event->event_id) {
case SWITCH_EVENT_CUSTOM:
{ {
if (strcmp(event->subclass_name, "portaudio::ringing") == 0 && !_active_calls.contains(uuid)) eventChannelExecute(event, uuid);
break;
}
case SWITCH_EVENT_CHANNEL_EXECUTE_COMPLETE:/*10/12/14/16/35A*/
{
eventChannelExecuteComplete(event, uuid);
break;
}
case SWITCH_EVENT_CHANNEL_OUTGOING:/*18B*/
{
eventChannelOutgoing(event, uuid);
break;
}
case SWITCH_EVENT_CHANNEL_ORIGINATE:/*19B*/
{
eventChannelOriginate(event, uuid);
break;
}
case SWITCH_EVENT_CALL_UPDATE:/*23/29/30B*/
{
eventCallUpdate(event, uuid);
break;
}
case SWITCH_EVENT_CHANNEL_PROGRESS:
{
eventChannelProgress(event, uuid);
break;
}
case SWITCH_EVENT_CHANNEL_PROGRESS_MEDIA:/*26B*/
{
eventChannelProgressMedia(event, uuid);
break;
}
case SWITCH_EVENT_CHANNEL_BRIDGE:/*27A*/
{
eventChannelBridge(event, uuid);
break;
}
/*32?*/
/*case SWITCH_EVENT_RECV_INFO:
{
eventRecvInfo(event, uuid);
break;
}*/
case SWITCH_EVENT_CHANNEL_HANGUP:/*36A-33B*/
{
eventChannelHangup(event, uuid);
break;
}
case SWITCH_EVENT_CHANNEL_UNBRIDGE:/*34A*/
{
eventChannelUnbridge(event, uuid);
break;
}
case SWITCH_EVENT_CHANNEL_HANGUP_COMPLETE:/*39/43B*/
{
eventChannelHangupComplete(event, uuid);
break;
}
case SWITCH_EVENT_CHANNEL_DESTROY:/*45A-41B*/
{
eventChannelDestroy(event, uuid);
break;
}
case SWITCH_EVENT_CUSTOM:/*5A*/
{
if (strcmp(event.data()->subclass_name, "sofia::gateway_state") == 0)
{ {
Call *callPtr = new Call(atoi(switch_event_get_header_nil(event, "call_id")), QString state = switch_event_get_header_nil(event.data(), "State");
switch_event_get_header_nil(event, "Caller-Caller-ID-Name"), QString gw = switch_event_get_header_nil(event.data(), "Gateway");
switch_event_get_header_nil(event, "Caller-Caller-ID-Number"),
FSCOMM_CALL_DIRECTION_INBOUND,
uuid);
QSharedPointer<Call> call(callPtr);
_active_calls.insert(uuid, call);
call.data()->setState(FSCOMM_CALL_STATE_RINGING);
emit ringing(call);
}
else if (strcmp(event->subclass_name, "portaudio::makecall") == 0)
{
Call *callPtr = new Call(atoi(switch_event_get_header_nil(event, "call_id")),NULL,
switch_event_get_header_nil(event, "Caller-Destination-Number"),
FSCOMM_CALL_DIRECTION_OUTBOUND,
uuid);
QSharedPointer<Call> call(callPtr);
_active_calls.insert(uuid, call);
call.data()->setState(FSCOMM_CALL_STATE_TRYING);
emit newOutgoingCall(call);
}
else if (strcmp(event->subclass_name, "sofia::gateway_state") == 0)
{
QString state = switch_event_get_header_nil(event, "State");
QString gw = switch_event_get_header_nil(event, "Gateway");
QSharedPointer<Account> acc = _accounts.value(gw); QSharedPointer<Account> acc = _accounts.value(gw);
if (acc.isNull()) if (acc.isNull())
return; return;
if (state == "TRYING") { if (state == "TRYING") {
acc.data()->setStatusPhrase(switch_event_get_header_nil(event, "Phrase")); acc.data()->setStatusPhrase(switch_event_get_header_nil(event.data(), "Phrase"));
acc.data()->setState(FSCOMM_GW_STATE_TRYING); acc.data()->setState(FSCOMM_GW_STATE_TRYING);
emit accountStateChange(acc); emit accountStateChange(acc);
} else if (state == "REGISTER") { } else if (state == "REGISTER") {
acc.data()->setStatusPhrase(switch_event_get_header_nil(event, "Phrase")); acc.data()->setStatusPhrase(switch_event_get_header_nil(event.data(), "Phrase"));
acc.data()->setState(FSCOMM_GW_STATE_REGISTER); acc.data()->setState(FSCOMM_GW_STATE_REGISTER);
emit accountStateChange(acc); emit accountStateChange(acc);
} else if (state == "REGED") { } else if (state == "REGED") {
acc.data()->setStatusPhrase(switch_event_get_header_nil(event, "Phrase")); acc.data()->setStatusPhrase(switch_event_get_header_nil(event.data(), "Phrase"));
acc.data()->setState(FSCOMM_GW_STATE_REGED); acc.data()->setState(FSCOMM_GW_STATE_REGED);
emit accountStateChange(acc); emit accountStateChange(acc);
} else if (state == "UNREGED") { } else if (state == "UNREGED") {
acc.data()->setStatusPhrase(switch_event_get_header_nil(event, "Phrase")); acc.data()->setStatusPhrase(switch_event_get_header_nil(event.data(), "Phrase"));
acc.data()->setState(FSCOMM_GW_STATE_UNREGED); acc.data()->setState(FSCOMM_GW_STATE_UNREGED);
emit accountStateChange(acc); emit accountStateChange(acc);
} else if (state == "UNREGISTER") { } else if (state == "UNREGISTER") {
acc.data()->setStatusPhrase(switch_event_get_header_nil(event, "Phrase")); acc.data()->setStatusPhrase(switch_event_get_header_nil(event.data(), "Phrase"));
acc.data()->setState(FSCOMM_GW_STATE_UNREGISTER); acc.data()->setState(FSCOMM_GW_STATE_UNREGISTER);
emit accountStateChange(acc); emit accountStateChange(acc);
} else if (state =="FAILED") { } else if (state =="FAILED") {
acc.data()->setStatusPhrase(switch_event_get_header_nil(event, "Phrase")); acc.data()->setStatusPhrase(switch_event_get_header_nil(event.data(), "Phrase"));
acc.data()->setState(FSCOMM_GW_STATE_FAILED); acc.data()->setState(FSCOMM_GW_STATE_FAILED);
emit accountStateChange(acc); emit accountStateChange(acc);
} else if (state == "FAIL_WAIT") { } else if (state == "FAIL_WAIT") {
acc.data()->setState(FSCOMM_GW_STATE_FAIL_WAIT); acc.data()->setState(FSCOMM_GW_STATE_FAIL_WAIT);
emit accountStateChange(acc); emit accountStateChange(acc);
} else if (state == "EXPIRED") { } else if (state == "EXPIRED") {
acc.data()->setStatusPhrase(switch_event_get_header_nil(event, "Phrase")); acc.data()->setStatusPhrase(switch_event_get_header_nil(event.data(), "Phrase"));
acc.data()->setState(FSCOMM_GW_STATE_EXPIRED); acc.data()->setState(FSCOMM_GW_STATE_EXPIRED);
emit accountStateChange(acc); emit accountStateChange(acc);
} else if (state == "NOREG") { } else if (state == "NOREG") {
acc.data()->setStatusPhrase(switch_event_get_header_nil(event, "Phrase")); acc.data()->setStatusPhrase(switch_event_get_header_nil(event.data(), "Phrase"));
acc.data()->setState(FSCOMM_GW_STATE_NOREG); acc.data()->setState(FSCOMM_GW_STATE_NOREG);
emit accountStateChange(acc); emit accountStateChange(acc);
} }
} }
else if (strcmp(event->subclass_name, "sofia::gateway_add") == 0) else if (strcmp(event.data()->subclass_name, "sofia::gateway_add") == 0)
{ {
QString gw = switch_event_get_header_nil(event, "Gateway"); QString gw = switch_event_get_header_nil(event.data(), "Gateway");
Account * accPtr = new Account(gw); Account * accPtr = new Account(gw);
QSharedPointer<Account> acc = QSharedPointer<Account>(accPtr); QSharedPointer<Account> acc = QSharedPointer<Account>(accPtr);
acc.data()->setState(FSCOMM_GW_STATE_NOAVAIL); acc.data()->setState(FSCOMM_GW_STATE_NOAVAIL);
_accounts.insert(gw, acc); _accounts.insert(gw, acc);
emit newAccount(acc); emit newAccount(acc);
} }
else if (strcmp(event->subclass_name, "sofia::gateway_delete") == 0) else if (strcmp(event.data()->subclass_name, "sofia::gateway_delete") == 0)
{ {
QSharedPointer<Account> acc = _accounts.take(switch_event_get_header_nil(event, "Gateway")); QSharedPointer<Account> acc = _accounts.take(switch_event_get_header_nil(event.data(), "Gateway"));
if (!acc.isNull()) if (!acc.isNull())
emit delAccount(acc); emit delAccount(acc);
} }
else else
{ {
printEventHeaders(event); //printEventHeaders(event);
} }
break; break;
} }
case SWITCH_EVENT_MODULE_LOAD: case SWITCH_EVENT_MODULE_LOAD:
{ {
QString modType = switch_event_get_header_nil(event, "type"); QString modType = switch_event_get_header_nil(event.data(), "type");
QString modName = switch_event_get_header_nil(event, "name"); QString modKey = switch_event_get_header_nil(event.data(), "key");
QString modKey = switch_event_get_header_nil(event, "key"); emit loadedModule(modType, modKey);
emit loadedModule(modType, modName, modKey);
break; break;
} }
default: default:
@ -429,7 +339,107 @@ 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(switch_event_get_header_nil(event.data(), "Other-Leg-Unique-ID")));
callPtr->setOtherLegChannel(_channels.value(uuid));
QSharedPointer<Call> call(callPtr);
_active_calls.insert(switch_event_get_header_nil(event.data(), "Other-Leg-Unique-ID"), call);
call.data()->setState(FSCOMM_CALL_STATE_RINGING);
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)
{
if (_active_calls.contains(uuid))
{
emit hungup(_active_calls.take(uuid));
}
}
void FSHost::eventChannelUnbridge(QSharedPointer<switch_event_t>event, QString uuid)
{}
void FSHost::eventChannelHangupComplete(QSharedPointer<switch_event_t>event, QString uuid)
{}
void FSHost::eventChannelDestroy(QSharedPointer<switch_event_t>event, QString uuid)
{
_channels.take(uuid);
}
void FSHost::eventCodec(QSharedPointer<switch_event_t>event, QString uuid)
{
_channels.value(uuid).data()->setCidName(switch_event_get_header_nil(event.data(), "Caller-Caller-ID-Name"));
_channels.value(uuid).data()->setCidNumber(switch_event_get_header_nil(event.data(), "Caller-Caller-ID-Number"));
}
void FSHost::eventCallUpdate(QSharedPointer<switch_event_t>event, QString uuid)
{}
void FSHost::eventRecvInfo(QSharedPointer<switch_event_t>event, QString uuid)
{}
void FSHost::minimalModuleLoaded(QString modType, QString modKey)
{ {
if (modType == "endpoint") if (modType == "endpoint")
{ {
@ -501,11 +511,11 @@ QSharedPointer<Call> FSHost::getCurrentActiveCall()
return QSharedPointer<Call>(); return QSharedPointer<Call>();
} }
void FSHost::printEventHeaders(switch_event_t *event) void FSHost::printEventHeaders(QSharedPointer<switch_event_t>event)
{ {
switch_event_header_t *hp; switch_event_header_t *hp;
qDebug() << QString("Received event: %1(%2)\n").arg(switch_event_name(event->event_id), switch_event_get_header_nil(event, "Event-Subclass")); qDebug() << QString("Received event: %1(%2)").arg(switch_event_name(event.data()->event_id), switch_event_get_header_nil(event.data(), "Event-Subclass"));
for (hp = event->headers; hp; hp = hp->next) { for (hp = event.data()->headers; hp; hp = hp->next) {
qDebug() << hp->name << "=" << hp->value; qDebug() << hp->name << "=" << hp->value;
} }
qDebug() << "\n\n"; qDebug() << "\n\n";

View File

@ -35,6 +35,7 @@
#include <QSharedPointer> #include <QSharedPointer>
#include <switch.h> #include <switch.h>
#include "call.h" #include "call.h"
#include "channel.h"
#include "account.h" #include "account.h"
class FSHost : public QThread class FSHost : public QThread
@ -43,7 +44,7 @@ Q_OBJECT
public: public:
explicit FSHost(QObject *parent = 0); explicit FSHost(QObject *parent = 0);
switch_status_t sendCmd(const char *cmd, const char *args, QString *res); switch_status_t sendCmd(const char *cmd, const char *args, QString *res);
void generalEventHandler(switch_event_t *event); void generalEventHandler(QSharedPointer<switch_event_t>event);
QSharedPointer<Call> getCallByUUID(QString uuid) { return _active_calls.value(uuid); } QSharedPointer<Call> getCallByUUID(QString uuid) { return _active_calls.value(uuid); }
QSharedPointer<Call> getCurrentActiveCall(); QSharedPointer<Call> getCurrentActiveCall();
QList<QSharedPointer<Account> > getAccounts() { return _accounts.values(); } QList<QSharedPointer<Account> > getAccounts() { return _accounts.values(); }
@ -57,15 +58,20 @@ protected:
void run(void); void run(void);
signals: signals:
/* Status signals */
void coreLoadingError(QString); void coreLoadingError(QString);
void loadingModules(QString, int, QColor); void loadingModules(QString, int, QColor);
void loadedModule(QString, QString, QString); void loadedModule(QString, QString);
void ready(void); void ready(void);
/* Call signals */
void ringing(QSharedPointer<Call>); void ringing(QSharedPointer<Call>);
void answered(QSharedPointer<Call>); void answered(QSharedPointer<Call>);
void newOutgoingCall(QSharedPointer<Call>); void newOutgoingCall(QSharedPointer<Call>);
void callFailed(QSharedPointer<Call>); void callFailed(QSharedPointer<Call>);
void hungup(QSharedPointer<Call>); void hungup(QSharedPointer<Call>);
/* Account signals */
void accountStateChange(QSharedPointer<Account>); void accountStateChange(QSharedPointer<Account>);
void newAccount(QSharedPointer<Account>); void newAccount(QSharedPointer<Account>);
void delAccount(QSharedPointer<Account>); void delAccount(QSharedPointer<Account>);
@ -73,16 +79,39 @@ signals:
private slots: private slots:
/* We need to wait for the gateway deletion before reloading it */ /* We need to wait for the gateway deletion before reloading it */
void accountReloadSlot(QSharedPointer<Account>); void accountReloadSlot(QSharedPointer<Account>);
void minimalModuleLoaded(QString, QString, QString); void minimalModuleLoaded(QString, QString);
private: private:
switch_status_t processBlegEvent(switch_event_t *, QString); /* Helper methods */
switch_status_t processAlegEvent(switch_event_t *, QString);
void createFolders(); void createFolders();
void printEventHeaders(switch_event_t *event); void printEventHeaders(QSharedPointer<switch_event_t>event);
/*FSM State handlers*/
/** Channel Related*/
void eventChannelCreate(QSharedPointer<switch_event_t> event, QString uuid);
void eventChannelAnswer(QSharedPointer<switch_event_t> event, QString uuid);
void eventChannelState(QSharedPointer<switch_event_t>event, QString uuid);
void eventChannelExecute(QSharedPointer<switch_event_t>event, QString uuid);
void eventChannelExecuteComplete(QSharedPointer<switch_event_t>event, QString uuid);
void eventChannelOutgoing(QSharedPointer<switch_event_t>event, QString uuid);
void eventChannelOriginate(QSharedPointer<switch_event_t>event, QString uuid);
void eventChannelProgress(QSharedPointer<switch_event_t>event, QString uuid);
void eventChannelProgressMedia(QSharedPointer<switch_event_t>event, QString uuid);
void eventChannelBridge(QSharedPointer<switch_event_t>event, QString uuid);
void eventChannelHangup(QSharedPointer<switch_event_t>event, QString uuid);
void eventChannelUnbridge(QSharedPointer<switch_event_t>event, QString uuid);
void eventChannelHangupComplete(QSharedPointer<switch_event_t>event, QString uuid);
void eventChannelDestroy(QSharedPointer<switch_event_t>event, QString uuid);
/** Others*/
void eventCodec(QSharedPointer<switch_event_t>event, QString uuid);
void eventCallUpdate(QSharedPointer<switch_event_t>event, QString uuid);
void eventRecvInfo(QSharedPointer<switch_event_t>event, QString uuid);
/* Structures to keep track of things */
QHash<QString, QSharedPointer<Call> > _active_calls; QHash<QString, QSharedPointer<Call> > _active_calls;
QHash<QString, QSharedPointer<Account> > _accounts; QHash<QString, QSharedPointer<Account> > _accounts;
QHash<QString, QString> _bleg_uuids; QHash<QString, QSharedPointer<Channel> > _channels;
QList<QString> _reloading_Accounts; QList<QString> _reloading_Accounts;
QList<QString> _loadedModules; QList<QString> _loadedModules;
}; };
@ -97,9 +126,9 @@ static void eventHandlerCallback(switch_event_t *event)
{ {
switch_event_t *clone = NULL; switch_event_t *clone = NULL;
if (switch_event_dup(&clone, event) == SWITCH_STATUS_SUCCESS) { if (switch_event_dup(&clone, event) == SWITCH_STATUS_SUCCESS) {
g_FSHost.generalEventHandler(clone); QSharedPointer<switch_event_t> e(clone);
g_FSHost.generalEventHandler(e);
} }
switch_safe_free(clone);
} }
#endif // FSHOST_H #endif // FSHOST_H

View File

@ -133,7 +133,7 @@ void MainWindow::updateCallTimers()
QSharedPointer<Call> call = g_FSHost.getCallByUUID(item->data(Qt::UserRole).toString()); QSharedPointer<Call> call = g_FSHost.getCallByUUID(item->data(Qt::UserRole).toString());
QTime time = call.data()->getCurrentStateTime(); QTime time = call.data()->getCurrentStateTime();
item->setText(time.toString("hh:mm:ss")); item->setText(time.toString("hh:mm:ss"));
item->setTextAlignment(Qt::AlignRight); item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
} }
} }
@ -267,7 +267,6 @@ void MainWindow::makeCall()
switch_core_set_variable("fscomm_caller_id_name", cidName.toAscii().data()); switch_core_set_variable("fscomm_caller_id_name", cidName.toAscii().data());
switch_core_set_variable("fscomm_caller_id_num", cidNum.toAscii().data()); switch_core_set_variable("fscomm_caller_id_num", cidNum.toAscii().data());
qDebug() << "Name:" << cidName << "Num:" << cidNum;
} }
if (ok && !dialstring.isEmpty()) if (ok && !dialstring.isEmpty())
@ -357,26 +356,26 @@ void MainWindow::recordCall(bool pressed)
tr("<p>Could not get active call to start/stop recording." tr("<p>Could not get active call to start/stop recording."
"<p>Please report this bug."), "<p>Please report this bug."),
QMessageBox::Ok); QMessageBox::Ok);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not record call [%s].\n", call.data()->getUUID().toAscii().data()); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not record call [%s].\n", call.data()->getUuid().toAscii().data());
return; return;
} }
} }
void MainWindow::newOutgoingCall(QSharedPointer<Call> call) void MainWindow::newOutgoingCall(QSharedPointer<Call> call)
{ {
ui->textEdit->setText(QString("Calling %1 (%2)").arg(call.data()->getCidName(), call.data()->getCidNumber())); ui->textEdit->setText(QString("Calling %1").arg(call.data()->getDestinationNumber()));
ui->tableCalls->setRowCount(ui->tableCalls->rowCount()+1); ui->tableCalls->setRowCount(ui->tableCalls->rowCount()+1);
QTableWidgetItem *item0 = new QTableWidgetItem(QString("%1 (%2)").arg(call.data()->getCidName(), call.data()->getCidNumber())); QTableWidgetItem *item0 = new QTableWidgetItem(QString("%1").arg(call.data()->getDestinationNumber()));
item0->setData(Qt::UserRole, call.data()->getUUID()); item0->setData(Qt::UserRole, call.data()->getUuid());
ui->tableCalls->setItem(ui->tableCalls->rowCount()-1,0,item0); ui->tableCalls->setItem(ui->tableCalls->rowCount()-1,0,item0);
QTableWidgetItem *item1 = new QTableWidgetItem(tr("Dialing...")); QTableWidgetItem *item1 = new QTableWidgetItem(tr("Dialing..."));
item1->setData(Qt::UserRole, call.data()->getUUID()); item1->setData(Qt::UserRole, call.data()->getUuid());
ui->tableCalls->setItem(ui->tableCalls->rowCount()-1,1,item1); ui->tableCalls->setItem(ui->tableCalls->rowCount()-1,1,item1);
QTableWidgetItem *item2 = new QTableWidgetItem("00:00:00"); QTableWidgetItem *item2 = new QTableWidgetItem("00:00:00");
item2->setData(Qt::UserRole, call.data()->getUUID()); item2->setData(Qt::UserRole, call.data()->getUuid());
ui->tableCalls->setItem(ui->tableCalls->rowCount()-1,2,item2); ui->tableCalls->setItem(ui->tableCalls->rowCount()-1,2,item2);
ui->tableCalls->resizeColumnsToContents(); ui->tableCalls->resizeColumnsToContents();
@ -393,27 +392,33 @@ void MainWindow::ringing(QSharedPointer<Call> call)
for (int i=0; i<ui->tableCalls->rowCount(); i++) for (int i=0; i<ui->tableCalls->rowCount(); i++)
{ {
QTableWidgetItem *item = ui->tableCalls->item(i, 1); QTableWidgetItem *item = ui->tableCalls->item(i, 1);
if (item->data(Qt::UserRole).toString() == call.data()->getUUID()) if (item->data(Qt::UserRole).toString() == call.data()->getUuid())
{ {
item->setText(tr("Ringing")); item->setText(tr("Ringing"));
ui->textEdit->setText(QString("Call from %1 (%2)").arg(call.data()->getCidName(), call.data()->getCidNumber())); if (call.data()->getDirection() == FSCOMM_CALL_DIRECTION_INBOUND)
ui->textEdit->setText(QString("Call from %1 (%2)").arg(call.data()->getCidName(), call.data()->getCidNumber()));
else
ui->textEdit->setText(QString("Call to %1 is ringing.").arg(call.data()->getDestinationNumber()));
return; return;
} }
} }
ui->textEdit->setText(QString("Call from %1 (%2)").arg(call.data()->getCidName(), call.data()->getCidNumber())); if (call.data()->getDirection() == FSCOMM_CALL_DIRECTION_INBOUND)
ui->textEdit->setText(QString("Call from %1 (%2)").arg(call.data()->getCidName(), call.data()->getCidNumber()));
else
ui->textEdit->setText(QString("Call to %1 is ringing.").arg(call.data()->getDestinationNumber()));
ui->tableCalls->setRowCount(ui->tableCalls->rowCount()+1); ui->tableCalls->setRowCount(ui->tableCalls->rowCount()+1);
QTableWidgetItem *item0 = new QTableWidgetItem(QString("%1 (%2)").arg(call.data()->getCidName(), call.data()->getCidNumber())); QTableWidgetItem *item0 = new QTableWidgetItem(QString("%1 (%2)").arg(call.data()->getCidName(), call.data()->getCidNumber()));
item0->setData(Qt::UserRole, call.data()->getUUID()); item0->setData(Qt::UserRole, call.data()->getUuid());
ui->tableCalls->setItem(ui->tableCalls->rowCount()-1,0,item0); ui->tableCalls->setItem(ui->tableCalls->rowCount()-1,0,item0);
QTableWidgetItem *item1 = new QTableWidgetItem(tr("Ringing")); QTableWidgetItem *item1 = new QTableWidgetItem(tr("Ringing"));
item1->setData(Qt::UserRole, call.data()->getUUID()); item1->setData(Qt::UserRole, call.data()->getUuid());
ui->tableCalls->setItem(ui->tableCalls->rowCount()-1,1,item1); ui->tableCalls->setItem(ui->tableCalls->rowCount()-1,1,item1);
QTableWidgetItem *item2 = new QTableWidgetItem("00:00:00"); QTableWidgetItem *item2 = new QTableWidgetItem("00:00:00");
item2->setData(Qt::UserRole, call.data()->getUUID()); item2->setData(Qt::UserRole, call.data()->getUuid());
ui->tableCalls->setItem(ui->tableCalls->rowCount()-1,2,item2); ui->tableCalls->setItem(ui->tableCalls->rowCount()-1,2,item2);
ui->tableCalls->resizeColumnsToContents(); ui->tableCalls->resizeColumnsToContents();
@ -429,7 +434,7 @@ void MainWindow::answered(QSharedPointer<Call> call)
for (int i=0; i<ui->tableCalls->rowCount(); i++) for (int i=0; i<ui->tableCalls->rowCount(); i++)
{ {
QTableWidgetItem *item = ui->tableCalls->item(i, 1); QTableWidgetItem *item = ui->tableCalls->item(i, 1);
if (item->data(Qt::UserRole).toString() == call.data()->getUUID()) if (item->data(Qt::UserRole).toString() == call.data()->getUuid())
{ {
item->setText(tr("Answered")); item->setText(tr("Answered"));
ui->tableCalls->resizeColumnsToContents(); ui->tableCalls->resizeColumnsToContents();
@ -463,7 +468,7 @@ void MainWindow::callFailed(QSharedPointer<Call> call)
for (int i=0; i<ui->tableCalls->rowCount(); i++) for (int i=0; i<ui->tableCalls->rowCount(); i++)
{ {
QTableWidgetItem *item = ui->tableCalls->item(i, 1); QTableWidgetItem *item = ui->tableCalls->item(i, 1);
if (item->data(Qt::UserRole).toString() == call.data()->getUUID()) if (item->data(Qt::UserRole).toString() == call.data()->getUuid())
{ {
ui->tableCalls->removeRow(i); ui->tableCalls->removeRow(i);
ui->tableCalls->resizeColumnsToContents(); ui->tableCalls->resizeColumnsToContents();
@ -505,7 +510,7 @@ void MainWindow::hungup(QSharedPointer<Call> call)
for (int i=0; i<ui->tableCalls->rowCount(); i++) for (int i=0; i<ui->tableCalls->rowCount(); i++)
{ {
QTableWidgetItem *item = ui->tableCalls->item(i, 1); QTableWidgetItem *item = ui->tableCalls->item(i, 1);
if (item->data(Qt::UserRole).toString() == call.data()->getUUID()) if (item->data(Qt::UserRole).toString() == call.data()->getUuid())
{ {
ui->tableCalls->removeRow(i); ui->tableCalls->removeRow(i);
ui->tableCalls->resizeColumnsToContents(); ui->tableCalls->resizeColumnsToContents();
@ -515,7 +520,14 @@ void MainWindow::hungup(QSharedPointer<Call> call)
} }
} }
call.data()->setActive(false); call.data()->setActive(false);
ui->textEdit->setText(tr("Call with %1 (%2) hungup.").arg(call.data()->getCidName(), call.data()->getCidNumber())); if (call.data()->getDirection() == FSCOMM_CALL_DIRECTION_INBOUND)
{
ui->textEdit->setText(tr("Call with %1 (%2) hungup.").arg(call.data()->getCidName(), call.data()->getCidNumber()));
}
else
{
ui->textEdit->setText(tr("Call with %1 hungup.").arg(call.data()->getDestinationNumber()));
}
/* TODO: Will cause problems if 2 calls are received at the same time */ /* TODO: Will cause problems if 2 calls are received at the same time */
ui->recoredCallBtn->setEnabled(false); ui->recoredCallBtn->setEnabled(false);
ui->recoredCallBtn->setChecked(false); ui->recoredCallBtn->setChecked(false);

View File

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

View File

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

View File

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

View File

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

View File

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

2065
libs/.gitignore vendored

File diff suppressed because it is too large Load Diff

View File

View File

View File

@ -72,7 +72,8 @@ $(SRC)/libteletone_detect.c \
$(SRC)/libteletone_generate.c \ $(SRC)/libteletone_generate.c \
$(SRC)/ftdm_buffer.c \ $(SRC)/ftdm_buffer.c \
$(SRC)/ftdm_threadmutex.c \ $(SRC)/ftdm_threadmutex.c \
$(SRC)/ftdm_dso.c $(SRC)/ftdm_dso.c \
$(SRC)/ftdm_cpu_monitor.c
library_include_HEADERS = \ library_include_HEADERS = \
$(SRC)/include/fsk.h \ $(SRC)/include/fsk.h \
@ -90,7 +91,8 @@ $(SRC)/include/ftdm_buffer.h \
$(SRC)/include/ftdm_config.h \ $(SRC)/include/ftdm_config.h \
$(SRC)/include/ftdm_threadmutex.h \ $(SRC)/include/ftdm_threadmutex.h \
$(SRC)/include/ftdm_dso.h \ $(SRC)/include/ftdm_dso.h \
$(SRC)/include/ftdm_types.h $(SRC)/include/ftdm_types.h \
$(SRC)/include/ftdm_cpu_monitor.h
lib_LTLIBRARIES = libfreetdm.la lib_LTLIBRARIES = libfreetdm.la
libfreetdm_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS) libfreetdm_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
@ -105,7 +107,7 @@ core-install: install-libLTLIBRARIES
# #
# tools & test programs # tools & test programs
# #
noinst_PROGRAMS = testtones detect_tones detect_dtmf testisdn testpri testr2 testanalog testapp testcid noinst_PROGRAMS = testtones detect_tones detect_dtmf testpri testr2 testanalog testapp testcid #testisdn
if HAVE_SCTP if HAVE_SCTP
noinst_PROGRAMS += testboost noinst_PROGRAMS += testboost
endif endif
@ -131,9 +133,9 @@ detect_dtmf_SOURCES = $(SRC)/detect_dtmf.c
detect_dtmf_LDADD = libfreetdm.la detect_dtmf_LDADD = libfreetdm.la
detect_dtmf_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS) detect_dtmf_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
testisdn_SOURCES = $(SRC)/testisdn.c #testisdn_SOURCES = $(SRC)/testisdn.c
testisdn_LDADD = libfreetdm.la #testisdn_LDADD = libfreetdm.la
testisdn_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS) #testisdn_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
testpri_SOURCES = $(SRC)/testpri.c testpri_SOURCES = $(SRC)/testpri.c
testpri_LDADD = libfreetdm.la testpri_LDADD = libfreetdm.la
@ -160,7 +162,7 @@ testanalog_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
# #
# ftmod modules # ftmod modules
# #
mod_LTLIBRARIES = ftmod_zt.la ftmod_skel.la ftmod_isdn.la ftmod_analog.la ftmod_analog_em.la mod_LTLIBRARIES = ftmod_zt.la ftmod_skel.la ftmod_analog.la ftmod_analog_em.la #ftmod_isdn.la
if HAVE_SCTP if HAVE_SCTP
@ -196,32 +198,32 @@ ftmod_wanpipe_la_LDFLAGS = -module -avoid-version -lsangoma
ftmod_wanpipe_la_LIBADD = $(MYLIB) ftmod_wanpipe_la_LIBADD = $(MYLIB)
endif endif
ftmod_isdn_la_SOURCES = \ #ftmod_isdn_la_SOURCES = \
$(SRC)/isdn/EuroISDNStateNT.c \ #$(SRC)/isdn/EuroISDNStateNT.c \
$(SRC)/isdn/EuroISDNStateTE.c \ #$(SRC)/isdn/EuroISDNStateTE.c \
$(SRC)/isdn/mfifo.c \ #$(SRC)/isdn/mfifo.c \
$(SRC)/isdn/Q921.c \ #$(SRC)/isdn/Q921.c \
$(SRC)/isdn/Q931api.c \ #$(SRC)/isdn/Q931api.c \
$(SRC)/isdn/Q931.c \ #$(SRC)/isdn/Q931.c \
$(SRC)/isdn/Q931ie.c \ #$(SRC)/isdn/Q931ie.c \
$(SRC)/isdn/Q931mes.c \ #$(SRC)/isdn/Q931mes.c \
$(SRC)/isdn/Q931StateNT.c \ #$(SRC)/isdn/Q931StateNT.c \
$(SRC)/isdn/Q931StateTE.c \ #$(SRC)/isdn/Q931StateTE.c \
$(SRC)/isdn/nationalmes.c \ #$(SRC)/isdn/nationalmes.c \
$(SRC)/isdn/nationalStateNT.c \ #$(SRC)/isdn/nationalStateNT.c \
$(SRC)/isdn/nationalStateTE.c \ #$(SRC)/isdn/nationalStateTE.c \
$(SRC)/isdn/DMSmes.c \ #$(SRC)/isdn/DMSmes.c \
$(SRC)/isdn/DMSStateNT.c \ #$(SRC)/isdn/DMSStateNT.c \
$(SRC)/isdn/DMSStateTE.c \ #$(SRC)/isdn/DMSStateTE.c \
$(SRC)/isdn/5ESSmes.c \ #$(SRC)/isdn/5ESSmes.c \
$(SRC)/isdn/5ESSStateNT.c \ #$(SRC)/isdn/5ESSStateNT.c \
$(SRC)/isdn/5ESSStateTE.c \ #$(SRC)/isdn/5ESSStateTE.c \
$(SRC)/isdn/Q932mes.c \ #$(SRC)/isdn/Q932mes.c \
$(SRC)/ftmod/ftmod_isdn/ftmod_isdn.c #$(SRC)/ftmod/ftmod_isdn/ftmod_isdn.c
ftmod_isdn_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS) -D_GNU_SOURCE #ftmod_isdn_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS) -D_GNU_SOURCE
ftmod_isdn_la_LDFLAGS = $(PCAP_LIB_FLAGS) -module -avoid-version #ftmod_isdn_la_LDFLAGS = $(PCAP_LIB_FLAGS) -module -avoid-version
ftmod_isdn_la_LIBADD = $(MYLIB) #ftmod_isdn_la_LIBADD = $(MYLIB)
ftmod_analog_la_SOURCES = $(SRC)/ftmod/ftmod_analog/ftmod_analog.c ftmod_analog_la_SOURCES = $(SRC)/ftmod/ftmod_analog/ftmod_analog.c
ftmod_analog_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS) ftmod_analog_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)

View File

@ -2767,6 +2767,8 @@ void dump_chan(ftdm_span_t *span, uint32_t chan_id, switch_stream_handle_t *stre
"type: %s\n" "type: %s\n"
"state: %s\n" "state: %s\n"
"last_state: %s\n" "last_state: %s\n"
"txgain: %3.2f\n"
"rxgain: %3.2f\n"
"cid_date: %s\n" "cid_date: %s\n"
"cid_name: %s\n" "cid_name: %s\n"
"cid_num: %s\n" "cid_num: %s\n"
@ -2782,6 +2784,8 @@ void dump_chan(ftdm_span_t *span, uint32_t chan_id, switch_stream_handle_t *stre
ftdm_chan_type2str(span->channels[chan_id]->type), ftdm_chan_type2str(span->channels[chan_id]->type),
ftdm_channel_state2str(span->channels[chan_id]->state), ftdm_channel_state2str(span->channels[chan_id]->state),
ftdm_channel_state2str(span->channels[chan_id]->last_state), ftdm_channel_state2str(span->channels[chan_id]->last_state),
span->channels[chan_id]->txgain,
span->channels[chan_id]->rxgain,
span->channels[chan_id]->caller_data.cid_date, span->channels[chan_id]->caller_data.cid_date,
span->channels[chan_id]->caller_data.cid_name, span->channels[chan_id]->caller_data.cid_name,
span->channels[chan_id]->caller_data.cid_num.digits, span->channels[chan_id]->caller_data.cid_num.digits,
@ -2808,6 +2812,8 @@ void dump_chan_xml(ftdm_span_t *span, uint32_t chan_id, switch_stream_handle_t *
" <type>%s</type>\n" " <type>%s</type>\n"
" <state>%s</state>\n" " <state>%s</state>\n"
" <last-state>%s</last-state>\n" " <last-state>%s</last-state>\n"
" <txgain>%3.2f</txgain>\n"
" <rxgain>%3.2f</rxgain>\n"
" <cid-date>%s</cid-date>\n" " <cid-date>%s</cid-date>\n"
" <cid-name>%s</cid-name>\n" " <cid-name>%s</cid-name>\n"
" <cid-num>%s</cid-num>\n" " <cid-num>%s</cid-num>\n"
@ -2824,6 +2830,8 @@ void dump_chan_xml(ftdm_span_t *span, uint32_t chan_id, switch_stream_handle_t *
ftdm_chan_type2str(span->channels[chan_id]->type), ftdm_chan_type2str(span->channels[chan_id]->type),
ftdm_channel_state2str(span->channels[chan_id]->state), ftdm_channel_state2str(span->channels[chan_id]->state),
ftdm_channel_state2str(span->channels[chan_id]->last_state), ftdm_channel_state2str(span->channels[chan_id]->last_state),
span->channels[chan_id]->txgain,
span->channels[chan_id]->rxgain,
span->channels[chan_id]->caller_data.cid_date, span->channels[chan_id]->caller_data.cid_date,
span->channels[chan_id]->caller_data.cid_name, span->channels[chan_id]->caller_data.cid_name,
span->channels[chan_id]->caller_data.cid_num.digits, span->channels[chan_id]->caller_data.cid_num.digits,
@ -3143,6 +3151,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_freetdm_load)
ftdm_global_set_logger(ftdm_logger); ftdm_global_set_logger(ftdm_logger);
ftdm_cpu_monitor_disable();
if (ftdm_global_init() != FTDM_SUCCESS) { if (ftdm_global_init() != FTDM_SUCCESS) {
ftdm_log(FTDM_LOG_ERROR, "Error loading FreeTDM\n"); ftdm_log(FTDM_LOG_ERROR, "Error loading FreeTDM\n");
return SWITCH_STATUS_TERM; return SWITCH_STATUS_TERM;

View File

@ -0,0 +1,271 @@
/*
* 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 (WIN32) || defined (WIN64)
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;
if (!::GetSystemTimes(&idleTime, &kernelTime, &userTime)) {
return false;
}
__int64 i64UserTime = (__int64)userTime.dwLowDateTime | ((__int64)userTime.dwHighDateTime << 32);
__int64 i64KernelTime = (__int64)kernelTime.dwLowDateTime | ((__int64)kernelTime.dwHighDateTime << 32);
__int64 i64IdleTime = (__int64)idleTime.dwLowDateTime | ((__int64)idleTime.dwHighDateTime << 32);
if (p->valid_last_times) {
__int64 i64User = i64UserTime - p->i64LastUserTime;
__int64 i64Kernel = i64KernelTime - p->i64LastKernelTime;
__int64 i64Idle = i64IdleTime - p->i64LastIdleTime;
__int64 i64System = i64User + i64Kernel;
*idle_percentage = 100.0 * i64Idle / i64System;
} else {
*idle_percentage = 100.0;
p->valid_last_times = 1;
}
/* Remember current value for the next call */
p->i64LastUserTime = i64UserTime;
p->i64LastKernelTime = i64KernelTime;
p->i64LastIdleTime = i64IdleTime;
/* Success */
return FTDM_SUCCESS;
}
#else
/* Unsupported */
FT_DECLARE(ftdm_status_t) ftdm_cpu_get_system_idle_time(struct ftdm_cpu_monitor_stats *p, double *idle_percentage)
{
return FTDM_FAIL;
}
#endif
FT_DECLARE(struct ftdm_cpu_monitor_stats*) ftdm_new_cpu_monitor(void)
{
return calloc(1, sizeof(struct ftdm_cpu_monitor_stats));
}
FT_DECLARE(void) ftdm_delete_cpu_monitor(struct ftdm_cpu_monitor_stats *p)
{
#ifdef __linux__
close(p->procfd);
#endif
free(p);
}
/* For Emacs:
* Local Variables:
* mode:c
* indent-tabs-mode:t
* tab-width:4
* c-basic-offset:4
* End:
* For VIM:
* vim:set softtabstop=4 shiftwidth=4 tabstop=4:
*/

View File

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

View File

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

View File

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

View File

@ -880,8 +880,8 @@ static __inline__ void advance_chan_states(ftdm_channel_t *ftdmchan);
*/ */
static void handle_call_start(ftdm_span_t *span, sangomabc_connection_t *mcon, sangomabc_event_t *event) static void handle_call_start(ftdm_span_t *span, sangomabc_connection_t *mcon, sangomabc_event_t *event)
{ {
ftdm_channel_t *ftdmchan; ftdm_channel_t *ftdmchan = NULL;
int hangup_cause = FTDM_CAUSE_CALL_REJECTED;
if (!(ftdmchan = find_ftdmchan(span, (sangomabc_short_event_t*)event, 0))) { if (!(ftdmchan = find_ftdmchan(span, (sangomabc_short_event_t*)event, 0))) {
if ((ftdmchan = find_ftdmchan(span, (sangomabc_short_event_t*)event, 1))) { if ((ftdmchan = find_ftdmchan(span, (sangomabc_short_event_t*)event, 1))) {
int r; int r;
@ -896,7 +896,7 @@ static void handle_call_start(ftdm_span_t *span, sangomabc_connection_t *mcon, s
} }
ftdm_set_sflag(ftdmchan, SFLAG_SENT_FINAL_MSG); ftdm_set_sflag(ftdmchan, SFLAG_SENT_FINAL_MSG);
ftdmchan=NULL; ftdmchan = NULL;
} }
ftdm_log(FTDM_LOG_CRIT, "START CANT FIND CHAN %d:%d\n", event->span+1,event->chan+1); ftdm_log(FTDM_LOG_CRIT, "START CANT FIND CHAN %d:%d\n", event->span+1,event->chan+1);
goto error; goto error;
@ -953,12 +953,13 @@ static void handle_call_start(ftdm_span_t *span, sangomabc_connection_t *mcon, s
return; return;
error: error:
hangup_cause = ftdmchan ? ftdmchan->caller_data.hangup_cause : FTDM_CAUSE_REQUESTED_CHAN_UNAVAIL;
sangomabc_exec_command(mcon, sangomabc_exec_command(mcon,
event->span, event->span,
event->chan, event->chan,
0, 0,
SIGBOOST_EVENT_CALL_START_NACK, SIGBOOST_EVENT_CALL_START_NACK,
0, 0); hangup_cause, 0);
} }
@ -2239,7 +2240,8 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_boost_configure_span)
span->get_span_sig_status = sangoma_boost_get_span_sig_status; span->get_span_sig_status = sangoma_boost_get_span_sig_status;
span->set_span_sig_status = sangoma_boost_set_span_sig_status; span->set_span_sig_status = sangoma_boost_set_span_sig_status;
span->state_map = &boost_state_map; span->state_map = &boost_state_map;
span->suggest_chan_id = 0; ftdm_clear_flag(span, FTDM_SPAN_SUGGEST_CHAN_ID);
ftdm_set_flag(span, FTDM_SPAN_USE_CHAN_QUEUE);
if (sigmod_iface) { if (sigmod_iface) {
/* the core will do the hunting */ /* the core will do the hunting */
span->channel_request = NULL; span->channel_request = NULL;

View File

@ -654,7 +654,6 @@ struct ftdm_span {
char *type; char *type;
char *dtmf_hangup; char *dtmf_hangup;
size_t dtmf_hangup_len; size_t dtmf_hangup_len;
int suggest_chan_id;
ftdm_state_map_t *state_map; ftdm_state_map_t *state_map;
ftdm_caller_data_t default_caller_data; ftdm_caller_data_t default_caller_data;
ftdm_queue_t *pendingchans; ftdm_queue_t *pendingchans;
@ -825,6 +824,7 @@ FT_DECLARE(ftdm_status_t) ftdm_span_find_by_name(const char *name, ftdm_span_t *
FT_DECLARE(char *) ftdm_api_execute(const char *type, const char *cmd); FT_DECLARE(char *) ftdm_api_execute(const char *type, const char *cmd);
FT_DECLARE(int) ftdm_vasprintf(char **ret, const char *fmt, va_list ap); FT_DECLARE(int) ftdm_vasprintf(char **ret, const char *fmt, va_list ap);
FT_DECLARE(ftdm_status_t) ftdm_channel_set_caller_data(ftdm_channel_t *ftdmchan, ftdm_caller_data_t *caller_data); FT_DECLARE(ftdm_status_t) ftdm_channel_set_caller_data(ftdm_channel_t *ftdmchan, ftdm_caller_data_t *caller_data);
FT_DECLARE(void) ftdm_cpu_monitor_disable(void);
FIO_CODEC_FUNCTION(fio_slin2ulaw); FIO_CODEC_FUNCTION(fio_slin2ulaw);
FIO_CODEC_FUNCTION(fio_ulaw2slin); FIO_CODEC_FUNCTION(fio_ulaw2slin);

View File

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

View File

@ -325,7 +325,9 @@ typedef enum {
FTDM_SPAN_STATE_CHANGE = (1 << 2), FTDM_SPAN_STATE_CHANGE = (1 << 2),
FTDM_SPAN_SUSPENDED = (1 << 3), FTDM_SPAN_SUSPENDED = (1 << 3),
FTDM_SPAN_IN_THREAD = (1 << 4), FTDM_SPAN_IN_THREAD = (1 << 4),
FTDM_SPAN_STOP_THREAD = (1 << 5) FTDM_SPAN_STOP_THREAD = (1 << 5),
FTDM_SPAN_USE_CHAN_QUEUE = (1 << 6),
FTDM_SPAN_SUGGEST_CHAN_ID = (1 << 7),
} ftdm_span_flag_t; } ftdm_span_flag_t;
typedef enum { typedef enum {

View File

View File

View File

View File

View File

View File

@ -100,13 +100,16 @@ if test "x${ax_cv_c_compiler_vendor}" = "xsun" ; then
fi fi
fi fi
SOFIA_PLAT_CFLAGS=
# openbsd seems to not define NULL as a void pointer, I blame standards by committee for this. # openbsd seems to not define NULL as a void pointer, I blame standards by committee for this.
# This is a dirty hack, but shuts up all the warnings # This is a dirty hack, but shuts up all the warnings
case "$host" in case "$host" in
*-openbsd*) SOFIA_CFLAGS="$SOFIA_CFLAGS -DNULL='(void *) 0L'";; *-openbsd*) SOFIA_PLAT_CFLAGS="-DNULL='(void *) 0L'";;
*) ;; *) ;;
esac esac
AC_SUBST(SOFIA_PLAT_CFLAGS, $SOFIA_PLAT_CFLAGS)
### checks for header files ### checks for header files
### ----------------------- ### -----------------------

View File

@ -1,7 +1,7 @@
# common Makefile targets for libsofia-sip-ua modules # common Makefile targets for libsofia-sip-ua modules
# --------------------------------------------------- # ---------------------------------------------------
AM_CFLAGS = $(CWFLAG) $(SOFIA_CFLAGS) $(SOFIA_COVERAGE) AM_CFLAGS = $(CWFLAG) $(SOFIA_CFLAGS) $(SOFIA_COVERAGE) $(SOFIA_PLAT_CFLAGS)
# Use with --enable-ndebug # Use with --enable-ndebug
if NDEBUG if NDEBUG

View File

@ -4,7 +4,7 @@
sofiasrcdir = ${top_srcdir}/libsofia-sip-ua sofiasrcdir = ${top_srcdir}/libsofia-sip-ua
sofiabuilddir = ${top_builddir}/libsofia-sip-ua sofiabuilddir = ${top_builddir}/libsofia-sip-ua
AM_CFLAGS = $(CWFLAG) $(SOFIA_COVERAGE) $(SOFIA_CFLAGS) $(openssl_CFLAGS) AM_CFLAGS = $(CWFLAG) $(SOFIA_COVERAGE) $(SOFIA_CFLAGS) $(openssl_CFLAGS) $(SOFIA_PLAT_CFLAGS)
SOFIA_COVERAGE = $(COVERAGE_FLAGS) SOFIA_COVERAGE = $(COVERAGE_FLAGS)

View File

0
libs/sqlite/notes/.empty Normal file
View File

View File

View File

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

View File

@ -35,11 +35,12 @@ fi
sed -e "s|\(AC_SUBST(SWITCH_VERSION_MAJOR, \[\).*\(\])\)|\1$major\2|" \ sed -e "s|\(AC_SUBST(SWITCH_VERSION_MAJOR, \[\).*\(\])\)|\1$major\2|" \
-e "s|\(AC_SUBST(SWITCH_VERSION_MINOR, \[\).*\(\])\)|\1$minor\2|" \ -e "s|\(AC_SUBST(SWITCH_VERSION_MINOR, \[\).*\(\])\)|\1$minor\2|" \
-e "s|\(AC_SUBST(SWITCH_VERSION_MICRO, \[\).*\(\])\)|\1$micro\2|" \ -e "s|\(AC_SUBST(SWITCH_VERSION_MICRO, \[\).*\(\])\)|\1$micro\2|" \
-e "s|\(AC_SUBST(SWITCH_VERSION_REVISION, \[\).*\(\])\)|\1$rev\2|" \ -e "s|\(AC_INIT(\[freeswitch\], \[\).*\(\], BUG-REPORT-ADDRESS)\)|\1$major.$minor.$micro\2|" \
-i configure.in -i configure.in
if [ -n "$rev" ]; then if [ -n "$rev" ]; then
sed -e "s|#\(AC_SUBST(SWITCH_VERSION_REVISION\)|\1|" \ sed -e "s|\(AC_SUBST(SWITCH_VERSION_REVISION, \[\).*\(\])\)|\1$rev\2|" \
-e "s|#\(AC_SUBST(SWITCH_VERSION_REVISION\)|\1|" \
-i configure.in -i configure.in
fi fi
@ -61,16 +62,17 @@ rm -f docs/COPYING
rm -f docs/ChangeLog rm -f docs/ChangeLog
rm -rf .git rm -rf .git
cd .. cd ..
tar -czvf $dst_name.tar.gz $dst_dir tar -cvf $dst_name.tar $dst_dir
tar -cjvf $dst_name.tar.bz2 $dst_dir gzip -9 -c $dst_name.tar > $dst_name.tar.gz || echo "gzip not available"
tar -cJvf $dst_name.tar.xz $dst_dir bzip2 -z -k $dst_name.tar || echo "bzip2 not available"
rm -rf $dst_dir xz -z -9 -k $dst_name.tar || echo "xz / xz-utils not available"
rm -rf $dst_name.tar $dst_dir
cat 1>&2 <<EOF cat 1>&2 <<EOF
---------------------------------------------------------------------- ----------------------------------------------------------------------
The v$ver tag has been committed locally, but it will not be The v$ver tag has been committed locally, but it will not be
globally visible until you 'git push' this repository up to the server globally visible until you 'git push --tags' this repository up to the
(I didn't do that for you). server (I didn't do that for you, as you might want to review first).
---------------------------------------------------------------------- ----------------------------------------------------------------------
EOF EOF

18
src/.gitignore vendored
View File

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

View File

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

View File

@ -245,6 +245,11 @@ SWITCH_DECLARE(const char *) switch_channel_get_variable_partner(switch_channel_
#define switch_channel_set_variable(_channel, _var, _val) switch_channel_set_variable_var_check(_channel, _var, _val, SWITCH_TRUE) #define switch_channel_set_variable(_channel, _var, _val) switch_channel_set_variable_var_check(_channel, _var, _val, SWITCH_TRUE)
#define switch_channel_set_variable_partner(_channel, _var, _val) switch_channel_set_variable_partner_var_check(_channel, _var, _val, SWITCH_TRUE) #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);
#define switch_channel_export_variable(_channel, _varname, _value, _nolocal) switch_channel_export_variable_var_check(_channel, _varname, _value, SWITCH_TRUE, _nolocal)
/*! /*!
\brief Retrieve a variable from a given channel \brief Retrieve a variable from a given channel
\param channel channel to retrieve variable from \param channel channel to retrieve variable from

111
src/mod/.gitignore vendored
View File

@ -1,52 +1,59 @@
Makefile /Makefile
Makefile.in /Makefile.in
applications/mod_commands/Makefile /applications/mod_commands/Makefile
applications/mod_conference/Makefile /applications/mod_conference/Makefile
applications/mod_dptools/Makefile /applications/mod_dptools/Makefile
applications/mod_enum/Makefile /applications/mod_enum/Makefile
applications/mod_enum/Makefile.in /applications/mod_enum/Makefile.in
applications/mod_enum/mod_enum.log /applications/mod_enum/mod_enum.log
applications/mod_expr/Makefile /applications/mod_expr/Makefile
applications/mod_expr/Makefile.in /applications/mod_expr/Makefile.in
applications/mod_expr/mod_expr.log /applications/mod_expr/mod_expr.log
applications/mod_fifo/Makefile /applications/mod_fifo/Makefile
applications/mod_fsv/Makefile /applications/mod_fsv/Makefile
applications/mod_limit/Makefile /applications/mod_limit/Makefile
applications/mod_stress/Makefile /applications/mod_stress/Makefile
applications/mod_stress/Makefile.in /applications/mod_stress/Makefile.in
applications/mod_t38gateway/Makefile /applications/mod_t38gateway/Makefile
applications/mod_t38gateway/Makefile.in /applications/mod_t38gateway/Makefile.in
applications/mod_valet_parking/Makefile /applications/mod_valet_parking/Makefile
applications/mod_voicemail/Makefile /applications/mod_voicemail/Makefile
asr_tts/mod_unimrcp/Makefile /asr_tts/mod_unimrcp/Makefile
asr_tts/mod_unimrcp/Makefile.in /asr_tts/mod_unimrcp/Makefile.in
dialplans/mod_dialplan_asterisk/Makefile /dialplans/mod_dialplan_asterisk/Makefile
dialplans/mod_dialplan_xml/Makefile /dialplans/mod_dialplan_xml/Makefile
endpoints/mod_portaudio/Makefile /endpoints/mod_portaudio/Makefile
endpoints/mod_portaudio/Makefile.in /endpoints/mod_portaudio/Makefile.in
endpoints/mod_skinny/Makefile /endpoints/mod_skinny/Makefile
endpoints/mod_skinny/Makefile.in /endpoints/mod_skinny/Makefile.in
endpoints/mod_skypopen/Makefile /endpoints/mod_skypopen/Makefile
endpoints/mod_skypopen/Makefile.in /endpoints/mod_skypopen/Makefile.in
endpoints/mod_sofia/Makefile /endpoints/mod_sofia/Makefile
endpoints/mod_sofia/Makefile.in /endpoints/mod_sofia/Makefile.in
endpoints/mod_sofia/mod_sofia.log /endpoints/mod_sofia/mod_sofia.log
event_handlers/mod_erlang_event/Makefile /event_handlers/mod_erlang_event/Makefile
event_handlers/mod_event_socket/Makefile /event_handlers/mod_event_socket/Makefile
formats/mod_native_file/Makefile /formats/mod_native_file/Makefile
formats/mod_portaudio_stream/Makefile /formats/mod_portaudio_stream/Makefile
formats/mod_portaudio_stream/Makefile.in /formats/mod_portaudio_stream/Makefile.in
formats/mod_tone_stream/Makefile /formats/mod_tone_stream/Makefile
languages/mod_java/Makefile /languages/mod_java/Makefile
languages/mod_lua/Makefile /languages/mod_lua/Makefile
languages/mod_lua/Makefile.in /languages/mod_lua/Makefile.in
languages/mod_lua/mod_lua.log /languages/mod_lua/mod_lua.log
languages/mod_python/Makefile /languages/mod_python/Makefile
languages/mod_spidermonkey/Makefile /languages/mod_spidermonkey/Makefile
languages/mod_spidermonkey/Makefile.in /languages/mod_spidermonkey/Makefile.in
languages/mod_spidermonkey/mod_spidermonkey.log /languages/mod_spidermonkey/mod_spidermonkey.log
loggers/mod_console/Makefile /loggers/mod_console/Makefile
loggers/mod_logfile/Makefile /loggers/mod_logfile/Makefile
loggers/mod_syslog/Makefile /loggers/mod_syslog/Makefile
say/mod_say_en/Makefile /say/mod_say_en/Makefile
say/mod_say_ru/Makefile /say/mod_say_ru/Makefile
/applications/mod_stress/mod_stress.log
/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> * 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

@ -0,0 +1 @@
Makefile

View File

@ -2,13 +2,12 @@ include $(top_srcdir)/build/modmake.rulesam
MODNAME=mod_enum MODNAME=mod_enum
UDNS_DIR=$(switch_srcdir)/libs/udns UDNS_DIR=$(switch_srcdir)/libs/udns
AM_CFLAGS += -I$(UDNS_DIR) -DHAVE_POLL mod_enum_la_CFLAGS = -I$(UDNS_DIR) -DHAVE_POLL $(AM_CFLAGS)
mod_LTLIBRARIES = mod_enum.la mod_LTLIBRARIES = mod_enum.la
mod_enum_la_SOURCES = mod_enum.c mod_enum_la_SOURCES = mod_enum.c
mod_enum_la_SOURCES += $(UDNS_DIR)/udns_dn.c $(UDNS_DIR)/udns_dntosp.c $(UDNS_DIR)/udns_parse.c $(UDNS_DIR)/udns_misc.c mod_enum_la_SOURCES += $(UDNS_DIR)/udns_dn.c $(UDNS_DIR)/udns_dntosp.c $(UDNS_DIR)/udns_parse.c $(UDNS_DIR)/udns_misc.c
mod_enum_la_SOURCES += $(UDNS_DIR)/udns_rr_a.c $(UDNS_DIR)/udns_rr_ptr.c $(UDNS_DIR)/udns_rr_mx.c $(UDNS_DIR)/udns_rr_txt.c $(UDNS_DIR)/udns_bl.c mod_enum_la_SOURCES += $(UDNS_DIR)/udns_rr_a.c $(UDNS_DIR)/udns_rr_ptr.c $(UDNS_DIR)/udns_rr_mx.c $(UDNS_DIR)/udns_rr_txt.c $(UDNS_DIR)/udns_bl.c
mod_enum_la_SOURCES += $(UDNS_DIR)/udns_rr_srv.c $(UDNS_DIR)/udns_rr_naptr.c $(UDNS_DIR)/udns_codes.c $(UDNS_DIR)/udns_resolver.c mod_enum_la_SOURCES += $(UDNS_DIR)/udns_rr_srv.c $(UDNS_DIR)/udns_rr_naptr.c $(UDNS_DIR)/udns_codes.c $(UDNS_DIR)/udns_resolver.c
mod_enum_la_CFLAGS = $(AM_CFLAGS)
mod_enum_la_LIBADD = $(switch_builddir)/libfreeswitch.la mod_enum_la_LIBADD = $(switch_builddir)/libfreeswitch.la
mod_enum_la_LDFLAGS = -avoid-version -module -no-undefined -shared mod_enum_la_LDFLAGS = -avoid-version -module -no-undefined -shared

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

@ -6,8 +6,7 @@ PALA=$(switch_builddir)/libs/portaudio/lib/libportaudio.la
mod_LTLIBRARIES = mod_portaudio.la mod_LTLIBRARIES = mod_portaudio.la
mod_portaudio_la_SOURCES = mod_portaudio.c pablio.c pa_ringbuffer.c mod_portaudio_la_SOURCES = mod_portaudio.c pablio.c pa_ringbuffer.c
mod_portaudio_la_CFLAGS = $(AM_CFLAGS) mod_portaudio_la_CFLAGS = -I. -I$(PA_DIR)/include -D__EXTENSION__=1 $(AM_CFLAGS)
mod_portaudio_la_CFLAGS += -I. -I$(PA_DIR)/include -D__EXTENSION__=1
mod_portaudio_la_LIBADD = $(switch_builddir)/libfreeswitch.la $(PALA) mod_portaudio_la_LIBADD = $(switch_builddir)/libfreeswitch.la $(PALA)
mod_portaudio_la_LDFLAGS = -avoid-version -module -no-undefined -shared $(PA_LIBS) mod_portaudio_la_LDFLAGS = -avoid-version -module -no-undefined -shared $(PA_LIBS)

View File

@ -3,7 +3,7 @@ include $(top_srcdir)/build/modmake.rulesam
MODNAME=mod_skinny MODNAME=mod_skinny
mod_LTLIBRARIES = mod_skinny.la mod_LTLIBRARIES = mod_skinny.la
mod_skinny_la_SOURCES = mod_skinny.c skinny_protocol.c skinny_tables.c mod_skinny_la_SOURCES = mod_skinny.c skinny_protocol.c skinny_tables.c skinny_api.c
mod_skinny_la_CFLAGS = $(AM_CFLAGS) -DSKINNY_SVN_VERSION=\"`cat $(switch_builddir)/.version`\" mod_skinny_la_CFLAGS = $(AM_CFLAGS)
mod_skinny_la_LIBADD = $(switch_builddir)/libfreeswitch.la mod_skinny_la_LIBADD = $(switch_builddir)/libfreeswitch.la
mod_skinny_la_LDFLAGS = -avoid-version -module -no-undefined -shared mod_skinny_la_LDFLAGS = -avoid-version -module -no-undefined -shared

View File

@ -49,7 +49,9 @@ sub send {
$parsed_count++; $parsed_count++;
} }
if($parsed_count != scalar(keys %{$self->{'data'}})) { if($parsed_count != scalar(keys %{$self->{'data'}})) {
printf "Incomplete message: %d out of %d\n", $parsed_count, scalar(keys %{$self->{'data'}}); printf "Incomplete message (type=%s (%X)) %d out of %d\n", Net::Skinny::Protocol::skinny_message_type2str($self->{'type'}), $self->{'type'},
$parsed_count, scalar(keys %{$self->{'data'}});
print Dumper(@$struct);
return; return;
} }
$self->{'socket'}->send_data($self->{'type'}, $raw); $self->{'socket'}->send_data($self->{'type'}, $raw);

File diff suppressed because it is too large Load Diff

View File

@ -42,50 +42,54 @@
#define SKINNY_EVENT_UNREGISTER "skinny::unregister" #define SKINNY_EVENT_UNREGISTER "skinny::unregister"
#define SKINNY_EVENT_EXPIRE "skinny::expire" #define SKINNY_EVENT_EXPIRE "skinny::expire"
#define SKINNY_EVENT_ALARM "skinny::alarm" #define SKINNY_EVENT_ALARM "skinny::alarm"
#define SKINNY_EVENT_CALL_STATE "skinny::call_state"
struct skinny_globals { struct skinny_globals {
/* data */ int running;
int calls; switch_memory_pool_t *pool;
switch_mutex_t *calls_mutex; switch_mutex_t *mutex;
switch_hash_t *profile_hash; switch_hash_t *profile_hash;
switch_event_node_t *heartbeat_node; switch_event_node_t *heartbeat_node;
int running; switch_event_node_t *call_state_node;
}; };
typedef struct skinny_globals skinny_globals_t; typedef struct skinny_globals skinny_globals_t;
skinny_globals_t globals; skinny_globals_t globals;
struct skinny_profile { struct skinny_profile {
/* prefs */ /* prefs */
char *name; char *name;
char *domain; char *domain;
char *ip; char *ip;
unsigned int port; unsigned int port;
char *dialplan; char *dialplan;
char *context; char *context;
uint32_t keep_alive; uint32_t keep_alive;
char date_format[6]; char date_format[6];
int debug; int debug;
/* db */ /* db */
char *dbname; char *dbname;
char *odbc_dsn; char *odbc_dsn;
char *odbc_user; char *odbc_user;
char *odbc_pass; char *odbc_pass;
switch_odbc_handle_t *master_odbc; switch_odbc_handle_t *master_odbc;
/* stats */ switch_mutex_t *sql_mutex;
uint32_t ib_calls; /* stats */
uint32_t ob_calls; uint32_t ib_calls;
uint32_t ib_failed_calls; uint32_t ob_calls;
uint32_t ob_failed_calls; uint32_t ib_failed_calls;
/* listener */ uint32_t ob_failed_calls;
int listener_threads; /* listener */
switch_mutex_t *listener_mutex; int listener_threads;
switch_socket_t *sock; switch_mutex_t *listener_mutex;
switch_mutex_t *sock_mutex; switch_socket_t *sock;
struct listener *listeners; switch_mutex_t *sock_mutex;
uint8_t listener_ready; struct listener *listeners;
/* call id */ uint8_t listener_ready;
uint32_t next_call_id; /* call id */
uint32_t next_call_id;
/* others */
switch_memory_pool_t *pool;
}; };
typedef struct skinny_profile skinny_profile_t; typedef struct skinny_profile skinny_profile_t;
@ -95,28 +99,26 @@ typedef struct skinny_profile skinny_profile_t;
/*****************************************************************************/ /*****************************************************************************/
typedef enum { typedef enum {
LFLAG_RUNNING = (1 << 0), LFLAG_RUNNING = (1 << 0),
} event_flag_t; } event_flag_t;
#define SKINNY_MAX_LINES 42 #define SKINNY_MAX_LINES 42
struct listener { struct listener {
skinny_profile_t *profile; skinny_profile_t *profile;
char device_name[16]; char device_name[16];
uint32_t device_instance; uint32_t device_instance;
switch_core_session_t *session[SKINNY_MAX_LINES];
uint32_t line_state[SKINNY_MAX_LINES]; /* See enum skinny_key_set */
switch_socket_t *sock; switch_socket_t *sock;
switch_memory_pool_t *pool; switch_memory_pool_t *pool;
switch_thread_rwlock_t *rwlock; switch_thread_rwlock_t *rwlock;
switch_sockaddr_t *sa; switch_sockaddr_t *sa;
char remote_ip[50]; char remote_ip[50];
switch_mutex_t *flag_mutex; switch_mutex_t *flag_mutex;
uint32_t flags; uint32_t flags;
switch_port_t remote_port; switch_port_t remote_port;
uint32_t id; uint32_t id;
time_t expire_time; time_t expire_time;
struct listener *next; struct listener *next;
}; };
typedef struct listener listener_t; typedef struct listener listener_t;
@ -127,83 +129,92 @@ typedef switch_status_t (*skinny_listener_callback_func_t) (listener_t *listener
/* CHANNEL TYPES */ /* CHANNEL TYPES */
/*****************************************************************************/ /*****************************************************************************/
typedef enum { typedef enum {
TFLAG_IO = (1 << 0), TFLAG_IO = (1 << 0),
TFLAG_INBOUND = (1 << 1), TFLAG_INBOUND = (1 << 1),
TFLAG_OUTBOUND = (1 << 2), TFLAG_OUTBOUND = (1 << 2),
TFLAG_DTMF = (1 << 3), TFLAG_DTMF = (1 << 3),
TFLAG_VOICE = (1 << 4), TFLAG_VOICE = (1 << 4),
TFLAG_HANGUP = (1 << 5), TFLAG_HANGUP = (1 << 5),
TFLAG_LINEAR = (1 << 6), TFLAG_LINEAR = (1 << 6),
TFLAG_CODEC = (1 << 7), TFLAG_CODEC = (1 << 7),
TFLAG_READING = (1 << 9), TFLAG_READING = (1 << 9),
TFLAG_WRITING = (1 << 10) TFLAG_WRITING = (1 << 10)
} TFLAGS; } TFLAGS;
typedef enum { typedef enum {
GFLAG_MY_CODEC_PREFS = (1 << 0) GFLAG_MY_CODEC_PREFS = (1 << 0)
} GFLAGS; } GFLAGS;
struct private_object { struct private_object {
unsigned int flags; unsigned int flags;
switch_frame_t read_frame; switch_frame_t read_frame;
unsigned char databuf[SWITCH_RECOMMENDED_BUFFER_SIZE]; unsigned char databuf[SWITCH_RECOMMENDED_BUFFER_SIZE];
switch_core_session_t *session; switch_core_session_t *session;
switch_caller_profile_t *caller_profile; switch_caller_profile_t *caller_profile;
switch_mutex_t *mutex; switch_mutex_t *mutex;
switch_mutex_t *flag_mutex; switch_mutex_t *flag_mutex;
/* identification */ /* identification */
struct listener *listener; uint32_t call_id;
uint32_t line; uint32_t party_id;
uint32_t call_id;
uint32_t party_id; skinny_profile_t *profile;
char *line_name;
char *line_shortname; /* codec */
char *line_displayname; char *iananame;
char dest[10]; switch_codec_t read_codec;
/* codec */ switch_codec_t write_codec;
char *iananame; switch_codec_implementation_t read_impl;
switch_codec_t read_codec; switch_codec_implementation_t write_impl;
switch_codec_t write_codec; unsigned long rm_rate;
switch_codec_implementation_t read_impl; uint32_t codec_ms;
switch_codec_implementation_t write_impl; char *rm_encoding;
unsigned long rm_rate; char *rm_fmtp;
uint32_t codec_ms; switch_payload_t agreed_pt;
char *rm_encoding; /* RTP */
char *rm_fmtp; switch_rtp_t *rtp_session;
switch_payload_t agreed_pt; char *local_sdp_audio_ip;
/* RTP */ switch_port_t local_sdp_audio_port;
switch_rtp_t *rtp_session; char *remote_sdp_audio_ip;
char *local_sdp_audio_ip; switch_port_t remote_sdp_audio_port;
switch_port_t local_sdp_audio_port;
char *remote_sdp_audio_ip;
switch_port_t remote_sdp_audio_port;
}; };
typedef struct private_object private_t; typedef struct private_object private_t;
/*****************************************************************************/
/* PROFILES FUNCTIONS */
/*****************************************************************************/
skinny_profile_t *skinny_find_profile(const char *profile_name);
switch_status_t skinny_profile_dump(const skinny_profile_t *profile, switch_stream_handle_t *stream);
switch_status_t skinny_profile_find_listener_by_device_name(skinny_profile_t *profile, const char *device_name, listener_t **listener);
switch_status_t skinny_profile_find_listener_by_device_name_and_instance(skinny_profile_t *profile, const char *device_name, uint32_t device_instance, listener_t **listener);
char * skinny_profile_find_session_uuid(skinny_profile_t *profile, listener_t *listener, uint32_t *line_instance_p, uint32_t call_id);
switch_core_session_t * skinny_profile_find_session(skinny_profile_t *profile, listener_t *listener, uint32_t *line_instance_p, uint32_t call_id);
switch_status_t dump_device(skinny_profile_t *profile, const char *device_name, switch_stream_handle_t *stream);
/*****************************************************************************/ /*****************************************************************************/
/* SQL FUNCTIONS */ /* SQL FUNCTIONS */
/*****************************************************************************/ /*****************************************************************************/
void skinny_execute_sql(skinny_profile_t *profile, char *sql, switch_mutex_t *mutex); void skinny_execute_sql(skinny_profile_t *profile, char *sql, switch_mutex_t *mutex);
switch_bool_t skinny_execute_sql_callback(skinny_profile_t *profile, switch_bool_t skinny_execute_sql_callback(skinny_profile_t *profile,
switch_mutex_t *mutex, char *sql, switch_core_db_callback_func_t callback, void *pdata); switch_mutex_t *mutex, char *sql, switch_core_db_callback_func_t callback, void *pdata);
/*****************************************************************************/ /*****************************************************************************/
/* LISTENER FUNCTIONS */ /* LISTENER FUNCTIONS */
/*****************************************************************************/ /*****************************************************************************/
uint8_t listener_is_ready(listener_t *listener);
switch_status_t keepalive_listener(listener_t *listener, void *pvt); switch_status_t keepalive_listener(listener_t *listener, void *pvt);
/*****************************************************************************/ /*****************************************************************************/
/* CHANNEL FUNCTIONS */ /* CHANNEL FUNCTIONS */
/*****************************************************************************/ /*****************************************************************************/
uint32_t skinny_line_perform_set_state(listener_t *listener, const char *file, const char *func, int line, uint32_t instance, uint32_t state, uint32_t call_id); void skinny_line_perform_set_state(const char *file, const char *func, int line, listener_t *listener, uint32_t line_instance, uint32_t call_id, uint32_t call_state);
#define skinny_line_set_state(listener, instance, state, call_id) skinny_line_perform_set_state(listener, __FILE__, __SWITCH_FUNC__, __LINE__, instance, state, call_id) #define skinny_line_set_state(listener, line_instance, call_id, call_state) skinny_line_perform_set_state(__FILE__, __SWITCH_FUNC__, __LINE__, listener, line_instance, call_id, call_state)
uint32_t skinny_line_get_state(listener_t *listener, uint32_t instance); uint32_t skinny_line_get_state(listener_t *listener, uint32_t line_instance, uint32_t call_id);
switch_status_t skinny_tech_set_codec(private_t *tech_pvt, int force); switch_status_t skinny_tech_set_codec(private_t *tech_pvt, int force);
void tech_init(private_t *tech_pvt, switch_core_session_t *session, listener_t *listener, uint32_t line); void tech_init(private_t *tech_pvt, skinny_profile_t *profile, switch_core_session_t *session);
switch_status_t channel_on_init(switch_core_session_t *session); switch_status_t channel_on_init(switch_core_session_t *session);
switch_status_t channel_on_hangup(switch_core_session_t *session); switch_status_t channel_on_hangup(switch_core_session_t *session);
switch_status_t channel_on_destroy(switch_core_session_t *session); switch_status_t channel_on_destroy(switch_core_session_t *session);
@ -211,8 +222,8 @@ switch_status_t channel_on_routing(switch_core_session_t *session);
switch_status_t channel_on_exchange_media(switch_core_session_t *session); switch_status_t channel_on_exchange_media(switch_core_session_t *session);
switch_status_t channel_on_soft_execute(switch_core_session_t *session); switch_status_t channel_on_soft_execute(switch_core_session_t *session);
switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event, switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event,
switch_caller_profile_t *outbound_profile, switch_caller_profile_t *outbound_profile,
switch_core_session_t **new_session, switch_memory_pool_t **pool, switch_originate_flag_t flags, switch_call_cause_t *cancel_cause); switch_core_session_t **new_session, switch_memory_pool_t **pool, switch_originate_flag_t flags, switch_call_cause_t *cancel_cause);
switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id); switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id);
switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id); switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id);
switch_status_t channel_kill_channel(switch_core_session_t *session, int sig); switch_status_t channel_kill_channel(switch_core_session_t *session, int sig);
@ -224,3 +235,14 @@ switch_endpoint_interface_t *skinny_get_endpoint_interface();
#endif /* _MOD_SKINNY_H */ #endif /* _MOD_SKINNY_H */
/* 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

@ -0,0 +1,473 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2010, Mathieu Parent <math.parent@gmail.com>
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Mathieu Parent <math.parent@gmail.com>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Mathieu Parent <math.parent@gmail.com>
*
*
* skinny_api.c -- Skinny Call Control Protocol (SCCP) Endpoint Module
*
*/
#include <switch.h>
#include "mod_skinny.h"
#include "skinny_protocol.h"
#include "skinny_tables.h"
/*****************************************************************************/
/* skinny_api_list_* */
/*****************************************************************************/
static switch_status_t skinny_api_list_profiles(const char *line, const char *cursor, switch_console_callback_match_t **matches)
{
switch_console_callback_match_t *my_matches = NULL;
switch_status_t status = SWITCH_STATUS_FALSE;
switch_hash_index_t *hi;
void *val;
skinny_profile_t *profile;
/* walk profiles */
switch_mutex_lock(globals.mutex);
for (hi = switch_hash_first(NULL, globals.profile_hash); hi; hi = switch_hash_next(hi)) {
switch_hash_this(hi, NULL, NULL, &val);
profile = (skinny_profile_t *) val;
switch_console_push_match(&my_matches, profile->name);
}
switch_mutex_unlock(globals.mutex);
if (my_matches) {
*matches = my_matches;
status = SWITCH_STATUS_SUCCESS;
}
return status;
}
struct match_helper {
switch_console_callback_match_t *my_matches;
};
static int skinny_api_list_devices_callback(void *pArg, int argc, char **argv, char **columnNames)
{
struct match_helper *h = (struct match_helper *) pArg;
char *device_name = argv[0];
switch_console_push_match(&h->my_matches, device_name);
return 0;
}
static switch_status_t skinny_api_list_devices(const char *line, const char *cursor, switch_console_callback_match_t **matches)
{
struct match_helper h = { 0 };
switch_status_t status = SWITCH_STATUS_FALSE;
skinny_profile_t *profile = NULL;
char *sql;
char *myline;
char *argv[1024] = { 0 };
int argc = 0;
if (!(myline = strdup(line))) {
status = SWITCH_STATUS_MEMERR;
return status;
}
if (!(argc = switch_separate_string(myline, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) || argc != 5) {
return status;
}
if(!strcasecmp(argv[1], "profile")) {/* skinny profile <profile_name> ... */
profile = skinny_find_profile(argv[2]);
} else if(!strcasecmp(argv[2], "profile")) {/* skinny status profile <profile_name> ... */
profile = skinny_find_profile(argv[3]);
}
if(profile) {
if ((sql = switch_mprintf("SELECT name FROM skinny_devices"))) {
skinny_execute_sql_callback(profile, profile->sql_mutex, sql, skinny_api_list_devices_callback, &h);
switch_safe_free(sql);
}
}
if (h.my_matches) {
*matches = h.my_matches;
status = SWITCH_STATUS_SUCCESS;
}
return status;
}
static switch_status_t skinny_api_list_reset_types(const char *line, const char *cursor, switch_console_callback_match_t **matches)
{
switch_status_t status = SWITCH_STATUS_FALSE;
SKINNY_PUSH_DEVICE_RESET_TYPES
return status;
}
static switch_status_t skinny_api_list_stimuli(const char *line, const char *cursor, switch_console_callback_match_t **matches)
{
switch_status_t status = SWITCH_STATUS_FALSE;
SKINNY_PUSH_STIMULI
return status;
}
static switch_status_t skinny_api_list_ring_types(const char *line, const char *cursor, switch_console_callback_match_t **matches)
{
switch_status_t status = SWITCH_STATUS_FALSE;
SKINNY_PUSH_RING_TYPES
return status;
}
static switch_status_t skinny_api_list_ring_modes(const char *line, const char *cursor, switch_console_callback_match_t **matches)
{
switch_status_t status = SWITCH_STATUS_FALSE;
SKINNY_PUSH_RING_MODES
return status;
}
static switch_status_t skinny_api_list_stimulus_instances(const char *line, const char *cursor, switch_console_callback_match_t **matches)
{
switch_status_t status = SWITCH_STATUS_FALSE;
switch_console_callback_match_t *my_matches = NULL;
switch_console_push_match(&my_matches, "<stimulus_instance>");
switch_console_push_match(&my_matches, "0");
if (my_matches) {
*matches = my_matches;
status = SWITCH_STATUS_SUCCESS;
}
return status;
}
static switch_status_t skinny_api_list_stimulus_modes(const char *line, const char *cursor, switch_console_callback_match_t **matches)
{
switch_status_t status = SWITCH_STATUS_FALSE;
SKINNY_PUSH_LAMP_MODES
return status;
}
static switch_status_t skinny_api_list_speaker_modes(const char *line, const char *cursor, switch_console_callback_match_t **matches)
{
switch_status_t status = SWITCH_STATUS_FALSE;
SKINNY_PUSH_SPEAKER_MODES
return status;
}
static switch_status_t skinny_api_list_call_states(const char *line, const char *cursor, switch_console_callback_match_t **matches)
{
switch_status_t status = SWITCH_STATUS_FALSE;
SKINNY_PUSH_CALL_STATES
return status;
}
static switch_status_t skinny_api_list_line_instances(const char *line, const char *cursor, switch_console_callback_match_t **matches)
{
switch_status_t status = SWITCH_STATUS_FALSE;
switch_console_callback_match_t *my_matches = NULL;
/* TODO */
switch_console_push_match(&my_matches, "1");
switch_console_push_match(&my_matches, "<line_instance>");
if (my_matches) {
*matches = my_matches;
status = SWITCH_STATUS_SUCCESS;
}
return status;
}
static switch_status_t skinny_api_list_call_ids(const char *line, const char *cursor, switch_console_callback_match_t **matches)
{
switch_status_t status = SWITCH_STATUS_FALSE;
switch_console_callback_match_t *my_matches = NULL;
/* TODO */
switch_console_push_match(&my_matches, "1345");
switch_console_push_match(&my_matches, "<call_id>");
if (my_matches) {
*matches = my_matches;
status = SWITCH_STATUS_SUCCESS;
}
return status;
}
/*****************************************************************************/
/* skinny_api_cmd_* */
/*****************************************************************************/
static switch_status_t skinny_api_cmd_status_profile(const char *profile_name, switch_stream_handle_t *stream)
{
skinny_profile_t *profile;
if ((profile = skinny_find_profile(profile_name))) {
skinny_profile_dump(profile, stream);
} else {
stream->write_function(stream, "Profile not found!\n");
}
return SWITCH_STATUS_SUCCESS;
}
static switch_status_t skinny_api_cmd_status_profile_device(const char *profile_name, const char *device_name, switch_stream_handle_t *stream)
{
skinny_profile_t *profile;
if ((profile = skinny_find_profile(profile_name))) {
dump_device(profile, device_name, stream);
} else {
stream->write_function(stream, "Profile not found!\n");
}
return SWITCH_STATUS_SUCCESS;
}
static switch_status_t skinny_api_cmd_profile_device_send_ringer_message(const char *profile_name, const char *device_name, const char *ring_type, const char *ring_mode, switch_stream_handle_t *stream)
{
skinny_profile_t *profile;
if ((profile = skinny_find_profile(profile_name))) {
listener_t *listener = NULL;
skinny_profile_find_listener_by_device_name(profile, device_name, &listener);
if(listener) {
send_set_ringer(listener, skinny_str2ring_type(ring_type), skinny_str2ring_mode(ring_mode), 0, 0);
} else {
stream->write_function(stream, "Listener not found!\n");
}
} else {
stream->write_function(stream, "Profile not found!\n");
}
return SWITCH_STATUS_SUCCESS;
}
static switch_status_t skinny_api_cmd_profile_device_send_lamp_message(const char *profile_name, const char *device_name, const char *stimulus, const char *instance, const char *lamp_mode, switch_stream_handle_t *stream)
{
skinny_profile_t *profile;
if ((profile = skinny_find_profile(profile_name))) {
listener_t *listener = NULL;
skinny_profile_find_listener_by_device_name(profile, device_name, &listener);
if(listener) {
send_set_lamp(listener, skinny_str2button(stimulus), atoi(instance), skinny_str2lamp_mode(lamp_mode));
} else {
stream->write_function(stream, "Listener not found!\n");
}
} else {
stream->write_function(stream, "Profile not found!\n");
}
return SWITCH_STATUS_SUCCESS;
}
static switch_status_t skinny_api_cmd_profile_device_send_speaker_mode_message(const char *profile_name, const char *device_name, const char *speaker_mode, switch_stream_handle_t *stream)
{
skinny_profile_t *profile;
if ((profile = skinny_find_profile(profile_name))) {
listener_t *listener = NULL;
skinny_profile_find_listener_by_device_name(profile, device_name, &listener);
if(listener) {
send_set_speaker_mode(listener, skinny_str2speaker_mode(speaker_mode));
} else {
stream->write_function(stream, "Listener not found!\n");
}
} else {
stream->write_function(stream, "Profile not found!\n");
}
return SWITCH_STATUS_SUCCESS;
}
static switch_status_t skinny_api_cmd_profile_device_send_call_state_message(const char *profile_name, const char *device_name, const char *call_state, const char *line_instance, const char *call_id, switch_stream_handle_t *stream)
{
skinny_profile_t *profile;
if ((profile = skinny_find_profile(profile_name))) {
listener_t *listener = NULL;
skinny_profile_find_listener_by_device_name(profile, device_name, &listener);
if(listener) {
send_call_state(listener, skinny_str2call_state(call_state), atoi(line_instance), atoi(call_id));
} else {
stream->write_function(stream, "Listener not found!\n");
}
} else {
stream->write_function(stream, "Profile not found!\n");
}
return SWITCH_STATUS_SUCCESS;
}
static switch_status_t skinny_api_cmd_profile_device_send_reset_message(const char *profile_name, const char *device_name, const char *reset_type, switch_stream_handle_t *stream)
{
skinny_profile_t *profile;
if ((profile = skinny_find_profile(profile_name))) {
listener_t *listener = NULL;
skinny_profile_find_listener_by_device_name(profile, device_name, &listener);
if(listener) {
send_reset(listener, skinny_str2device_reset_type(reset_type));
} else {
stream->write_function(stream, "Listener not found!\n");
}
} else {
stream->write_function(stream, "Profile not found!\n");
}
return SWITCH_STATUS_SUCCESS;
}
/*****************************************************************************/
/* API */
/*****************************************************************************/
SWITCH_STANDARD_API(skinny_function)
{
char *argv[1024] = { 0 };
int argc = 0;
char *mycmd = NULL;
switch_status_t status = SWITCH_STATUS_SUCCESS;
const char *usage_string = "USAGE:\n"
"--------------------------------------------------------------------------------\n"
"skinny help\n"
"skinny status profile <profile_name>\n"
"skinny status profile <profile_name> device <device_name>\n"
"skinny profile <profile_name> device <device_name> send ResetMessage [DeviceReset|DeviceRestart]\n"
"skinny profile <profile_name> device <device_name> send SetRingerMessage <ring_type> <ring_mode>\n"
"skinny profile <profile_name> device <device_name> send SetLampMessage <stimulus> <instance> <lamp_mode>\n"
"skinny profile <profile_name> device <device_name> send SetSpeakerModeMessage <speaker_mode>\n"
"skinny profile <profile_name> device <device_name> send CallStateMessage <call_state> <line_instance> <call_id>\n"
"--------------------------------------------------------------------------------\n";
if (session) {
return SWITCH_STATUS_FALSE;
}
if (zstr(cmd)) {
stream->write_function(stream, "%s", usage_string);
goto done;
}
if (!(mycmd = strdup(cmd))) {
status = SWITCH_STATUS_MEMERR;
goto done;
}
if (!(argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) || !argv[0]) {
stream->write_function(stream, "%s", usage_string);
goto done;
}
if (!strcasecmp(argv[0], "help")) {/* skinny help */
stream->write_function(stream, "%s", usage_string);
goto done;
} else if (argc == 3 && !strcasecmp(argv[0], "status") && !strcasecmp(argv[1], "profile")) {
/* skinny status profile <profile_name> */
status = skinny_api_cmd_status_profile(argv[2], stream);
} else if (argc == 5 && !strcasecmp(argv[0], "status") && !strcasecmp(argv[1], "profile") && !strcasecmp(argv[3], "device")) {
/* skinny status profile <profile_name> device <device_name> */
status = skinny_api_cmd_status_profile_device(argv[2], argv[4], stream);
} else if (argc >= 6 && !strcasecmp(argv[0], "profile") && !strcasecmp(argv[2], "device") && !strcasecmp(argv[4], "send")) {
/* skinny profile <profile_name> device <device_name> send ... */
switch(skinny_str2message_type(argv[5])) {
case SET_RINGER_MESSAGE:
if(argc == 8) {
/* SetRingerMessage <ring_type> <ring_mode> */
status = skinny_api_cmd_profile_device_send_ringer_message(argv[1], argv[3], argv[6], argv[7], stream);
}
break;
case SET_LAMP_MESSAGE:
if (argc == 9) {
/* SetLampMessage <stimulus> <instance> <lamp_mode> */
status = skinny_api_cmd_profile_device_send_lamp_message(argv[1], argv[3], argv[6], argv[7], argv[8], stream);
}
break;
case SET_SPEAKER_MODE_MESSAGE:
if (argc == 7) {
/* SetSpeakerModeMessage <speaker_mode> */
status = skinny_api_cmd_profile_device_send_speaker_mode_message(argv[1], argv[3], argv[6], stream);
}
break;
case CALL_STATE_MESSAGE:
if (argc == 9) {
/* CallStateMessage <call_state> <line_instance> <call_id> */
status = skinny_api_cmd_profile_device_send_call_state_message(argv[1], argv[3], argv[6], argv[7], argv[8], stream);
}
break;
case RESET_MESSAGE:
if (argc == 7) {
/* ResetMessage <reset_type> */
status = skinny_api_cmd_profile_device_send_reset_message(argv[1], argv[3], argv[6], stream);
}
break;
default:
stream->write_function(stream, "Unhandled message %s\n", argv[5]);
}
} else {
stream->write_function(stream, "Unknown Command [%s]\n", argv[0]);
}
done:
switch_safe_free(mycmd);
return status;
}
switch_status_t skinny_api_register(switch_loadable_module_interface_t **module_interface)
{
switch_api_interface_t *api_interface;
SWITCH_ADD_API(api_interface, "skinny", "Skinny Controls", skinny_function, "<cmd> <args>");
switch_console_set_complete("add skinny help");
switch_console_set_complete("add skinny status profile ::skinny::list_profiles");
switch_console_set_complete("add skinny status profile ::skinny::list_profiles device ::skinny::list_devices");
switch_console_set_complete("add skinny profile ::skinny::list_profiles device ::skinny::list_devices send ResetMessage ::skinny::list_reset_types");
switch_console_set_complete("add skinny profile ::skinny::list_profiles device ::skinny::list_devices send SetRingerMessage ::skinny::list_ring_types ::skinny::list_ring_modes");
switch_console_set_complete("add skinny profile ::skinny::list_profiles device ::skinny::list_devices send SetLampMessage ::skinny::list_stimuli ::skinny::list_stimulus_instances ::skinny::list_stimulus_modes");
switch_console_set_complete("add skinny profile ::skinny::list_profiles device ::skinny::list_devices send SetSpeakerModeMessage ::skinny::list_speaker_modes");
switch_console_set_complete("add skinny profile ::skinny::list_profiles device ::skinny::list_devices send CallStateMessage ::skinny::list_call_states ::skinny::list_line_instances ::skinny::list_call_ids");
switch_console_add_complete_func("::skinny::list_profiles", skinny_api_list_profiles);
switch_console_add_complete_func("::skinny::list_devices", skinny_api_list_devices);
switch_console_add_complete_func("::skinny::list_reset_types", skinny_api_list_reset_types);
switch_console_add_complete_func("::skinny::list_ring_types", skinny_api_list_ring_types);
switch_console_add_complete_func("::skinny::list_ring_modes", skinny_api_list_ring_modes);
switch_console_add_complete_func("::skinny::list_stimuli", skinny_api_list_stimuli);
switch_console_add_complete_func("::skinny::list_stimulus_instances", skinny_api_list_stimulus_instances);
switch_console_add_complete_func("::skinny::list_stimulus_modes", skinny_api_list_stimulus_modes);
switch_console_add_complete_func("::skinny::list_speaker_modes", skinny_api_list_speaker_modes);
switch_console_add_complete_func("::skinny::list_call_states", skinny_api_list_call_states);
switch_console_add_complete_func("::skinny::list_line_instances", skinny_api_list_line_instances);
switch_console_add_complete_func("::skinny::list_call_ids", skinny_api_list_call_ids);
return SWITCH_STATUS_SUCCESS;
}
/* 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

@ -0,0 +1,50 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2010, Mathieu Parent <math.parent@gmail.com>
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Mathieu Parent <math.parent@gmail.com>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Mathieu Parent <math.parent@gmail.com>
*
*
* skinny_api.h -- Skinny Call Control Protocol (SCCP) Endpoint Module
*
*/
#ifndef _SKINNY_API_H
#define _SKINNY_API_H
switch_status_t skinny_api_register(switch_loadable_module_interface_t **module_interface);
#endif /* _SKINNY_API_H */
/* 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:
*/

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -35,157 +35,169 @@
/* Translation tables */ /* Translation tables */
struct skinny_table SKINNY_MESSAGE_TYPES[] = { struct skinny_table SKINNY_MESSAGE_TYPES[] = {
{"KeepAliveMessage", KEEP_ALIVE_MESSAGE}, {"KeepAliveMessage", KEEP_ALIVE_MESSAGE},
{"RegisterMessage", REGISTER_MESSAGE}, {"RegisterMessage", REGISTER_MESSAGE},
{"PortMessage", PORT_MESSAGE}, {"PortMessage", PORT_MESSAGE},
{"KeypadButtonMessage", KEYPAD_BUTTON_MESSAGE}, {"KeypadButtonMessage", KEYPAD_BUTTON_MESSAGE},
{"StimulusMessage", STIMULUS_MESSAGE}, {"StimulusMessage", STIMULUS_MESSAGE},
{"OffHookMessage", OFF_HOOK_MESSAGE}, {"OffHookMessage", OFF_HOOK_MESSAGE},
{"OnHookMessage", ON_HOOK_MESSAGE}, {"OnHookMessage", ON_HOOK_MESSAGE},
{"SpeedDialStatReqMessage", SPEED_DIAL_STAT_REQ_MESSAGE}, {"SpeedDialStatReqMessage", SPEED_DIAL_STAT_REQ_MESSAGE},
{"LineStatReqMessage", LINE_STAT_REQ_MESSAGE}, {"LineStatReqMessage", LINE_STAT_REQ_MESSAGE},
{"ConfigStatReqMessage", CONFIG_STAT_REQ_MESSAGE}, {"ConfigStatReqMessage", CONFIG_STAT_REQ_MESSAGE},
{"TimeDateReqMessage", TIME_DATE_REQ_MESSAGE}, {"TimeDateReqMessage", TIME_DATE_REQ_MESSAGE},
{"ButtonTemplateReqMessage", BUTTON_TEMPLATE_REQ_MESSAGE}, {"ButtonTemplateReqMessage", BUTTON_TEMPLATE_REQ_MESSAGE},
{"CapabilitiesReqMessage", CAPABILITIES_RES_MESSAGE}, {"CapabilitiesReqMessage", CAPABILITIES_RES_MESSAGE},
{"AlarmMessage", ALARM_MESSAGE}, {"AlarmMessage", ALARM_MESSAGE},
{"OpenReceiveChannelAckMessage", OPEN_RECEIVE_CHANNEL_ACK_MESSAGE}, {"OpenReceiveChannelAckMessage", OPEN_RECEIVE_CHANNEL_ACK_MESSAGE},
{"SoftKeySetReqMessage", SOFT_KEY_SET_REQ_MESSAGE}, {"SoftKeySetReqMessage", SOFT_KEY_SET_REQ_MESSAGE},
{"SoftKeyEventMessage", SOFT_KEY_EVENT_MESSAGE}, {"SoftKeyEventMessage", SOFT_KEY_EVENT_MESSAGE},
{"UnregisterMessage", UNREGISTER_MESSAGE}, {"UnregisterMessage", UNREGISTER_MESSAGE},
{"SoftKeyTemplateReqMessage", SOFT_KEY_TEMPLATE_REQ_MESSAGE}, {"SoftKeyTemplateReqMessage", SOFT_KEY_TEMPLATE_REQ_MESSAGE},
{"ServiceUrlStatReqMessage", SERVICE_URL_STAT_REQ_MESSAGE}, {"ServiceUrlStatReqMessage", SERVICE_URL_STAT_REQ_MESSAGE},
{"FeatureStatReqMessage", FEATURE_STAT_REQ_MESSAGE}, {"FeatureStatReqMessage", FEATURE_STAT_REQ_MESSAGE},
{"HeadsetStatusMessage", HEADSET_STATUS_MESSAGE}, {"HeadsetStatusMessage", HEADSET_STATUS_MESSAGE},
{"RegisterAvailableLinesMessage", REGISTER_AVAILABLE_LINES_MESSAGE}, {"RegisterAvailableLinesMessage", REGISTER_AVAILABLE_LINES_MESSAGE},
{"RegisterAckMessage", REGISTER_ACK_MESSAGE}, {"RegisterAckMessage", REGISTER_ACK_MESSAGE},
{"StartToneMessage", START_TONE_MESSAGE}, {"StartToneMessage", START_TONE_MESSAGE},
{"StopToneMessage", STOP_TONE_MESSAGE}, {"StopToneMessage", STOP_TONE_MESSAGE},
{"SetRingerMessage", SET_RINGER_MESSAGE}, {"SetRingerMessage", SET_RINGER_MESSAGE},
{"SetLampMessage", SET_LAMP_MESSAGE}, {"SetLampMessage", SET_LAMP_MESSAGE},
{"SetSpeakerModeMessage", SET_SPEAKER_MODE_MESSAGE}, {"SetSpeakerModeMessage", SET_SPEAKER_MODE_MESSAGE},
{"StartMediaTransmissionMessage", START_MEDIA_TRANSMISSION_MESSAGE}, {"StartMediaTransmissionMessage", START_MEDIA_TRANSMISSION_MESSAGE},
{"StopMediaTransmissionMessage", STOP_MEDIA_TRANSMISSION_MESSAGE}, {"StopMediaTransmissionMessage", STOP_MEDIA_TRANSMISSION_MESSAGE},
{"CallInfoMessage", CALL_INFO_MESSAGE}, {"CallInfoMessage", CALL_INFO_MESSAGE},
{"SpeedDialStatResMessage", SPEED_DIAL_STAT_RES_MESSAGE}, {"SpeedDialStatResMessage", SPEED_DIAL_STAT_RES_MESSAGE},
{"LineStatResMessage", LINE_STAT_RES_MESSAGE}, {"LineStatResMessage", LINE_STAT_RES_MESSAGE},
{"ConfigStatResMessage", CONFIG_STAT_RES_MESSAGE}, {"ConfigStatResMessage", CONFIG_STAT_RES_MESSAGE},
{"DefineTimeDateMessage", DEFINE_TIME_DATE_MESSAGE}, {"DefineTimeDateMessage", DEFINE_TIME_DATE_MESSAGE},
{"ButtonTemplateResMessage", BUTTON_TEMPLATE_RES_MESSAGE}, {"ButtonTemplateResMessage", BUTTON_TEMPLATE_RES_MESSAGE},
{"CapabilitiesReqMessage", CAPABILITIES_REQ_MESSAGE}, {"CapabilitiesReqMessage", CAPABILITIES_REQ_MESSAGE},
{"RegisterRejMessage", REGISTER_REJ_MESSAGE}, {"RegisterRejectMessage", REGISTER_REJECT_MESSAGE},
{"ResetMessage", RESET_MESSAGE}, {"ResetMessage", RESET_MESSAGE},
{"KeepAliveAckMessage", KEEP_ALIVE_ACK_MESSAGE}, {"KeepAliveAckMessage", KEEP_ALIVE_ACK_MESSAGE},
{"OpenReceiveChannelMessage", OPEN_RECEIVE_CHANNEL_MESSAGE}, {"OpenReceiveChannelMessage", OPEN_RECEIVE_CHANNEL_MESSAGE},
{"OCloseReceiveChannelMessage", CLOSE_RECEIVE_CHANNEL_MESSAGE}, {"CloseReceiveChannelMessage", CLOSE_RECEIVE_CHANNEL_MESSAGE},
{"SoftKeyTemplateResMessage", SOFT_KEY_TEMPLATE_RES_MESSAGE}, {"SoftKeyTemplateResMessage", SOFT_KEY_TEMPLATE_RES_MESSAGE},
{"SoftKeySetResMessage", SOFT_KEY_SET_RES_MESSAGE}, {"SoftKeySetResMessage", SOFT_KEY_SET_RES_MESSAGE},
{"SelectSoftKeysMessage", SELECT_SOFT_KEYS_MESSAGE}, {"SelectSoftKeysMessage", SELECT_SOFT_KEYS_MESSAGE},
{"CallStateMessage", CALL_STATE_MESSAGE}, {"CallStateMessage", CALL_STATE_MESSAGE},
{"DisplayPromptStatusMessage", DISPLAY_PROMPT_STATUS_MESSAGE}, {"DisplayPromptStatusMessage", DISPLAY_PROMPT_STATUS_MESSAGE},
{"ClearPromptStatusMessage", CLEAR_PROMPT_STATUS_MESSAGE}, {"ClearPromptStatusMessage", CLEAR_PROMPT_STATUS_MESSAGE},
{"ActivateCallPlaneMessage", ACTIVATE_CALL_PLANE_MESSAGE}, {"ActivateCallPlaneMessage", ACTIVATE_CALL_PLANE_MESSAGE},
{"UnregisterAckMessage", UNREGISTER_ACK_MESSAGE}, {"UnregisterAckMessage", UNREGISTER_ACK_MESSAGE},
{"DialedNumberMessage", DIALED_NUMBER_MESSAGE}, {"DialedNumberMessage", DIALED_NUMBER_MESSAGE},
{"FeatureResMessage", FEATURE_STAT_RES_MESSAGE}, {"FeatureResMessage", FEATURE_STAT_RES_MESSAGE},
{"ServiceUrlStatMessage", SERVICE_URL_STAT_RES_MESSAGE}, {"DisplayPriNotifyMessage", DISPLAY_PRI_NOTIFY_MESSAGE},
{NULL, 0} {"ServiceUrlStatMessage", SERVICE_URL_STAT_RES_MESSAGE},
{NULL, 0}
}; };
SKINNY_DECLARE_ID2STR(skinny_message_type2str, SKINNY_MESSAGE_TYPES, "UnknownMessage") SKINNY_DECLARE_ID2STR(skinny_message_type2str, SKINNY_MESSAGE_TYPES, "UnknownMessage")
SKINNY_DECLARE_STR2ID(skinny_str2message_type, SKINNY_MESSAGE_TYPES, -1) SKINNY_DECLARE_STR2ID(skinny_str2message_type, SKINNY_MESSAGE_TYPES, -1)
struct skinny_table SKINNY_RING_TYPES[] = { struct skinny_table SKINNY_RING_TYPES[] = {
{"RingOff", SKINNY_RING_OFF}, {"RingOff", SKINNY_RING_OFF},
{"RingInside", SKINNY_RING_INSIDE}, {"RingInside", SKINNY_RING_INSIDE},
{"RingOutside", SKINNY_RING_OUTSIDE}, {"RingOutside", SKINNY_RING_OUTSIDE},
{"RingFeature", SKINNY_RING_FEATURE}, {"RingFeature", SKINNY_RING_FEATURE},
{NULL, 0} {NULL, 0}
}; };
SKINNY_DECLARE_ID2STR(skinny_ring_type2str, SKINNY_RING_TYPES, "RingTypeUnknown") SKINNY_DECLARE_ID2STR(skinny_ring_type2str, SKINNY_RING_TYPES, "RingTypeUnknown")
SKINNY_DECLARE_STR2ID(skinny_str2ring_type, SKINNY_RING_TYPES, -1) SKINNY_DECLARE_STR2ID(skinny_str2ring_type, SKINNY_RING_TYPES, -1)
struct skinny_table SKINNY_RING_MODES[] = { struct skinny_table SKINNY_RING_MODES[] = {
{"RingForever", SKINNY_RING_FOREVER}, {"RingForever", SKINNY_RING_FOREVER},
{"RingOnce", SKINNY_RING_ONCE}, {"RingOnce", SKINNY_RING_ONCE},
{NULL, 0} {NULL, 0}
}; };
SKINNY_DECLARE_ID2STR(skinny_ring_mode2str, SKINNY_RING_MODES, "RingModeUnknown") SKINNY_DECLARE_ID2STR(skinny_ring_mode2str, SKINNY_RING_MODES, "RingModeUnknown")
SKINNY_DECLARE_STR2ID(skinny_str2ring_mode, SKINNY_RING_MODES, -1) SKINNY_DECLARE_STR2ID(skinny_str2ring_mode, SKINNY_RING_MODES, -1)
struct skinny_table SKINNY_BUTTONS[] = { struct skinny_table SKINNY_BUTTONS[] = {
{"Unknown", SKINNY_BUTTON_UNKNOWN}, {"Unknown", SKINNY_BUTTON_UNKNOWN},
{"LastNumberRedial", SKINNY_BUTTON_LAST_NUMBER_REDIAL}, {"LastNumberRedial", SKINNY_BUTTON_LAST_NUMBER_REDIAL},
{"SpeedDial", SKINNY_BUTTON_SPEED_DIAL}, {"SpeedDial", SKINNY_BUTTON_SPEED_DIAL},
{"Line", SKINNY_BUTTON_LINE}, {"Line", SKINNY_BUTTON_LINE},
{"Voicemail", SKINNY_BUTTON_VOICEMAIL}, {"Voicemail", SKINNY_BUTTON_VOICEMAIL},
{"Privacy", SKINNY_BUTTON_PRIVACY}, {"Privacy", SKINNY_BUTTON_PRIVACY},
{"ServiceUrl", SKINNY_BUTTON_SERVICE_URL}, {"ServiceUrl", SKINNY_BUTTON_SERVICE_URL},
{"Undefined", SKINNY_BUTTON_UNDEFINED}, {"Undefined", SKINNY_BUTTON_UNDEFINED},
{NULL, 0} {NULL, 0}
}; };
SKINNY_DECLARE_ID2STR(skinny_button2str, SKINNY_BUTTONS, "Unknown") SKINNY_DECLARE_ID2STR(skinny_button2str, SKINNY_BUTTONS, "Unknown")
SKINNY_DECLARE_STR2ID(skinny_str2button, SKINNY_BUTTONS, -1) SKINNY_DECLARE_STR2ID(skinny_str2button, SKINNY_BUTTONS, -1)
struct skinny_table SKINNY_LAMP_MODES[] = { struct skinny_table SKINNY_LAMP_MODES[] = {
{"Off", SKINNY_LAMP_OFF}, {"Off", SKINNY_LAMP_OFF},
{"On", SKINNY_LAMP_ON}, {"On", SKINNY_LAMP_ON},
{"Wink", SKINNY_LAMP_WINK}, {"Wink", SKINNY_LAMP_WINK},
{"Flash", SKINNY_LAMP_FLASH}, {"Flash", SKINNY_LAMP_FLASH},
{"Blink", SKINNY_LAMP_BLINK}, {"Blink", SKINNY_LAMP_BLINK},
{NULL, 0} {NULL, 0}
}; };
SKINNY_DECLARE_ID2STR(skinny_lamp_mode2str, SKINNY_LAMP_MODES, "Unknown") SKINNY_DECLARE_ID2STR(skinny_lamp_mode2str, SKINNY_LAMP_MODES, "Unknown")
SKINNY_DECLARE_STR2ID(skinny_str2lamp_mode, SKINNY_LAMP_MODES, -1) SKINNY_DECLARE_STR2ID(skinny_str2lamp_mode, SKINNY_LAMP_MODES, -1)
struct skinny_table SKINNY_SPEAKER_MODES[] = { struct skinny_table SKINNY_SPEAKER_MODES[] = {
{"SpeakerOn", SKINNY_SPEAKER_ON}, {"SpeakerOn", SKINNY_SPEAKER_ON},
{"SpeakerOff", SKINNY_SPEAKER_OFF}, {"SpeakerOff", SKINNY_SPEAKER_OFF},
{NULL, 0} {NULL, 0}
}; };
SKINNY_DECLARE_ID2STR(skinny_speaker_mode2str, SKINNY_SPEAKER_MODES, "Unknown") SKINNY_DECLARE_ID2STR(skinny_speaker_mode2str, SKINNY_SPEAKER_MODES, "Unknown")
SKINNY_DECLARE_STR2ID(skinny_str2speaker_mode, SKINNY_SPEAKER_MODES, -1) SKINNY_DECLARE_STR2ID(skinny_str2speaker_mode, SKINNY_SPEAKER_MODES, -1)
struct skinny_table SKINNY_KEY_SETS[] = { struct skinny_table SKINNY_KEY_SETS[] = {
{"KeySetOnHook", SKINNY_KEY_SET_ON_HOOK}, {"KeySetOnHook", SKINNY_KEY_SET_ON_HOOK},
{"KeySetConnected", SKINNY_KEY_SET_CONNECTED}, {"KeySetConnected", SKINNY_KEY_SET_CONNECTED},
{"KeySetOnHold", SKINNY_KEY_SET_ON_HOLD}, {"KeySetOnHold", SKINNY_KEY_SET_ON_HOLD},
{"KeySetRingIn", SKINNY_KEY_SET_RING_IN}, {"KeySetRingIn", SKINNY_KEY_SET_RING_IN},
{"KeySetOffHook", SKINNY_KEY_SET_OFF_HOOK}, {"KeySetOffHook", SKINNY_KEY_SET_OFF_HOOK},
{"KeySetConnectedWithTransfer", SKINNY_KEY_SET_CONNECTED_WITH_TRANSFER}, {"KeySetConnectedWithTransfer", SKINNY_KEY_SET_CONNECTED_WITH_TRANSFER},
{"KeySetDigitsAfterDialingFirstDigit", SKINNY_KEY_SET_DIGITS_AFTER_DIALING_FIRST_DIGIT}, {"KeySetDigitsAfterDialingFirstDigit", SKINNY_KEY_SET_DIGITS_AFTER_DIALING_FIRST_DIGIT},
{"KeySetConnectedWithConference", SKINNY_KEY_SET_CONNECTED_WITH_CONFERENCE}, {"KeySetConnectedWithConference", SKINNY_KEY_SET_CONNECTED_WITH_CONFERENCE},
{"KeySetRingOut", SKINNY_KEY_SET_RING_OUT}, {"KeySetRingOut", SKINNY_KEY_SET_RING_OUT},
{"KeySetOffHookWithFeatures", SKINNY_KEY_SET_OFF_HOOK_WITH_FEATURES}, {"KeySetOffHookWithFeatures", SKINNY_KEY_SET_OFF_HOOK_WITH_FEATURES},
{NULL, 0} {NULL, 0}
}; };
SKINNY_DECLARE_ID2STR(skinny_soft_key_set2str, SKINNY_KEY_SETS, "UNKNOWN_SOFT_KEY_SET") SKINNY_DECLARE_ID2STR(skinny_soft_key_set2str, SKINNY_KEY_SETS, "UNKNOWN_SOFT_KEY_SET")
SKINNY_DECLARE_STR2ID(skinny_str2soft_key_set, SKINNY_KEY_SETS, -1) SKINNY_DECLARE_STR2ID(skinny_str2soft_key_set, SKINNY_KEY_SETS, -1)
struct skinny_table SKINNY_CALL_STATES[] = { struct skinny_table SKINNY_CALL_STATES[] = {
{"OffHook", SKINNY_OFF_HOOK}, {"OffHook", SKINNY_OFF_HOOK},
{"OnHook", SKINNY_ON_HOOK}, {"OnHook", SKINNY_ON_HOOK},
{"RingOut", SKINNY_RING_OUT}, {"RingOut", SKINNY_RING_OUT},
{"RingIn", SKINNY_RING_IN}, {"RingIn", SKINNY_RING_IN},
{"Connected", SKINNY_CONNECTED}, {"Connected", SKINNY_CONNECTED},
{"Busy", SKINNY_BUSY}, {"Busy", SKINNY_BUSY},
{"Congestion", SKINNY_CONGESTION}, {"LineInUse", SKINNY_LINE_IN_USE},
{"Hold", SKINNY_HOLD}, {"Hold", SKINNY_HOLD},
{"CallWaiting", SKINNY_CALL_WAITING}, {"CallWaiting", SKINNY_CALL_WAITING},
{"CallTransfer", SKINNY_CALL_TRANSFER}, {"CallTransfer", SKINNY_CALL_TRANSFER},
{"CallPark", SKINNY_CALL_PARK}, {"CallPark", SKINNY_CALL_PARK},
{"Proceed", SKINNY_PROCEED}, {"Proceed", SKINNY_PROCEED},
{"CallRemoteMultiline", SKINNY_CALL_REMOTE_MULTILINE}, {"InUseRemotely", SKINNY_IN_USE_REMOTELY},
{"InvalidNumber", SKINNY_INVALID_NUMBER}, {"InvalidNumber", SKINNY_INVALID_NUMBER},
{NULL, 0} {NULL, 0}
}; };
SKINNY_DECLARE_ID2STR(skinny_call_state2str, SKINNY_CALL_STATES, "CallStateUnknown") SKINNY_DECLARE_ID2STR(skinny_call_state2str, SKINNY_CALL_STATES, "CallStateUnknown")
SKINNY_DECLARE_STR2ID(skinny_str2call_state, SKINNY_CALL_STATES, -1) SKINNY_DECLARE_STR2ID(skinny_str2call_state, SKINNY_CALL_STATES, -1)
struct skinny_table SKINNY_DEVICE_RESET_TYPES[] = { struct skinny_table SKINNY_DEVICE_RESET_TYPES[] = {
{"DeviceReset", SKINNY_DEVICE_RESET}, {"DeviceReset", SKINNY_DEVICE_RESET},
{"DeviceRestart", SKINNY_DEVICE_RESTART}, {"DeviceRestart", SKINNY_DEVICE_RESTART},
{NULL, 0} {NULL, 0}
}; };
SKINNY_DECLARE_ID2STR(skinny_device_reset_type2str, SKINNY_DEVICE_RESET_TYPES, "DeviceResetTypeUnknown") SKINNY_DECLARE_ID2STR(skinny_device_reset_type2str, SKINNY_DEVICE_RESET_TYPES, "DeviceResetTypeUnknown")
SKINNY_DECLARE_STR2ID(skinny_str2device_reset_type, SKINNY_DEVICE_RESET_TYPES, -1) SKINNY_DECLARE_STR2ID(skinny_str2device_reset_type, SKINNY_DEVICE_RESET_TYPES, -1)
/* 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

@ -36,74 +36,74 @@
/* SKINNY TABLES */ /* SKINNY TABLES */
/*****************************************************************************/ /*****************************************************************************/
struct skinny_table { struct skinny_table {
const char *name; const char *name;
uint32_t id; uint32_t id;
}; };
#define SKINNY_DECLARE_ID2STR(func, TABLE, DEFAULT_STR) \ #define SKINNY_DECLARE_ID2STR(func, TABLE, DEFAULT_STR) \
const char *func(uint32_t id) \ const char *func(uint32_t id) \
{ \ { \
const char *str = DEFAULT_STR; \ const char *str = DEFAULT_STR; \
\ \
for (uint8_t x = 0; x < (sizeof(TABLE) / sizeof(struct skinny_table)) - 1; x++) {\ for (uint8_t x = 0; x < (sizeof(TABLE) / sizeof(struct skinny_table)) - 1; x++) {\
if (TABLE[x].id == id) {\ if (TABLE[x].id == id) {\
str = TABLE[x].name;\ str = TABLE[x].name;\
break;\ break;\
}\ }\
}\ }\
\ \
return str;\ return str;\
} }
#define SKINNY_DECLARE_STR2ID(func, TABLE, DEFAULT_ID) \ #define SKINNY_DECLARE_STR2ID(func, TABLE, DEFAULT_ID) \
uint32_t func(const char *str)\ uint32_t func(const char *str)\
{\ {\
uint32_t id = DEFAULT_ID;\ uint32_t id = DEFAULT_ID;\
\ \
if (*str > 47 && *str < 58) {\ if (*str > 47 && *str < 58) {\
id = atoi(str);\ id = atoi(str);\
} else {\ } else {\
for (uint8_t x = 0; x < (sizeof(TABLE) / sizeof(struct skinny_table)) - 1 && TABLE[x].name; x++) {\ for (uint8_t x = 0; x < (sizeof(TABLE) / sizeof(struct skinny_table)) - 1 && TABLE[x].name; x++) {\
if (!strcasecmp(TABLE[x].name, str)) {\ if (!strcasecmp(TABLE[x].name, str)) {\
id = TABLE[x].id;\ id = TABLE[x].id;\
break;\ break;\
}\ }\
}\ }\
}\ }\
return id;\ return id;\
} }
#define SKINNY_DECLARE_PUSH_MATCH(TABLE) \ #define SKINNY_DECLARE_PUSH_MATCH(TABLE) \
switch_console_callback_match_t *my_matches = NULL;\ switch_console_callback_match_t *my_matches = NULL;\
for (uint8_t x = 0; x < (sizeof(TABLE) / sizeof(struct skinny_table)) - 1; x++) {\ for (uint8_t x = 0; x < (sizeof(TABLE) / sizeof(struct skinny_table)) - 1; x++) {\
switch_console_push_match(&my_matches, TABLE[x].name);\ switch_console_push_match(&my_matches, TABLE[x].name);\
}\ }\
if (my_matches) {\ if (my_matches) {\
*matches = my_matches;\ *matches = my_matches;\
status = SWITCH_STATUS_SUCCESS;\ status = SWITCH_STATUS_SUCCESS;\
} }
struct skinny_table SKINNY_MESSAGE_TYPES[55]; struct skinny_table SKINNY_MESSAGE_TYPES[56];
const char *skinny_message_type2str(uint32_t id); const char *skinny_message_type2str(uint32_t id);
uint32_t skinny_str2message_type(const char *str); uint32_t skinny_str2message_type(const char *str);
#define SKINNY_PUSH_MESSAGE_TYPES SKINNY_DECLARE_PUSH_MATCH(SKINNY_MESSAGE_TYPES) #define SKINNY_PUSH_MESSAGE_TYPES SKINNY_DECLARE_PUSH_MATCH(SKINNY_MESSAGE_TYPES)
enum skinny_tone { enum skinny_tone {
SKINNY_TONE_SILENCE = 0x00, SKINNY_TONE_SILENCE = 0x00,
SKINNY_TONE_DIALTONE = 0x21, SKINNY_TONE_DIALTONE = 0x21,
SKINNY_TONE_BUSYTONE = 0x23, SKINNY_TONE_BUSYTONE = 0x23,
SKINNY_TONE_ALERT = 0x24, SKINNY_TONE_ALERT = 0x24,
SKINNY_TONE_REORDER = 0x25, SKINNY_TONE_REORDER = 0x25,
SKINNY_TONE_CALLWAITTONE = 0x2D, SKINNY_TONE_CALLWAITTONE = 0x2D,
SKINNY_TONE_NOTONE = 0x7F, SKINNY_TONE_NOTONE = 0x7F,
}; };
enum skinny_ring_type { enum skinny_ring_type {
SKINNY_RING_OFF = 1, SKINNY_RING_OFF = 1,
SKINNY_RING_INSIDE = 2, SKINNY_RING_INSIDE = 2,
SKINNY_RING_OUTSIDE = 3, SKINNY_RING_OUTSIDE = 3,
SKINNY_RING_FEATURE = 4 SKINNY_RING_FEATURE = 4
}; };
struct skinny_table SKINNY_RING_TYPES[5]; struct skinny_table SKINNY_RING_TYPES[5];
const char *skinny_ring_type2str(uint32_t id); const char *skinny_ring_type2str(uint32_t id);
@ -111,8 +111,8 @@ uint32_t skinny_str2ring_type(const char *str);
#define SKINNY_PUSH_RING_TYPES SKINNY_DECLARE_PUSH_MATCH(SKINNY_RING_TYPES) #define SKINNY_PUSH_RING_TYPES SKINNY_DECLARE_PUSH_MATCH(SKINNY_RING_TYPES)
enum skinny_ring_mode { enum skinny_ring_mode {
SKINNY_RING_FOREVER = 1, SKINNY_RING_FOREVER = 1,
SKINNY_RING_ONCE = 2, SKINNY_RING_ONCE = 2,
}; };
struct skinny_table SKINNY_RING_MODES[3]; struct skinny_table SKINNY_RING_MODES[3];
const char *skinny_ring_mode2str(uint32_t id); const char *skinny_ring_mode2str(uint32_t id);
@ -121,11 +121,11 @@ uint32_t skinny_str2ring_mode(const char *str);
enum skinny_lamp_mode { enum skinny_lamp_mode {
SKINNY_LAMP_OFF = 1, SKINNY_LAMP_OFF = 1,
SKINNY_LAMP_ON = 2, SKINNY_LAMP_ON = 2,
SKINNY_LAMP_WINK = 3, SKINNY_LAMP_WINK = 3,
SKINNY_LAMP_FLASH = 4, SKINNY_LAMP_FLASH = 4,
SKINNY_LAMP_BLINK = 5, SKINNY_LAMP_BLINK = 5,
}; };
struct skinny_table SKINNY_LAMP_MODES[6]; struct skinny_table SKINNY_LAMP_MODES[6];
const char *skinny_lamp_mode2str(uint32_t id); const char *skinny_lamp_mode2str(uint32_t id);
@ -133,8 +133,8 @@ uint32_t skinny_str2lamp_mode(const char *str);
#define SKINNY_PUSH_LAMP_MODES SKINNY_DECLARE_PUSH_MATCH(SKINNY_LAMP_MODES) #define SKINNY_PUSH_LAMP_MODES SKINNY_DECLARE_PUSH_MATCH(SKINNY_LAMP_MODES)
enum skinny_speaker_mode { enum skinny_speaker_mode {
SKINNY_SPEAKER_ON = 1, SKINNY_SPEAKER_ON = 1,
SKINNY_SPEAKER_OFF = 2, SKINNY_SPEAKER_OFF = 2,
}; };
struct skinny_table SKINNY_SPEAKER_MODES[3]; struct skinny_table SKINNY_SPEAKER_MODES[3];
const char *skinny_speaker_mode2str(uint32_t id); const char *skinny_speaker_mode2str(uint32_t id);
@ -142,20 +142,20 @@ uint32_t skinny_str2speaker_mode(const char *str);
#define SKINNY_PUSH_SPEAKER_MODES SKINNY_DECLARE_PUSH_MATCH(SKINNY_SPEAKER_MODES) #define SKINNY_PUSH_SPEAKER_MODES SKINNY_DECLARE_PUSH_MATCH(SKINNY_SPEAKER_MODES)
enum skinny_call_type { enum skinny_call_type {
SKINNY_INBOUND_CALL = 1, SKINNY_INBOUND_CALL = 1,
SKINNY_OUTBOUND_CALL = 2, SKINNY_OUTBOUND_CALL = 2,
SKINNY_FORWARD_CALL = 3, SKINNY_FORWARD_CALL = 3,
}; };
enum skinny_button_definition { enum skinny_button_definition {
SKINNY_BUTTON_UNKNOWN = 0x00, SKINNY_BUTTON_UNKNOWN = 0x00,
SKINNY_BUTTON_LAST_NUMBER_REDIAL = 0x01, SKINNY_BUTTON_LAST_NUMBER_REDIAL = 0x01,
SKINNY_BUTTON_SPEED_DIAL = 0x02, SKINNY_BUTTON_SPEED_DIAL = 0x02,
SKINNY_BUTTON_LINE = 0x09, SKINNY_BUTTON_LINE = 0x09,
SKINNY_BUTTON_VOICEMAIL = 0x0F, SKINNY_BUTTON_VOICEMAIL = 0x0F,
SKINNY_BUTTON_PRIVACY = 0x13, SKINNY_BUTTON_PRIVACY = 0x13,
SKINNY_BUTTON_SERVICE_URL = 0x14, SKINNY_BUTTON_SERVICE_URL = 0x14,
SKINNY_BUTTON_UNDEFINED = 0xFF, SKINNY_BUTTON_UNDEFINED = 0xFF,
}; };
struct skinny_table SKINNY_BUTTONS[9]; struct skinny_table SKINNY_BUTTONS[9];
const char *skinny_button2str(uint32_t id); const char *skinny_button2str(uint32_t id);
@ -163,39 +163,39 @@ uint32_t skinny_str2button(const char *str);
#define SKINNY_PUSH_STIMULI SKINNY_DECLARE_PUSH_MATCH(SKINNY_BUTTONS) #define SKINNY_PUSH_STIMULI SKINNY_DECLARE_PUSH_MATCH(SKINNY_BUTTONS)
enum skinny_soft_key_event { enum skinny_soft_key_event {
SOFTKEY_REDIAL = 0x01, SOFTKEY_REDIAL = 0x01,
SOFTKEY_NEWCALL = 0x02, SOFTKEY_NEWCALL = 0x02,
SOFTKEY_HOLD = 0x03, SOFTKEY_HOLD = 0x03,
SOFTKEY_TRANSFER = 0x04, SOFTKEY_TRANSFER = 0x04,
SOFTKEY_CFWDALL = 0x05, SOFTKEY_CFWDALL = 0x05,
SOFTKEY_CFWDBUSY = 0x06, SOFTKEY_CFWDBUSY = 0x06,
SOFTKEY_CFWDNOANSWER = 0x07, SOFTKEY_CFWDNOANSWER = 0x07,
SOFTKEY_BACKSPACE = 0x08, SOFTKEY_BACKSPACE = 0x08,
SOFTKEY_ENDCALL = 0x09, SOFTKEY_ENDCALL = 0x09,
SOFTKEY_RESUME = 0x0A, SOFTKEY_RESUME = 0x0A,
SOFTKEY_ANSWER = 0x0B, SOFTKEY_ANSWER = 0x0B,
SOFTKEY_INFO = 0x0C, SOFTKEY_INFO = 0x0C,
SOFTKEY_CONFRM = 0x0D, SOFTKEY_CONFRM = 0x0D,
SOFTKEY_PARK = 0x0E, SOFTKEY_PARK = 0x0E,
SOFTKEY_JOIN = 0x0F, SOFTKEY_JOIN = 0x0F,
SOFTKEY_MEETMECONFRM = 0x10, SOFTKEY_MEETMECONFRM = 0x10,
SOFTKEY_CALLPICKUP = 0x11, SOFTKEY_CALLPICKUP = 0x11,
SOFTKEY_GRPCALLPICKUP = 0x12, SOFTKEY_GRPCALLPICKUP = 0x12,
SOFTKEY_DND = 0x13, SOFTKEY_DND = 0x13,
SOFTKEY_IDIVERT = 0x14, SOFTKEY_IDIVERT = 0x14,
}; };
enum skinny_key_set { enum skinny_key_set {
SKINNY_KEY_SET_ON_HOOK = 0, SKINNY_KEY_SET_ON_HOOK = 0,
SKINNY_KEY_SET_CONNECTED = 1, SKINNY_KEY_SET_CONNECTED = 1,
SKINNY_KEY_SET_ON_HOLD = 2, SKINNY_KEY_SET_ON_HOLD = 2,
SKINNY_KEY_SET_RING_IN = 3, SKINNY_KEY_SET_RING_IN = 3,
SKINNY_KEY_SET_OFF_HOOK = 4, SKINNY_KEY_SET_OFF_HOOK = 4,
SKINNY_KEY_SET_CONNECTED_WITH_TRANSFER = 5, SKINNY_KEY_SET_CONNECTED_WITH_TRANSFER = 5,
SKINNY_KEY_SET_DIGITS_AFTER_DIALING_FIRST_DIGIT = 6, SKINNY_KEY_SET_DIGITS_AFTER_DIALING_FIRST_DIGIT = 6,
SKINNY_KEY_SET_CONNECTED_WITH_CONFERENCE = 7, SKINNY_KEY_SET_CONNECTED_WITH_CONFERENCE = 7,
SKINNY_KEY_SET_RING_OUT = 8, SKINNY_KEY_SET_RING_OUT = 8,
SKINNY_KEY_SET_OFF_HOOK_WITH_FEATURES = 9, SKINNY_KEY_SET_OFF_HOOK_WITH_FEATURES = 9,
}; };
struct skinny_table SKINNY_KEY_SETS[11]; struct skinny_table SKINNY_KEY_SETS[11];
const char *skinny_soft_key_set2str(uint32_t id); const char *skinny_soft_key_set2str(uint32_t id);
@ -204,20 +204,20 @@ uint32_t skinny_str2soft_key_set(const char *str);
enum skinny_call_state { enum skinny_call_state {
SKINNY_OFF_HOOK = 1, SKINNY_OFF_HOOK = 1,
SKINNY_ON_HOOK = 2, SKINNY_ON_HOOK = 2,
SKINNY_RING_OUT = 3, SKINNY_RING_OUT = 3,
SKINNY_RING_IN = 4, SKINNY_RING_IN = 4,
SKINNY_CONNECTED = 5, SKINNY_CONNECTED = 5,
SKINNY_BUSY = 6, SKINNY_BUSY = 6,
SKINNY_CONGESTION = 7, SKINNY_LINE_IN_USE = 7,
SKINNY_HOLD = 8, SKINNY_HOLD = 8,
SKINNY_CALL_WAITING = 9, SKINNY_CALL_WAITING = 9,
SKINNY_CALL_TRANSFER = 10, SKINNY_CALL_TRANSFER = 10,
SKINNY_CALL_PARK = 11, SKINNY_CALL_PARK = 11,
SKINNY_PROCEED = 12, SKINNY_PROCEED = 12,
SKINNY_CALL_REMOTE_MULTILINE = 13, SKINNY_IN_USE_REMOTELY = 13,
SKINNY_INVALID_NUMBER = 14 SKINNY_INVALID_NUMBER = 14
}; };
struct skinny_table SKINNY_CALL_STATES[15]; struct skinny_table SKINNY_CALL_STATES[15];
const char *skinny_call_state2str(uint32_t id); const char *skinny_call_state2str(uint32_t id);
@ -235,3 +235,14 @@ uint32_t skinny_str2device_reset_type(const char *str);
#endif /* _SKINNY_TABLES_H */ #endif /* _SKINNY_TABLES_H */
/* 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

@ -11,12 +11,13 @@ BEGIN {
use strict; use strict;
use warnings; use warnings;
use Sys::Hostname;
use Net::Skinny; use Net::Skinny;
use Net::Skinny::Protocol qw/:all/; use Net::Skinny::Protocol qw/:all/;
use Net::Skinny::Message; use Net::Skinny::Message;
#Config #Config
my $skinny_server = '127.0.0.1'; my $skinny_server = hostname;
my $device_name = "SEP001120AABBCC"; my $device_name = "SEP001120AABBCC";
my $device_ip = 10+256*(11+256*(12+256*13)); # 10.11.12.13 my $device_ip = 10+256*(11+256*(12+256*13)); # 10.11.12.13
#====== #======
@ -70,6 +71,7 @@ $socket->receive_message(); # SoftKeyTemplateRes
$socket->send_message(SOFT_KEY_SET_REQ_MESSAGE); $socket->send_message(SOFT_KEY_SET_REQ_MESSAGE);
$socket->receive_message(); # SoftKeySetRes $socket->receive_message(); # SoftKeySetRes
$socket->receive_message(); # SelectSoftKeys
$socket->send_message( $socket->send_message(
LINE_STAT_REQ_MESSAGE, LINE_STAT_REQ_MESSAGE,
@ -82,8 +84,68 @@ $socket->send_message(
count => 2 count => 2
); );
while(1) { for(my $i = 0; $i < 1; $i++) {
$socket->sleep(20); $socket->sleep(5);
$socket->send_message(KEEP_ALIVE_MESSAGE); $socket->send_message(KEEP_ALIVE_MESSAGE);
$socket->receive_message(); # keepaliveack $socket->receive_message(); # keepaliveack
} }
$socket->sleep(5);
#NewCall
$socket->send_message(
SOFT_KEY_EVENT_MESSAGE,
event => 2, #NewCall
line_instance => 2,
call_id => 0
);
$socket->receive_message(); # SetRinger
$socket->receive_message(); # SetSpeakerMode
$socket->receive_message(); # SetLamp
$socket->receive_message(); # SelectSoftKeys
$socket->receive_message(); # DisplayPromptStatus
$socket->receive_message(); # ActivateCallPlane
$socket->receive_message(); # StartTone
$socket->sleep(5);
#VoiceMail
$socket->send_message(
STIMULUS_MESSAGE,
instance_type => 0xf, #VoiceMail
instance => 0,
);
$socket->receive_message(); #
$socket->receive_message(); #
$socket->receive_message(); #
$socket->receive_message(); #
$socket->receive_message(); #
$socket->receive_message(); #
$socket->receive_message(); #
$socket->receive_message(); #
$socket->receive_message(); #
$socket->receive_message(); #
#
$socket->send_message(
OPEN_RECEIVE_CHANNEL_ACK_MESSAGE,
status => 1,
ip => $device_ip,
port => 12,
pass_thru_party_id => 0,
);
$socket->receive_message(); # StartMediaTransmission
$socket->sleep(20);
#EndCall
$socket->send_message(
SOFT_KEY_EVENT_MESSAGE,
event => 0x09, #NewCall
line_instance => 1,
call_id => 0
);
while(1) {
$socket->receive_message();
}

View File

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

View File

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

View File

@ -0,0 +1 @@
Makefile

View File

@ -7,8 +7,7 @@ MODPA_DIR=$(switch_srcdir)/src/mod/endpoints/mod_portaudio
mod_LTLIBRARIES = mod_portaudio_stream.la mod_LTLIBRARIES = mod_portaudio_stream.la
mod_portaudio_stream_la_SOURCES = mod_portaudio_stream.c $(MODPA_DIR)/pablio.c $(MODPA_DIR)/pa_ringbuffer.c mod_portaudio_stream_la_SOURCES = mod_portaudio_stream.c $(MODPA_DIR)/pablio.c $(MODPA_DIR)/pa_ringbuffer.c
mod_portaudio_stream_la_CFLAGS = $(AM_CFLAGS) mod_portaudio_stream_la_CFLAGS = -I. -I$(PA_DIR)/include -D__EXTENSION__=1 -I$(MODPA_DIR) $(AM_CFLAGS)
mod_portaudio_stream_la_CFLAGS += -I. -I$(PA_DIR)/include -D__EXTENSION__=1 -I$(MODPA_DIR)
mod_portaudio_stream_la_LIBADD = $(switch_builddir)/libfreeswitch.la $(PALA) mod_portaudio_stream_la_LIBADD = $(switch_builddir)/libfreeswitch.la $(PALA)
mod_portaudio_stream_la_LDFLAGS = -avoid-version -module -no-undefined -shared $(PA_LIBS) mod_portaudio_stream_la_LDFLAGS = -avoid-version -module -no-undefined -shared $(PA_LIBS)

View File

@ -21403,6 +21403,26 @@ SWIGEXPORT char * SWIGSTDCALL CSharp_switch_channel_get_variable_partner(void *
} }
SWIGEXPORT int SWIGSTDCALL CSharp_switch_channel_export_variable_var_check(void * jarg1, char * jarg2, char * jarg3, int jarg4, int jarg5) {
int jresult ;
switch_channel_t *arg1 = (switch_channel_t *) 0 ;
char *arg2 = (char *) 0 ;
char *arg3 = (char *) 0 ;
switch_bool_t arg4 ;
switch_bool_t arg5 ;
switch_status_t result;
arg1 = (switch_channel_t *)jarg1;
arg2 = (char *)jarg2;
arg3 = (char *)jarg3;
arg4 = (switch_bool_t)jarg4;
arg5 = (switch_bool_t)jarg5;
result = (switch_status_t)switch_channel_export_variable_var_check(arg1,(char const *)arg2,(char const *)arg3,arg4,arg5);
jresult = result;
return jresult;
}
SWIGEXPORT char * SWIGSTDCALL CSharp_switch_channel_get_variable_dup(void * jarg1, char * jarg2, int jarg3) { SWIGEXPORT char * SWIGSTDCALL CSharp_switch_channel_get_variable_dup(void * jarg1, char * jarg2, int jarg3) {
char * jresult ; char * jresult ;
switch_channel_t *arg1 = (switch_channel_t *) 0 ; switch_channel_t *arg1 = (switch_channel_t *) 0 ;

View File

@ -2904,6 +2904,11 @@ public class freeswitch {
return ret; return ret;
} }
public static switch_status_t switch_channel_export_variable_var_check(SWIGTYPE_p_switch_channel channel, string varname, string value, switch_bool_t var_check, switch_bool_t nolocal) {
switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_channel_export_variable_var_check(SWIGTYPE_p_switch_channel.getCPtr(channel), varname, value, (int)var_check, (int)nolocal);
return ret;
}
public static string switch_channel_get_variable_dup(SWIGTYPE_p_switch_channel channel, string varname, switch_bool_t dup) { public static string switch_channel_get_variable_dup(SWIGTYPE_p_switch_channel channel, string varname, switch_bool_t dup) {
string ret = freeswitchPINVOKE.switch_channel_get_variable_dup(SWIGTYPE_p_switch_channel.getCPtr(channel), varname, (int)dup); string ret = freeswitchPINVOKE.switch_channel_get_variable_dup(SWIGTYPE_p_switch_channel.getCPtr(channel), varname, (int)dup);
return ret; return ret;
@ -10209,6 +10214,9 @@ class freeswitchPINVOKE {
[DllImport("mod_managed", EntryPoint="CSharp_switch_channel_get_variable_partner")] [DllImport("mod_managed", EntryPoint="CSharp_switch_channel_get_variable_partner")]
public static extern string switch_channel_get_variable_partner(HandleRef jarg1, string jarg2); public static extern string switch_channel_get_variable_partner(HandleRef jarg1, string jarg2);
[DllImport("mod_managed", EntryPoint="CSharp_switch_channel_export_variable_var_check")]
public static extern int switch_channel_export_variable_var_check(HandleRef jarg1, string jarg2, string jarg3, int jarg4, int jarg5);
[DllImport("mod_managed", EntryPoint="CSharp_switch_channel_get_variable_dup")] [DllImport("mod_managed", EntryPoint="CSharp_switch_channel_get_variable_dup")]
public static extern string switch_channel_get_variable_dup(HandleRef jarg1, string jarg2, int jarg3); public static extern string switch_channel_get_variable_dup(HandleRef jarg1, string jarg2, int jarg3);

0
src/mod/timers/.empty Normal file
View File

View File

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

View File

@ -737,6 +737,37 @@ SWITCH_DECLARE(switch_status_t) switch_channel_set_profile_var(switch_channel_t
return status; return status;
} }
SWITCH_DECLARE(switch_status_t) switch_channel_export_variable_var_check(switch_channel_t *channel, const char *varname, const char *value, switch_bool_t var_check, switch_bool_t nolocal)
{
const char *exports, *exports_varname = varname;
switch_status_t status;
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 (varname && value) {
if (exports) {
switch_channel_set_variable_printf(channel, SWITCH_EXPORT_VARS_VARIABLE, "%s,%s", exports, exports_varname);
} else {
switch_channel_set_variable(channel, SWITCH_EXPORT_VARS_VARIABLE, exports_varname);
}
}
done:
if (exports_varname != varname) {
free((char*)exports_varname);
}
return status;
}
SWITCH_DECLARE(switch_status_t) switch_channel_set_variable_var_check(switch_channel_t *channel, SWITCH_DECLARE(switch_status_t) switch_channel_set_variable_var_check(switch_channel_t *channel,
const char *varname, const char *value, switch_bool_t var_check) const char *varname, const char *value, switch_bool_t var_check)
{ {

View File

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

View File

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

View File

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

0
web/etc/.empty Normal file
View File

0
web/planet/.empty Normal file
View File