Let there be PHONE CALLS!

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@16142 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
Brian West 2010-01-04 20:49:22 +00:00
parent 074afad5b5
commit 721c391a2b
23 changed files with 2503 additions and 0 deletions

40
fscomm/FSPhone.pro Normal file
View File

@ -0,0 +1,40 @@
# #####################################
# version check qt
# #####################################
contains(QT_VERSION, ^4\.[0-5]\..*) {
message("Cannot build FsGui with Qt version $$QT_VERSION.")
error("Use at least Qt 4.6.")
}
QT += xml
TARGET = fsphone
macx:TARGET = FSPhone
TEMPLATE = app
INCLUDEPATH = ../../../src/include \
../../../libs/apr/include \
../../../libs/libteletone/src
LIBS = -L../../../.libs \
-lfreeswitch \
-lm
!win32:!macx {
# This is here to comply with the default freeswitch installation
QMAKE_LFLAGS += -Wl,-rpath,/usr/local/freeswitch/lib
LIBS += -lcrypt \
-lrt
}
SOURCES += main.cpp \
mainwindow.cpp \
fshost.cpp \
call.cpp \
mod_qsettings/mod_qsettings.cpp \
prefdialog.cpp
HEADERS += mainwindow.h \
fshost.h \
call.h \
mod_qsettings/mod_qsettings.h \
prefdialog.h
FORMS += mainwindow.ui \
prefdialog.ui
RESOURCES += resources.qrc
OTHER_FILES += conf/portaudio.conf.xml \
conf/event_socket.conf.xml \
conf/freeswitch.xml

43
fscomm/call.cpp Normal file
View File

@ -0,0 +1,43 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005-2009, Anthony Minessale II <anthm@freeswitch.org>
*
* 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
* Anthony Minessale II <anthm@freeswitch.org>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Joao Mesquita <jmesquita@freeswitch.org>
*
*/
#include "call.h"
Call::Call()
{
}
Call::Call(int call_id, QString cid_name, QString cid_number, fsphone_call_direction_t direction, QString uuid) :
_call_id(call_id),
_cid_name(cid_name),
_cid_number(cid_number),
_direction(direction),
_uuid (uuid)
{
}

73
fscomm/call.h Normal file
View File

@ -0,0 +1,73 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005-2009, Anthony Minessale II <anthm@freeswitch.org>
*
* 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
* Anthony Minessale II <anthm@freeswitch.org>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Joao Mesquita <jmesquita@freeswitch.org>
*
*/
#ifndef CALL_H
#define CALL_H
#include <QtCore>
#include <QString>
#include <fshost.h>
typedef enum {
FSPHONE_CALL_STATE_RINGING = 0,
FSPHONE_CALL_STATE_TRYING = 1,
FSPHONE_CALL_STATE_ANSWERED = 2
} fsphone_call_state_t;
typedef enum {
FSPHONE_CALL_DIRECTION_INBOUND = 0,
FSPHONE_CALL_DIRECTION_OUTBOUND = 1
} fsphone_call_direction_t;
class Call
{
public:
Call(void);
Call(int call_id, QString cid_name, QString cid_number, fsphone_call_direction_t direction, QString uuid);
QString getCidName(void) { return _cid_name; }
QString getCidNumber(void) { return _cid_number; }
int getCallID(void) { return _call_id; }
QString getUUID(void) { return _uuid; }
void setbUUID(QString uuid) { _buuid = uuid; }
fsphone_call_direction_t getDirection() { return _direction; }
fsphone_call_state_t getState() { return _state; }
void setState(fsphone_call_state_t state) { _state = state; }
private:
int _call_id;
QString _cid_name;
QString _cid_number;
fsphone_call_direction_t _direction;
QString _uuid;
QString _buuid;
fsphone_call_state_t _state;
};
Q_DECLARE_METATYPE(Call)
#endif // CALL_H

View File

@ -0,0 +1,34 @@
<include>
<!--<gateway name="default">-->
<!--/// account username *required* ///-->
<!--<param name="username" value="cluecon"/>-->
<!--/// auth realm: *optional* same as gateway name, if blank ///-->
<!--<param name="realm" value="asterlink.com"/>-->
<!--/// username to use in from: *optional* same as username, if blank ///-->
<!--<param name="from-user" value="cluecon"/>-->
<!--/// domain to use in from: *optional* same as realm, if blank ///-->
<!--<param name="from-domain" value="asterlink.com"/>-->
<!--/// account password *required* ///-->
<!--<param name="password" value="cluecon"/>-->
<!--/// extension for inbound calls: *optional* same as username, if blank ///-->
<!--<param name="extension" value="cluecon"/>-->
<!--/// proxy host: *optional* same as realm, if blank ///-->
<!--<param name="proxy" value="asterlink.com"/>-->
<!--/// send register to this proxy: *optional* same as proxy, if blank ///-->
<!--<param name="register-proxy" value="mysbc.com"/>-->
<!--/// expire in seconds: *optional* 3600, if blank ///-->
<!--<param name="expire-seconds" value="60"/>-->
<!--/// do not register ///-->
<!--<param name="register" value="false"/>-->
<!-- which transport to use for register -->
<!--<param name="register-transport" value="udp"/>-->
<!--How many seconds before a retry when a failure or timeout occurs -->
<!--<param name="retry-seconds" value="30"/>-->
<!--Use the callerid of an inbound call in the from field on outbound calls via this gateway -->
<!--<param name="caller-id-in-from" value="false"/>-->
<!--extra sip params to send in the contact-->
<!--<param name="contact-params" value="tport=tcp"/>-->
<!--send an options ping every x seconds, failure will unregister and/or mark it down-->
<!--<param name="ping" value="25"/>-->
<!--</gateway>-->
</include>

View File

@ -0,0 +1,8 @@
<configuration name="event_socket.conf" description="Socket Client">
<settings>
<param name="nat-map" value="false"/>
<param name="listen-ip" value="127.0.0.1"/>
<param name="listen-port" value="8021"/>
<param name="password" value="ClueCon"/>
</settings>
</configuration>

Binary file not shown.

267
fscomm/conf/freeswitch.xml Normal file
View File

@ -0,0 +1,267 @@
<?xml version="1.0"?>
<document type="freeswitch/xml">
<X-PRE-PROCESS cmd="set" data="auto_answer=false"/>
<X-PRE-PROCESS cmd="set" data="domain=$${local_ip_v4}"/>
<X-PRE-PROCESS cmd="set" data="hold_music=local_stream://moh"/>
<X-PRE-PROCESS cmd="set" data="codec_prefs=CELT@48000h,G7221@32000h,G7221@16000h,G722,PCMU,PCMA,GSM"/>
<X-PRE-PROCESS cmd="set" data="external_rtp_ip=stun:stun.freeswitch.org"/>
<X-PRE-PROCESS cmd="set" data="external_sip_ip=stun:stun.freeswitch.org"/>
<X-PRE-PROCESS cmd="set" data="outbound_caller_name=FreeSWITCH"/>
<X-PRE-PROCESS cmd="set" data="outbound_caller_id=0000000000"/>
<X-PRE-PROCESS cmd="set" data="console_loglevel=info"/>
<X-PRE-PROCESS cmd="set" data="default_gateway=default"/>
<X-PRE-PROCESS cmd="set" data="us-ring=%(2000, 4000, 440.0, 480.0)"/>
<X-PRE-PROCESS cmd="set" data="bong-ring=v=-7;%(100,0,941.0,1477.0);v=-7;>=2;+=.1;%(1400,0,350,440)"/>
<X-PRE-PROCESS cmd="set" data="sit=%(274,0,913.8);%(274,0,1370.6);%(380,0,1776.7)"/>
<section name="configuration" description="Various Configuration">
<configuration name="cdr_csv.conf" description="CDR CSV Format">
<settings>
<param name="default-template" value="example"/>
<param name="rotate-on-hup" value="true"/>
<param name="legs" value="a"/>
</settings>
<templates>
<template name="example">"${caller_id_name}","${caller_id_number}","${destination_number}","${context}","${start_stamp}","${answer_stamp}","${end_stamp}","${duration}","${billsec}","${hangup_cause}","${uuid}","${bleg_uuid}","${accountcode}","${read_codec}","${write_codec}"</template>
</templates>
</configuration>
<configuration name="console.conf" description="Console Logger">
<mappings>
<map name="all" value="console,debug,info,notice,warning,err,crit,alert"/>
</mappings>
<settings>
<param name="colorize" value="true"/>
<param name="loglevel" value="$${console_loglevel}"/>
</settings>
</configuration>
<configuration name="enum.conf" description="ENUM Module">
<settings>
<param name="default-root" value="e164.org"/>
<param name="default-isn-root" value="freenum.org"/>
<param name="query-timeout" value="10"/>
<param name="auto-reload" value="true"/>
</settings>
<routes>
<route service="E2U+SIP" regex="sip:(.*)" replace="sofia/softphone/$1"/>
</routes>
</configuration>
<configuration name="qsettings.conf" description="configures our mod_qsettings">
<bindings value="dialplan" />
</configuration>
<configuration name="local_stream.conf" description="stream files from local dir">
<directory name="moh/48000" path="$${base_dir}/sounds/music/48000">
<param name="rate" value="48000"/>
<param name="shuffle" value="true"/>
<param name="channels" value="1"/>
<param name="interval" value="10"/>
<param name="timer-name" value="soft"/>
</directory>
</configuration>
<configuration name="logfile.conf" description="File Logging">
<settings>
<param name="rotate-on-hup" value="true"/>
</settings>
<profiles>
<profile name="default">
<settings>
</settings>
<mappings>
<map name="all" value="debug,info,notice,warning,err,crit,alert"/>
</mappings>
</profile>
</profiles>
</configuration>
<configuration name="modules.conf" description="Modules">
<modules>
<load module="mod_console"/>
<load module="mod_logfile"/>
<load module="mod_enum"/>
<load module="mod_cdr_csv"/>
<load module="mod_portaudio"/>
<load module="mod_sofia"/>
<load module="mod_loopback"/>
<load module="mod_commands"/>
<load module="mod_dptools"/>
<load module="mod_dialplan_xml"/>
<load module="mod_voipcodecs"/>
<load module="mod_ilbc"/>
<load module="mod_speex"/>
<load module="mod_celt"/>
<load module="mod_siren"/>
<load module="mod_sndfile"/>
<load module="mod_tone_stream"/>
<load module="mod_local_stream"/>
</modules>
</configuration>
<configuration name="post_load_modules.conf" description="Modules">
<modules>
</modules>
</configuration>
<configuration name="sofia.conf" description="sofia Endpoint">
<global_settings>
<param name="log-level" value="0"/>
<param name="auto-restart" value="true"/>
<param name="debug-presence" value="0"/>
</global_settings>
<profiles>
<profile name="softphone">
<gateways>
<X-PRE-PROCESS cmd="include" data="accounts/*.xml"/>
</gateways>
<settings>
<!--<param name="media-option" value="bypass-media-after-att-xfer"/>-->
<param name="user-agent-string" value="FreeSWITCH/FSPhone"/>
<!-- <param name="user-agent-string" value="FreeSWITCH Rocks!"/> -->
<param name="debug" value="0"/>
<param name="sip-trace" value="no"/>
<param name="context" value="public"/>
<param name="rfc2833-pt" value="101"/>
<!-- port to bind to for sip traffic -->
<param name="sip-port" value="12345"/>
<param name="dialplan" value="XML"/>
<param name="dtmf-duration" value="100"/>
<param name="codec-prefs" value="$${codec_prefs}"/>
<param name="use-rtp-timer" value="true"/>
<param name="rtp-timer-name" value="soft"/>
<!-- ip address to use for rtp, DO NOT USE HOSTNAMES ONLY IP ADDRESSES -->
<param name="rtp-ip" value="$${local_ip_v4}"/>
<!-- ip address to bind to, DO NOT USE HOSTNAMES ONLY IP ADDRESSES -->
<param name="sip-ip" value="$${local_ip_v4}"/>
<param name="hold-music" value="$${hold_music}"/>
<param name="apply-nat-acl" value="rfc1918"/>
<!--<param name="enable-timer" value="false"/>-->
<!--<param name="enable-100rel" value="true"/>-->
<!--<param name="minimum-session-expires" value="120"/>-->
<!--<param name="dtmf-type" value="info"/>-->
<param name="manage-presence" value="false"/>
<!--<param name="bitpacking" value="aal2"/> -->
<param name="max-proceeding" value="3"/>
<!--<param name="session-timeout" value="120"/>-->
<!--set to 'greedy' if you want your codec list to take precedence -->
<param name="inbound-codec-negotiation" value="generous"/>
<!-- if you want to send any special bind params of your own -->
<!--<param name="bind-params" value="transport=udp"/>-->
<!--Uncomment to let calls hit the dialplan *before* you decide if the codec is ok-->
<!--<param name="inbound-late-negotiation" value="true"/>-->
<!--<param name="accept-blind-reg" value="true"/> -->
<!--<param name="accept-blind-auth" value="true"/> -->
<!--<param name="suppress-cng" value="true"/> -->
<param name="nonce-ttl" value="60"/>
<!--<param name="NDLB-broken-auth-hash" value="true"/>-->
<!--<param name="NDLB-received-in-nat-reg-contact" value="true"/>-->
<param name="auth-calls" value="false"/>
<param name="auth-all-packets" value="false"/>
<param name="ext-rtp-ip" value="$${external_rtp_ip}"/>
<param name="ext-sip-ip" value="$${external_sip_ip}"/>
<!-- rtp inactivity timeout -->
<param name="rtp-timeout-sec" value="300"/>
<param name="rtp-hold-timeout-sec" value="1800"/>
<!-- VAD choose one (out is a good choice); -->
<!-- <param name="vad" value="in"/> -->
<!-- <param name="vad" value="out"/> -->
<!-- <param name="vad" value="both"/> -->
<param name="disable-register" value="true"/>
<!--<param name="NDLB-force-rport" value="true"/>-->
<param name="challenge-realm" value="auto_from"/>
<!--<param name="disable-rtp-auto-adjust" value="true"/>-->
<!--<param name="inbound-use-callid-as-uuid" value="true"/>-->
<!--<param name="outbound-use-uuid-as-callid" value="true"/>-->
<!--<param name="auto-rtp-bugs" data="clear"/>-->
</settings>
</profile>
</profiles>
</configuration>
<configuration name="switch.conf" description="Core Configuration">
<cli-keybindings>
<key name="1" value="help"/>
<key name="2" value="status"/>
<key name="3" value="pa answer"/>
<key name="4" value="pa hangup"/>
<key name="5" value="sofia status"/>
<key name="6" value="reloadxml"/>
<key name="7" value="console loglevel 0"/>
<key name="8" value="console loglevel 7"/>
<key name="9" value="sofia status profile softphone"/>
<key name="10" value="fsctl pause"/>
<key name="11" value="fsctl resume"/>
<key name="12" value="version"/>
</cli-keybindings>
<settings>
<param name="colorize-console" value="true"/>
<param name="max-sessions" value="20"/>
<param name="sessions-per-second" value="5"/>
<param name="loglevel" value="debug"/>
<param name="crash-protection" value="false"/>
<param name="dump-cores" value="yes"/>
<param name="rtp-start-port" value="16384"/>
<param name="rtp-end-port" value="16484"/>
</settings>
</configuration>
</section>
<section name="dialplan" description="Regex/XML Dialplan">
<context name="default">
<extension name="codec_and_sip_uri">
<condition field="destination_number" expression="^sip:(.*):(.*)$">
<action application="bridge" data="{absolute_codec_string=$1}sofia/softphone/$2"/>
</condition>
</extension>
<extension name="sip_uri">
<condition field="destination_number" expression="^sip:(.*)$">
<action application="bridge" data="sofia/softphone/$1"/>
</condition>
</extension>
<extension name="codec_and_number">
<condition field="destination_number" expression="^(.*):(.*)@(.*)$">
<action application="bridge" data="{absolute_codec_string=$1}sofia/gateway/$3/$2"/>
</condition>
</extension>
<extension name="number">
<condition field="destination_number" expression="^(.*)@(.*)$">
<action application="bridge" data="sofia/gateway/$2/$1"/>
</condition>
</extension>
<extension name="number">
<condition field="destination_number" expression="^(.*)$">
<action application="bridge" data="sofia/gateway/${default_gateway}/$1"/>
</condition>
</extension>
</context>
<context name="public">
<extension name="public_extensions">
<condition field="$${auto_answer}" expression="^true$"/>
<condition field="destination_number" expression="^(.*)$">
<action application="info"/>
<action application="bridge" data="portaudio/auto_answer"/>
</condition>
</extension>
<extension name="public_extensions">
<condition field="${sip_to_params}" expression="intercom=true"/>
<condition field="${alert_info}" expression="Ring;Answer"/>
<condition field="destination_number" expression="^(.*)$">
<action application="info"/>
<action application="bridge" data="portaudio/auto_answer"/>
</condition>
</extension>
<extension name="public_extensions">
<condition field="destination_number" expression="^(.*)$">
<action application="info"/>
<action application="set" data="ringback=${us-ring}"/>
<action application="pre_answer"/>
<action application="bridge" data="portaudio"/>
</condition>
</extension>
</context>
</section>
</document>

View File

@ -0,0 +1,17 @@
<configuration name="portaudio.conf" description="Soundcard Endpoint">
<settings>
<param name="indev" value="${indev}"/>
<!-- device to use for output -->
<param name="outdev" value="${outdev}"/>
<!--<param name="ringdev" value="${ringdev}"/>-->
<param name="ring-file" value="${ring-file}"/>
<param name="ring-interval" value="${ring-interval}"/>
<param name="hold-file" value="$${hold_music}"/>
<!--<param name="timer-name" value="soft"/>-->
<param name="dialplan" value="XML"/>
<param name="cid-name" value="$${outbound_caller_name}"/>
<param name="cid-num" value="$${outbound_caller_number}"/>
<param name="sample-rate" value="48000"/>
<param name="codec-ms" value="10"/>
</settings>
</configuration>

352
fscomm/fshost.cpp Normal file
View File

@ -0,0 +1,352 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005-2009, Anthony Minessale II <anthm@freeswitch.org>
*
* 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
* Anthony Minessale II <anthm@freeswitch.org>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Joao Mesquita <jmesquita@freeswitch.org>
*
*/
#include <QtGui>
#include "fshost.h"
#include "call.h"
#include "mod_qsettings/mod_qsettings.h"
/* Declare it globally */
FSHost g_FSHost;
FSHost::FSHost(QObject *parent) :
QThread(parent)
{
/* Initialize libs & globals */
printf("Initializing globals...\n");
switch_core_setrlimits();
switch_core_set_globals();
qRegisterMetaType<Call>("Call");
}
void FSHost::run(void)
{
switch_core_flag_t flags = SCF_USE_SQL | SCF_USE_AUTO_NAT;
const char *err = NULL;
switch_bool_t console = SWITCH_FALSE;
switch_status_t destroy_status;
/* Create directory structure for softphone with default configs */
QDir conf_dir = QDir(QDir::home());
if (!conf_dir.exists(".fsphone"))
{
conf_dir.mkpath(".fsphone/conf/accounts");
conf_dir.mkpath(".fsphone/templates");
QFile rootXML(":/confs/freeswitch.xml");
QString dest = QString("%1/.fsphone/conf/freeswitch.xml").arg(conf_dir.absolutePath());
rootXML.copy(dest);
QFile defaultAccount(":/confs/example.xml");
dest = QString("%1/.fsphone/conf/accounts/example.xml").arg(conf_dir.absolutePath());
defaultAccount.copy(dest);
}
/* Set all directories to the home user directory */
if (conf_dir.cd(".fsphone"))
{
SWITCH_GLOBAL_dirs.conf_dir = (char *) malloc(strlen(QString("%1/conf").arg(conf_dir.absolutePath()).toAscii().constData()) + 1);
if (!SWITCH_GLOBAL_dirs.conf_dir) {
emit coreLoadingError("Cannot allocate memory for conf_dir.");
}
strcpy(SWITCH_GLOBAL_dirs.conf_dir, QString("%1/conf").arg(conf_dir.absolutePath()).toAscii().constData());
SWITCH_GLOBAL_dirs.log_dir = (char *) malloc(strlen(QString("%1/log").arg(conf_dir.absolutePath()).toAscii().constData()) + 1);
if (!SWITCH_GLOBAL_dirs.log_dir) {
emit coreLoadingError("Cannot allocate memory for log_dir.");
}
strcpy(SWITCH_GLOBAL_dirs.log_dir, QString("%1/log").arg(conf_dir.absolutePath()).toAscii().constData());
SWITCH_GLOBAL_dirs.run_dir = (char *) malloc(strlen(QString("%1/run").arg(conf_dir.absolutePath()).toAscii().constData()) + 1);
if (!SWITCH_GLOBAL_dirs.run_dir) {
emit coreLoadingError("Cannot allocate memory for run_dir.");
}
strcpy(SWITCH_GLOBAL_dirs.run_dir, QString("%1/run").arg(conf_dir.absolutePath()).toAscii().constData());
SWITCH_GLOBAL_dirs.db_dir = (char *) malloc(strlen(QString("%1/db").arg(conf_dir.absolutePath()).toAscii().constData()) + 1);
if (!SWITCH_GLOBAL_dirs.db_dir) {
emit coreLoadingError("Cannot allocate memory for db_dir.");
}
strcpy(SWITCH_GLOBAL_dirs.db_dir, QString("%1/db").arg(conf_dir.absolutePath()).toAscii().constData());
SWITCH_GLOBAL_dirs.script_dir = (char *) malloc(strlen(QString("%1/script").arg(conf_dir.absolutePath()).toAscii().constData()) + 1);
if (!SWITCH_GLOBAL_dirs.script_dir) {
emit coreLoadingError("Cannot allocate memory for script_dir.");
}
strcpy(SWITCH_GLOBAL_dirs.script_dir, QString("%1/script").arg(conf_dir.absolutePath()).toAscii().constData());
SWITCH_GLOBAL_dirs.htdocs_dir = (char *) malloc(strlen(QString("%1/htdocs").arg(conf_dir.absolutePath()).toAscii().constData()) + 1);
if (!SWITCH_GLOBAL_dirs.htdocs_dir) {
emit coreLoadingError("Cannot allocate memory for htdocs_dir.");
}
strcpy(SWITCH_GLOBAL_dirs.htdocs_dir, QString("%1/htdocs").arg(conf_dir.absolutePath()).toAscii().constData());
}
/* If you need to override configuration directories, you need to change them in the SWITCH_GLOBAL_dirs global structure */
printf("Initializing core...\n");
/* Initialize the core and load modules, that will startup FS completely */
if (switch_core_init_and_modload(flags, console, &err) != SWITCH_STATUS_SUCCESS) {
fprintf(stderr, "Failed to initialize FreeSWITCH's core: %s\n", err);
emit coreLoadingError(err);
}
printf("Everything OK, Entering runtime loop.\n");
if (switch_event_bind("FSHost", SWITCH_EVENT_ALL, SWITCH_EVENT_SUBCLASS_ANY, eventHandlerCallback, NULL) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
}
/* Load our QSettings module */
if (switch_loadable_module_build_dynamic("mod_qsettings",mod_qsettings_load,NULL,mod_qsettings_shutdown,SWITCH_FALSE) != SWITCH_STATUS_SUCCESS)
{
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't load mod_qsettings\n");
}
QString res;
sendCmd("load", "mod_event_socket", &res);
emit ready();
/* Go into the runtime loop. If the argument is true, this basically sets runtime.running = 1 and loops while that is set
* If its false, it initializes the libedit for the console, then does the same thing
*/
switch_core_runtime_loop(!console);
fflush(stdout);
switch_event_unbind_callback(eventHandlerCallback);
/* When the runtime loop exits, its time to shutdown */
destroy_status = switch_core_destroy();
if (destroy_status == SWITCH_STATUS_SUCCESS)
{
printf("We have properly shutdown the core.\n");
}
}
switch_status_t FSHost::processAlegEvent(switch_event_t * event, QString uuid)
{
switch_status_t status = SWITCH_STATUS_SUCCESS;
Call * call = _active_calls.value(uuid);
/* Inbound call */
if (call->getDirection() == FSPHONE_CALL_DIRECTION_INBOUND)
{
switch(event->event_id) {
case SWITCH_EVENT_CHANNEL_ANSWER:
{
call->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->setState(FSPHONE_CALL_STATE_ANSWERED);
emit answered(uuid);
break;
}
case SWITCH_EVENT_CHANNEL_HANGUP_COMPLETE:
{
emit hungup(_active_calls.take(uuid));
break;
}
case SWITCH_EVENT_CHANNEL_STATE:
{
printf("CHANNEL_STATE Answer-State: %s | Channel-State: %s | %s | %s\n", 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:
{
_active_calls.value(uuid)->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->getState() == FSPHONE_CALL_STATE_TRYING)
{
emit callFailed(uuid);
_active_calls.take(uuid);
}
break;
}
default:
printf("A leg: %s(%s)\n",switch_event_name(event->event_id), switch_event_get_header_nil(event, "Event-Subclass"));
break;
}
}
return status;
}
switch_status_t FSHost::processBlegEvent(switch_event_t * event, QString buuid)
{
QString uuid = _bleg_uuids.value(buuid);
switch_status_t status = SWITCH_STATUS_SUCCESS;
Call * call = _active_calls.value(uuid);
/* Inbound call */
if (call->getDirection() == FSPHONE_CALL_DIRECTION_INBOUND)
{
qDebug() << " Inbound call";
}
/* Outbound call */
else
{
switch(event->event_id)
{
case SWITCH_EVENT_CHANNEL_ANSWER:
{
emit answered(uuid);
break;
}
case SWITCH_EVENT_CHANNEL_HANGUP_COMPLETE:
{
emit hungup(_active_calls.take(uuid));
_bleg_uuids.take(buuid);
break;
}
case SWITCH_EVENT_CHANNEL_STATE:
{
if (QString(switch_event_get_header_nil(event, "Answer-State")) == "early")
{
call->setState(FSPHONE_CALL_STATE_RINGING);
emit ringing(uuid);
}
//printEventHeaders(event);
break;
}
default:
printf("B leg: %s(%s)\n",switch_event_name(event->event_id), switch_event_get_header_nil(event, "Event-Subclass"));
break;
}
}
return status;
}
void FSHost::generalEventHandler(switch_event_t *event)
{
QString uuid = switch_event_get_header_nil(event, "Unique-ID");
if (_bleg_uuids.contains(uuid))
{
if (processBlegEvent(event, uuid) == SWITCH_STATUS_SUCCESS)
{
return;
}
}
if (_active_calls.contains(uuid))
{
if (processAlegEvent(event, uuid) == SWITCH_STATUS_SUCCESS)
{
return;
}
}
/* 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))
{
Call *call = new Call(atoi(switch_event_get_header_nil(event, "call_id")),
switch_event_get_header_nil(event, "Caller-Caller-ID-Name"),
switch_event_get_header_nil(event, "Caller-Caller-ID-Number"),
FSPHONE_CALL_DIRECTION_INBOUND,
uuid);
_active_calls.insert(uuid, call);
call->setState(FSPHONE_CALL_STATE_RINGING);
emit ringing(uuid);
}
else if (strcmp(event->subclass_name, "portaudio::makecall") == 0)
{
Call *call = new Call(atoi(switch_event_get_header_nil(event, "call_id")),NULL,
switch_event_get_header_nil(event, "Caller-Destination-Number"),
FSPHONE_CALL_DIRECTION_OUTBOUND,
uuid);
_active_calls.insert(uuid, call);
call->setState(FSPHONE_CALL_STATE_TRYING);
emit newOutgoingCall(uuid);
}
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");
if (state == "TRYING")
emit gwStateChange(gw, FSPHONE_GW_STATE_TRYING);
else if (state == "REGISTER")
emit gwStateChange(gw, FSPHONE_GW_STATE_REGISTER);
else if (state == "REGED")
emit gwStateChange(gw, FSPHONE_GW_STATE_REGED);
else if (state == "UNREGED")
emit gwStateChange(gw, FSPHONE_GW_STATE_UNREGED);
else if (state == "UNREGISTER")
emit gwStateChange(gw, FSPHONE_GW_STATE_UNREGISTER);
else if (state =="FAILED")
emit gwStateChange(gw, FSPHONE_GW_STATE_FAILED);
else if (state == "FAIL_WAIT")
emit gwStateChange(gw, FSPHONE_GW_STATE_FAIL_WAIT);
else if (state == "EXPIRED")
emit gwStateChange(gw, FSPHONE_GW_STATE_EXPIRED);
else if (state == "NOREG")
emit gwStateChange(gw, FSPHONE_GW_STATE_NOREG);
}
else
{
//printf("We got a not treated custom event: %s\n", (!zstr(event->subclass_name) ? event->subclass_name : "NULL"));
}
break;
}
default:
break;
}
}
switch_status_t FSHost::sendCmd(const char *cmd, const char *args, QString *res)
{
switch_status_t status = SWITCH_STATUS_FALSE;
switch_stream_handle_t stream = { 0 };
SWITCH_STANDARD_STREAM(stream);
status = switch_api_execute(cmd, args, NULL, &stream);
*res = switch_str_nil((char *) stream.data);
return status;
}
void FSHost::printEventHeaders(switch_event_t *event)
{
switch_event_header_t *hp;
printf("Received event: %s(%s)\n", switch_event_name(event->event_id), switch_event_get_header_nil(event, "Event-Subclass"));
for (hp = event->headers; hp; hp = hp->next) {
printf("%s=%s\n", hp->name, hp->value);
}
printf("\n\n");
}

106
fscomm/fshost.h Normal file
View File

@ -0,0 +1,106 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005-2009, Anthony Minessale II <anthm@freeswitch.org>
*
* 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
* Anthony Minessale II <anthm@freeswitch.org>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Joao Mesquita <jmesquita@freeswitch.org>
*
*/
#ifndef FSHOST_H
#define FSHOST_H
#include <QThread>
#include <QHash>
#include <switch.h>
class Call;
#define FSPHONE_GW_STATE_TRYING 0
#define FSPHONE_GW_STATE_REGISTER 1
#define FSPHONE_GW_STATE_REGED 2
#define FSPHONE_GW_STATE_UNREGED 3
#define FSPHONE_GW_STATE_UNREGISTER 4
#define FSPHONE_GW_STATE_FAILED 5
#define FSPHONE_GW_STATE_FAIL_WAIT 6
#define FSPHONE_GW_STATE_EXPIRED 7
#define FSPHONE_GW_STATE_NOREG 8
static const char *fsphone_gw_state_names[] = {
"TRYING",
"REGISTER",
"REGED",
"UNREGED",
"UNREGISTER",
"FAILED",
"FAIL_WAIT",
"EXPIRED",
"NOREG"
};
class FSHost : public QThread
{
Q_OBJECT
public:
explicit FSHost(QObject *parent = 0);
switch_status_t sendCmd(const char *cmd, const char *args, QString *res);
void generalEventHandler(switch_event_t *event);
Call * getCallByUUID(QString uuid) { return _active_calls.value(uuid, NULL); }
QString getGwStateName(int id) { return fsphone_gw_state_names[id]; }
protected:
void run(void);
signals:
void coreLoadingError(QString);
void ready(void);
void ringing(QString);
void answered(QString);
void newOutgoingCall(QString);
void callFailed(QString);
void hungup(Call*);
void gwStateChange(QString, int);
private:
switch_status_t processBlegEvent(switch_event_t *, QString);
switch_status_t processAlegEvent(switch_event_t *, QString);
void printEventHeaders(switch_event_t *event);
QHash<QString, Call*> _active_calls;
QHash<QString, QString> _bleg_uuids;
};
extern FSHost g_FSHost;
/*
Used to match callback from fs core. We dup the event and call the class
method callback to make use of the signal/slot infrastructure.
*/
static void eventHandlerCallback(switch_event_t *event)
{
switch_event_t *clone = NULL;
if (switch_event_dup(&clone, event) == SWITCH_STATUS_SUCCESS) {
g_FSHost.generalEventHandler(clone);
}
switch_safe_free(clone);
}
#endif // FSHOST_H

51
fscomm/main.cpp Normal file
View File

@ -0,0 +1,51 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005-2009, Anthony Minessale II <anthm@freeswitch.org>
*
* 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
* Anthony Minessale II <anthm@freeswitch.org>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Joao Mesquita <jmesquita@freeswitch.org>
*
*/
#include <QtGui/QApplication>
#include <QSplashScreen>
#include "mainwindow.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QCoreApplication::setOrganizationName("FreeSWITCH");
QCoreApplication::setOrganizationDomain("freeswitch.org");
QCoreApplication::setApplicationName("FSPhone");
QPixmap image(":/images/splash.png");
QSplashScreen *splash = new QSplashScreen(image);
splash->show();
splash->showMessage("Loading, please wait...", Qt::AlignRight|Qt::AlignBottom, Qt::blue);
QObject::connect(&g_FSHost, SIGNAL(ready()), splash, SLOT(close()));
MainWindow w;
QObject::connect(&g_FSHost, SIGNAL(ready()), &w, SLOT(show()));
g_FSHost.start();
return a.exec();
}

334
fscomm/mainwindow.cpp Normal file
View File

@ -0,0 +1,334 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005-2009, Anthony Minessale II <anthm@freeswitch.org>
*
* 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
* Anthony Minessale II <anthm@freeswitch.org>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Joao Mesquita <jmesquita@freeswitch.org>
*
*/
#include <QInputDialog>
#include <QMessageBox>
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow),
preferences(NULL)
{
ui->setupUi(this);
dialpadMapper = new QSignalMapper(this);
connect(ui->dtmf0Btn, SIGNAL(clicked()), dialpadMapper, SLOT(map()));
connect(ui->dtmf1Btn, SIGNAL(clicked()), dialpadMapper, SLOT(map()));
connect(ui->dtmf2Btn, SIGNAL(clicked()), dialpadMapper, SLOT(map()));
connect(ui->dtmf3Btn, SIGNAL(clicked()), dialpadMapper, SLOT(map()));
connect(ui->dtmf4Btn, SIGNAL(clicked()), dialpadMapper, SLOT(map()));
connect(ui->dtmf5Btn, SIGNAL(clicked()), dialpadMapper, SLOT(map()));
connect(ui->dtmf6Btn, SIGNAL(clicked()), dialpadMapper, SLOT(map()));
connect(ui->dtmf7Btn, SIGNAL(clicked()), dialpadMapper, SLOT(map()));
connect(ui->dtmf8Btn, SIGNAL(clicked()), dialpadMapper, SLOT(map()));
connect(ui->dtmf9Btn, SIGNAL(clicked()), dialpadMapper, SLOT(map()));
connect(ui->dtmfABtn, SIGNAL(clicked()), dialpadMapper, SLOT(map()));
connect(ui->dtmfBBtn, SIGNAL(clicked()), dialpadMapper, SLOT(map()));
connect(ui->dtmfCBtn, SIGNAL(clicked()), dialpadMapper, SLOT(map()));
connect(ui->dtmfDBtn, SIGNAL(clicked()), dialpadMapper, SLOT(map()));
connect(ui->dtmfAstBtn, SIGNAL(clicked()), dialpadMapper, SLOT(map()));
connect(ui->dtmfPoundBtn, SIGNAL(clicked()), dialpadMapper, SLOT(map()));
dialpadMapper->setMapping(ui->dtmf0Btn, QString("0"));
dialpadMapper->setMapping(ui->dtmf1Btn, QString("1"));
dialpadMapper->setMapping(ui->dtmf2Btn, QString("2"));
dialpadMapper->setMapping(ui->dtmf3Btn, QString("3"));
dialpadMapper->setMapping(ui->dtmf4Btn, QString("4"));
dialpadMapper->setMapping(ui->dtmf5Btn, QString("5"));
dialpadMapper->setMapping(ui->dtmf6Btn, QString("6"));
dialpadMapper->setMapping(ui->dtmf7Btn, QString("7"));
dialpadMapper->setMapping(ui->dtmf8Btn, QString("8"));
dialpadMapper->setMapping(ui->dtmf9Btn, QString("9"));
dialpadMapper->setMapping(ui->dtmfABtn, QString("A"));
dialpadMapper->setMapping(ui->dtmfBBtn, QString("B"));
dialpadMapper->setMapping(ui->dtmfCBtn, QString("C"));
dialpadMapper->setMapping(ui->dtmfDBtn, QString("D"));
dialpadMapper->setMapping(ui->dtmfAstBtn, QString("*"));
dialpadMapper->setMapping(ui->dtmfPoundBtn, QString("#"));
connect(dialpadMapper, SIGNAL(mapped(QString)), this, SLOT(dialDTMF(QString)));
connect(&g_FSHost, SIGNAL(ready()),this, SLOT(fshostReady()));
connect(&g_FSHost, SIGNAL(ringing(QString)), this, SLOT(ringing(QString)));
connect(&g_FSHost, SIGNAL(answered(QString)), this, SLOT(answered(QString)));
connect(&g_FSHost, SIGNAL(hungup(Call*)), this, SLOT(hungup(Call*)));
connect(&g_FSHost, SIGNAL(newOutgoingCall(QString)), this, SLOT(newOutgoingCall(QString)));
connect(&g_FSHost, SIGNAL(gwStateChange(QString,int)), this, SLOT(gwStateChanged(QString,int)));
/*connect(&g_FSHost, SIGNAL(coreLoadingError(QString)), this, SLOT(coreLoadingError(QString)));*/
connect(ui->newCallBtn, SIGNAL(clicked()), this, SLOT(makeCall()));
connect(ui->answerBtn, SIGNAL(clicked()), this, SLOT(paAnswer()));
connect(ui->hangupBtn, SIGNAL(clicked()), this, SLOT(paHangup()));
connect(ui->listCalls, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(callListDoubleClick(QListWidgetItem*)));
connect(ui->action_Preferences, SIGNAL(triggered()), this, SLOT(prefTriggered()));
connect(ui->action_Exit, SIGNAL(triggered()), this, SLOT(close()));
}
MainWindow::~MainWindow()
{
delete ui;
QString res;
g_FSHost.sendCmd("fsctl", "shutdown", &res);
g_FSHost.wait();
}
void MainWindow::prefTriggered()
{
if (!preferences)
preferences = new PrefDialog();
preferences->raise();
preferences->show();
preferences->activateWindow();
}
void MainWindow::coreLoadingError(QString err)
{
QMessageBox::warning(this, "Error Loading Core...", err, QMessageBox::Ok);
QApplication::exit(255);
}
void MainWindow::gwStateChanged(QString gw, int state)
{
ui->statusBar->showMessage(tr("Account %1 is %2").arg(gw, g_FSHost.getGwStateName(state)));
/* TODO: This should be placed somewhere else when the config handler is here... */
QList<QTableWidgetItem *> match = ui->tableAccounts->findItems(gw, Qt::MatchExactly);
if (match.isEmpty())
{
/* Create the damn thing */
ui->tableAccounts->setRowCount(ui->tableAccounts->rowCount()+1);
QTableWidgetItem *gwField = new QTableWidgetItem(gw);
QTableWidgetItem *stField = new QTableWidgetItem(g_FSHost.getGwStateName(state));
ui->tableAccounts->setItem(0,0,gwField);
ui->tableAccounts->setItem(0,1,stField);
ui->tableAccounts->resizeColumnsToContents();
return;
}
QTableWidgetItem *gwField = match.at(0);
QTableWidgetItem *stField = ui->tableAccounts->item(gwField->row(),1);
stField->setText(g_FSHost.getGwStateName(state));
ui->tableAccounts->resizeColumnsToContents();
}
void MainWindow::dialDTMF(QString dtmf)
{
QString result;
QString dtmf_string = QString("dtmf %1").arg(dtmf);
if (g_FSHost.sendCmd("pa", dtmf_string.toAscii(), &result) == SWITCH_STATUS_FALSE) {
ui->textEdit->setText("Error sending that command");
}
}
void MainWindow::callListDoubleClick(QListWidgetItem *item)
{
Call *call = g_FSHost.getCallByUUID(item->data(Qt::UserRole).toString());
QString switch_str = QString("switch %1").arg(call->getCallID());
QString result;
if (g_FSHost.sendCmd("pa", switch_str.toAscii(), &result) == SWITCH_STATUS_FALSE) {
ui->textEdit->setText(QString("Error switching to call %1").arg(call->getCallID()));
return;
}
ui->hangupBtn->setEnabled(true);
}
void MainWindow::makeCall()
{
bool ok;
QString dialstring = QInputDialog::getText(this, tr("Make new call"),
tr("Number to dial:"), QLineEdit::Normal, NULL,&ok);
if (ok && !dialstring.isEmpty())
{
paCall(dialstring);
}
}
void MainWindow::fshostReady()
{
ui->statusBar->showMessage("Ready");
ui->newCallBtn->setEnabled(true);
ui->textEdit->setEnabled(true);
ui->textEdit->setText("Ready to dial and receive calls!");
}
void MainWindow::paAnswer()
{
QString result;
if (g_FSHost.sendCmd("pa", "answer", &result) == SWITCH_STATUS_FALSE) {
ui->textEdit->setText("Error sending that command");
}
ui->textEdit->setText("Talking...");
ui->hangupBtn->setEnabled(true);
ui->answerBtn->setEnabled(false);
}
void MainWindow::paCall(QString dialstring)
{
QString result;
QString callstring = QString("call %1").arg(dialstring);
if (g_FSHost.sendCmd("pa", callstring.toAscii(), &result) == SWITCH_STATUS_FALSE) {
ui->textEdit->setText("Error sending that command");
}
ui->hangupBtn->setEnabled(true);
}
void MainWindow::paHangup()
{
QString result;
if (g_FSHost.sendCmd("pa", "hangup", &result) == SWITCH_STATUS_FALSE) {
ui->textEdit->setText("Error sending that command");
}
ui->textEdit->setText("Click to dial number...");
ui->statusBar->showMessage("Call hungup");
ui->hangupBtn->setEnabled(false);
}
void MainWindow::newOutgoingCall(QString uuid)
{
Call *call = g_FSHost.getCallByUUID(uuid);
ui->textEdit->setText(QString("Calling %1 (%2)").arg(call->getCidName(), call->getCidNumber()));
QListWidgetItem *item = new QListWidgetItem(tr("%1 (%2) - Calling").arg(call->getCidName(), call->getCidNumber()));
item->setData(Qt::UserRole, uuid);
ui->listCalls->addItem(item);
ui->hangupBtn->setEnabled(true);
}
void MainWindow::ringing(QString uuid)
{
Call *call = g_FSHost.getCallByUUID(uuid);
for (int i=0; i<ui->listCalls->count(); i++)
{
QListWidgetItem *item = ui->listCalls->item(i);
if (item->data(Qt::UserRole).toString() == uuid)
{
item->setText(tr("%1 - Ringing").arg(call->getCidNumber()));
ui->textEdit->setText(QString("Call from %1 (%2)").arg(call->getCidName(), call->getCidNumber()));
return;
}
}
ui->textEdit->setText(QString("Call from %1 (%2)").arg(call->getCidName(), call->getCidNumber()));
QListWidgetItem *item = new QListWidgetItem(tr("%1 (%2) - Ringing").arg(call->getCidName(), call->getCidNumber()));
item->setData(Qt::UserRole, uuid);
ui->listCalls->addItem(item);
ui->answerBtn->setEnabled(true);
}
void MainWindow::answered(QString uuid)
{
Call *call = g_FSHost.getCallByUUID(uuid);
for (int i=0; i<ui->listCalls->count(); i++)
{
QListWidgetItem *item = ui->listCalls->item(i);
if (item->data(Qt::UserRole).toString() == uuid)
{
if (call->getDirection() == FSPHONE_CALL_DIRECTION_INBOUND)
{
item->setText(tr("%1 (%2) - Active").arg(call->getCidName(), call->getCidNumber()));
break;
}
else
{
item->setText(tr("%1 - Active").arg(call->getCidNumber()));
break;
}
}
}
ui->dtmf0Btn->setEnabled(true);
ui->dtmf1Btn->setEnabled(true);
ui->dtmf2Btn->setEnabled(true);
ui->dtmf3Btn->setEnabled(true);
ui->dtmf4Btn->setEnabled(true);
ui->dtmf5Btn->setEnabled(true);
ui->dtmf6Btn->setEnabled(true);
ui->dtmf7Btn->setEnabled(true);
ui->dtmf8Btn->setEnabled(true);
ui->dtmf9Btn->setEnabled(true);
ui->dtmfABtn->setEnabled(true);
ui->dtmfBBtn->setEnabled(true);
ui->dtmfCBtn->setEnabled(true);
ui->dtmfDBtn->setEnabled(true);
ui->dtmfAstBtn->setEnabled(true);
ui->dtmfPoundBtn->setEnabled(true);
}
void MainWindow::hungup(Call* call)
{
for (int i=0; i<ui->listCalls->count(); i++)
{
QListWidgetItem *item = ui->listCalls->item(i);
if (item->data(Qt::UserRole).toString() == call->getUUID())
{
delete ui->listCalls->takeItem(i);
break;
}
}
ui->textEdit->setText(tr("Call with %1 (%2) hungup.").arg(call->getCidName(), call->getCidNumber()));
/* TODO: Will cause problems if 2 calls are received at the same time */
ui->answerBtn->setEnabled(false);
ui->hangupBtn->setEnabled(false);
ui->dtmf0Btn->setEnabled(false);
ui->dtmf1Btn->setEnabled(false);
ui->dtmf2Btn->setEnabled(false);
ui->dtmf3Btn->setEnabled(false);
ui->dtmf4Btn->setEnabled(false);
ui->dtmf5Btn->setEnabled(false);
ui->dtmf6Btn->setEnabled(false);
ui->dtmf7Btn->setEnabled(false);
ui->dtmf8Btn->setEnabled(false);
ui->dtmf9Btn->setEnabled(false);
ui->dtmfABtn->setEnabled(false);
ui->dtmfBBtn->setEnabled(false);
ui->dtmfCBtn->setEnabled(false);
ui->dtmfDBtn->setEnabled(false);
ui->dtmfAstBtn->setEnabled(false);
ui->dtmfPoundBtn->setEnabled(false);
delete call;
}
void MainWindow::changeEvent(QEvent *e)
{
QMainWindow::changeEvent(e);
switch (e->type()) {
case QEvent::LanguageChange:
ui->retranslateUi(this);
break;
default:
break;
}
}

80
fscomm/mainwindow.h Normal file
View File

@ -0,0 +1,80 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005-2009, Anthony Minessale II <anthm@freeswitch.org>
*
* 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
* Anthony Minessale II <anthm@freeswitch.org>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Joao Mesquita <jmesquita@freeswitch.org>
*
*/
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QListWidgetItem>
#include <QSignalMapper>
#include <switch.h>
#include <fshost.h>
#include <call.h>
#include <prefdialog.h>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow {
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
protected:
void changeEvent(QEvent *e);
signals:
void dtmfDialed(QString);
private slots:
void prefTriggered();
void coreLoadingError(QString);
void gwStateChanged(QString, int);
void dialDTMF(QString);
void callListDoubleClick(QListWidgetItem *);
void makeCall();
void fshostReady();
void paAnswer();
void paCall(QString);
void paHangup();
void newOutgoingCall(QString);
void ringing(QString);
void answered(QString);
void hungup(Call*);
private:
Ui::MainWindow *ui;
QSignalMapper *dialpadMapper;
PrefDialog *preferences;
};
#endif // MAINWINDOW_H

350
fscomm/mainwindow.ui Normal file
View File

@ -0,0 +1,350 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>580</width>
<height>563</height>
</rect>
</property>
<property name="windowTitle">
<string>FSPhone - A FreeSWITCH softphone</string>
</property>
<widget class="QWidget" name="centralWidget">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QTextEdit" name="textEdit">
<property name="enabled">
<bool>false</bool>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="newCallBtn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>New Call</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QPushButton" name="answerBtn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Answer</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="hangupBtn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Hangup</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QPushButton" name="dtmf1Btn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>1</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="dtmf2Btn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>2</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="dtmf3Btn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>3</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="dtmf4Btn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>4</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="dtmf5Btn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>5</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="dtmf6Btn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>6</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QPushButton" name="dtmf7Btn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>7</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="dtmf8Btn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>8</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QPushButton" name="dtmf9Btn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>9</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QPushButton" name="dtmfAstBtn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>*</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QPushButton" name="dtmf0Btn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QPushButton" name="dtmfPoundBtn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>#</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QPushButton" name="dtmfABtn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>A</string>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QPushButton" name="dtmfBBtn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>B</string>
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QPushButton" name="dtmfDBtn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>D</string>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QPushButton" name="dtmfCBtn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>C</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Active Calls</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QListWidget" name="listCalls"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Active Accounts</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QTableWidget" name="tableAccounts">
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="alternatingRowColors">
<bool>false</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="showGrid">
<bool>false</bool>
</property>
<property name="cornerButtonEnabled">
<bool>true</bool>
</property>
<property name="rowCount">
<number>0</number>
</property>
<attribute name="horizontalHeaderVisible">
<bool>true</bool>
</attribute>
<attribute name="horizontalHeaderCascadingSectionResizes">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderHighlightSections">
<bool>false</bool>
</attribute>
<column>
<property name="text">
<string>Account</string>
</property>
</column>
<column>
<property name="text">
<string>Status</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>580</width>
<height>22</height>
</rect>
</property>
<widget class="QMenu" name="menu_File">
<property name="title">
<string>&amp;File</string>
</property>
<addaction name="action_Preferences"/>
<addaction name="separator"/>
<addaction name="action_Exit"/>
</widget>
<addaction name="menu_File"/>
</widget>
<widget class="QToolBar" name="mainToolBar">
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
</widget>
<widget class="QStatusBar" name="statusBar"/>
<action name="action_Preferences">
<property name="text">
<string>&amp;Preferences</string>
</property>
</action>
<action name="action_Exit">
<property name="text">
<string>&amp;Exit</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,149 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005-2009, Anthony Minessale II <anthm@freeswitch.org>
*
* 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
* Anthony Minessale II <anthm@freeswitch.org>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Joao Mesquita <jmesquita@freeswitch.org>
*
*
* Description:
* Module to load configurations from Qt preference system QSettings
*
*/
#include <QString>
#include <QtGui>
#include <QDir>
#include "mod_qsettings/mod_qsettings.h"
static struct {
switch_memory_pool_t* pool;
} globals;
switch_xml_t XMLBinding::getConfigXML(QString tmpl)
{
switch_event_t *e;
switch_event_create_plain(&e, SWITCH_EVENT_REQUEST_PARAMS);
switch_assert(e);
QFile tmplFile(QString("%1/templates/%2.xml").arg(QApplication::applicationDirPath(),tmpl));
if (!tmplFile.exists()) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,
"Template %s.xml, doesn't exist on directory, falling back to embedded template.\n",
tmpl.toAscii().constData());
tmplFile.setFileName(QString(":/confs/%1.xml").arg(tmpl));
return NULL;
}
if (tmplFile.open(QIODevice::ReadOnly | QIODevice::Text))
{
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Template %s could not be read.!\n", tmpl.toAscii().constData());
return NULL;
}
/* Open template file and expand all strings based on QSettings */
QString tmplContents(tmplFile.readAll());
tmplFile.close();
_settings->beginGroup("FreeSIWTCH/conf");
_settings->beginGroup(tmpl);
foreach(QString k, _settings->childKeys())
{
switch_event_add_header_string(e, SWITCH_STACK_BOTTOM, k.toAscii().constData(), _settings->value(k).toByteArray().constData());
}
char *res = switch_event_expand_headers(e, tmplContents.toAscii().constData());
switch_safe_free(e);
return switch_xml_parse_str(res, strlen(res));
}
static switch_xml_t xml_url_fetch(const char *section, const char *tag_name, const char *key_name, const char *key_value, switch_event_t *params,
void *user_data)
{
XMLBinding *binding = (XMLBinding *) user_data;
if (!binding) {
return NULL;
}
return binding->getConfigXML(key_value);
}
static switch_status_t do_config(void)
{
char *cf = "qsettings.conf";
switch_xml_t cfg, xml, bindings_tag;
XMLBinding *binding = NULL;
if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "open of %s failed\n", cf);
return SWITCH_STATUS_TERM;
}
if (!(bindings_tag = switch_xml_child(cfg, "bindings"))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing <bindings> tag!\n");
switch_xml_free(xml);
return SWITCH_STATUS_FALSE;
}
QString bind_mask = switch_xml_attr_soft(bindings_tag, "value");
if (!bind_mask.isEmpty())
{
binding = new XMLBinding(bind_mask);
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Binding XML Fetch Function [%s]\n",
binding->getBinding().isEmpty() ? "all" : binding->getBinding().toAscii().constData());
switch_xml_bind_search_function(xml_url_fetch, switch_xml_parse_section_string(binding->getBinding().toAscii().constData()), binding);
binding = NULL;
switch_xml_free(xml);
return SWITCH_STATUS_SUCCESS;
}
SWITCH_MODULE_LOAD_FUNCTION(mod_qsettings_load)
{
/*switch_api_interface_t *qsettings_api_interface;*/
/* connect my internal structure to the blank pointer passed to me */
*module_interface = switch_loadable_module_create_module_interface(pool, "mod_qsettings");
memset(&globals,0,sizeof(globals));
globals.pool = pool;
if (do_config() == SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Sucessfully configured.\n");
} else {
return SWITCH_STATUS_FALSE;
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "We loaded mod_qsettings.\n");
/* indicate that the module should continue to be loaded */
return SWITCH_STATUS_SUCCESS;
}
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_qsettings_shutdown)
{
switch_xml_unbind_search_function_ptr(xml_url_fetch);
return SWITCH_STATUS_SUCCESS;
}

View File

@ -0,0 +1,51 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005-2009, Anthony Minessale II <anthm@freeswitch.org>
*
* 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
* Anthony Minessale II <anthm@freeswitch.org>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Joao Mesquita <jmesquita@freeswitch.org>
*
*/
#ifndef MOD_QSETTINGS_H
#define MOD_QSETTINGS_H
#include <QString>
#include <QSettings>
#include <switch.h>
SWITCH_MODULE_LOAD_FUNCTION(mod_qsettings_load);
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_qsettings_shutdown);
class XMLBinding
{
public:
XMLBinding(QString binding) : _binding(binding), _settings(new QSettings) {}
QString getBinding(void) { return _binding; }
switch_xml_t getConfigXML(QString);
private:
QString _binding;
QSettings* _settings;
};
#endif // MOD_QSETTINGS_H

132
fscomm/prefdialog.cpp Normal file
View File

@ -0,0 +1,132 @@
#include <QtGui>
#include "prefdialog.h"
#include "ui_prefdialog.h"
PrefDialog::PrefDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::PrefDialog)
{
ui->setupUi(this);
getPaDevlist();
}
PrefDialog::~PrefDialog()
{
delete ui;
}
void PrefDialog::getPaDevlist()
{
QString result;
int errorLine, errorColumn;
QString errorMsg;
if (g_FSHost.sendCmd("pa", "devlist xml", &result) != SWITCH_STATUS_SUCCESS)
{
QMessageBox::critical(this, tr("PortAudio error" ),
tr("Error querying audio devices."),
QMessageBox::Ok);
return;
}
if (!_xmlPaDevList.setContent(result, &errorMsg, &errorLine, &errorColumn))
{
QMessageBox::critical(this, tr("PortAudio error" ),
tr("Error parsing output xml from pa devlist.\n%1 (Line:%2, Col:%3).").arg(errorMsg,
errorLine,
errorColumn),
QMessageBox::Ok);
return;
}
QDomElement root = _xmlPaDevList.documentElement();
if (root.tagName() != "xml")
{
QMessageBox::critical(this, tr("PortAudio error" ),
tr("Error parsing output xml from pa devlist. Root tag is not <xml>."),
QMessageBox::Ok);
return;
}
QDomElement devices = root.firstChildElement("devices");
if (devices.isNull())
{
QMessageBox::critical(this, tr("PortAudio error" ),
tr("Error parsing output xml from pa devlist. There is no <devices> tag."),
QMessageBox::Ok);
return;
}
QDomElement child = devices.firstChildElement();
if (child.isNull())
{
QMessageBox::critical(this, tr("PortAudio error" ),
tr("Error parsing output xml from pa devlist. There is no <device> tag."),
QMessageBox::Ok);
return;
}
while (!child.isNull())
{
if (child.tagName() == "device")
{
QString id, name, inputs, outputs;
id = child.attribute("id","-1");
name = child.attribute("name","Null");
inputs = child.attribute("inputs","0");
outputs = child.attribute("outputs","0");
if (inputs.toInt() != 0)
ui->PaIndevCombo->addItem(name,inputs.toInt());
if (outputs.toInt() != 0)
{
ui->PaOutdevCombo->addItem(name,inputs.toInt());
ui->PaRingdevCombo->addItem(name,inputs.toInt());
}
}
child = child.nextSiblingElement();
}
QDomElement bindings = root.firstChildElement("bindings");
if (bindings.isNull())
{
QMessageBox::critical(this, tr("PortAudio error" ),
tr("Error parsing output xml from pa devlist. There is no <bindings> tag."),
QMessageBox::Ok);
return;
}
child = devices.firstChildElement();
if (child.isNull())
{
QMessageBox::critical(this, tr("PortAudio error" ),
tr("Error parsing output xml from pa devlist. There are no bindings."),
QMessageBox::Ok);
return;
}
while (!child.isNull())
{
QString id;
id = child.attribute("device","-1");
if (child.tagName() == "ring")
ui->PaRingdevCombo->setCurrentIndex(id.toInt());
else if (child.tagName() == "input")
ui->PaIndevCombo->setCurrentIndex(id.toInt());
else if (child.tagName() == "ring")
ui->PaOutdevCombo->setCurrentIndex(id.toInt());
child = child.nextSiblingElement();
}
}
void PrefDialog::changeEvent(QEvent *e)
{
QDialog::changeEvent(e);
switch (e->type()) {
case QEvent::LanguageChange:
ui->retranslateUi(this);
break;
default:
break;
}
}

27
fscomm/prefdialog.h Normal file
View File

@ -0,0 +1,27 @@
#ifndef PREFDIALOG_H
#define PREFDIALOG_H
#include <QDialog>
#include <QDomDocument>
#include <fshost.h>
namespace Ui {
class PrefDialog;
}
class PrefDialog : public QDialog {
Q_OBJECT
public:
PrefDialog(QWidget *parent = 0);
~PrefDialog();
protected:
void changeEvent(QEvent *e);
private:
void getPaDevlist(void);
Ui::PrefDialog *ui;
QDomDocument _xmlPaDevList;
};
#endif // PREFDIALOG_H

376
fscomm/prefdialog.ui Normal file
View File

@ -0,0 +1,376 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PrefDialog</class>
<widget class="QDialog" name="PrefDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>477</width>
<height>356</height>
</rect>
</property>
<property name="windowTitle">
<string>Preferences</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QListWidget" name="listSections">
<property name="minimumSize">
<size>
<width>120</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>120</width>
<height>16777215</height>
</size>
</property>
<property name="showDropIndicator" stdset="0">
<bool>false</bool>
</property>
<property name="dragDropMode">
<enum>QAbstractItemView::NoDragDrop</enum>
</property>
<property name="iconSize">
<size>
<width>96</width>
<height>84</height>
</size>
</property>
<property name="movement">
<enum>QListView::Static</enum>
</property>
<property name="flow">
<enum>QListView::LeftToRight</enum>
</property>
<property name="isWrapping" stdset="0">
<bool>true</bool>
</property>
<property name="spacing">
<number>12</number>
</property>
<property name="viewMode">
<enum>QListView::IconMode</enum>
</property>
<item>
<property name="text">
<string>Sofia</string>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/images/pref_sip.png</normaloff>:/images/pref_sip.png</iconset>
</property>
</item>
<item>
<property name="text">
<string>PortAudio</string>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/images/pref_audio.gif</normaloff>:/images/pref_audio.gif</iconset>
</property>
</item>
</widget>
</item>
<item>
<widget class="QStackedWidget" name="stackedWidget">
<property name="currentIndex">
<number>1</number>
</property>
<widget class="QWidget" name="page">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Global Settings</string>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>log-level</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="spinBox"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>auto-restart</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="comboBox"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>debug-presence</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="spinBox_2"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Softphone Profile</string>
</property>
<layout class="QFormLayout" name="formLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>user-agent-string</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="lineEdit"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>debug</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="spinBox_3"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>sip-trace</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="comboBox_2"/>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="page_2">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Devices</string>
</property>
<widget class="QLabel" name="label_7">
<property name="geometry">
<rect>
<x>72</x>
<y>34</y>
<width>34</width>
<height>17</height>
</rect>
</property>
<property name="text">
<string>indev</string>
</property>
</widget>
<widget class="QComboBox" name="PaIndevCombo">
<property name="geometry">
<rect>
<x>111</x>
<y>32</y>
<width>111</width>
<height>26</height>
</rect>
</property>
</widget>
<widget class="QLabel" name="label_8">
<property name="geometry">
<rect>
<x>63</x>
<y>64</y>
<width>43</width>
<height>17</height>
</rect>
</property>
<property name="text">
<string>outdev</string>
</property>
</widget>
<widget class="QComboBox" name="PaOutdevCombo">
<property name="geometry">
<rect>
<x>111</x>
<y>62</y>
<width>111</width>
<height>26</height>
</rect>
</property>
</widget>
<widget class="QLabel" name="label_9">
<property name="geometry">
<rect>
<x>59</x>
<y>94</y>
<width>47</width>
<height>17</height>
</rect>
</property>
<property name="text">
<string>rindgev</string>
</property>
</widget>
<widget class="QComboBox" name="PaRingdevCombo">
<property name="geometry">
<rect>
<x>111</x>
<y>92</y>
<width>111</width>
<height>26</height>
</rect>
</property>
</widget>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_4">
<property name="title">
<string>Files</string>
</property>
<layout class="QFormLayout" name="formLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>ring-file</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="lineEdit_2">
<property name="text">
<string>tone_stream://%(2000,4000,440.0,480.0);loops=20</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>ring-interval</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="spinBox_4"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>hold-file</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="lineEdit_3"/>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources>
<include location="resources.qrc"/>
</resources>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>PrefDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>544</x>
<y>224</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>246</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>PrefDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>544</x>
<y>230</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>246</y>
</hint>
</hints>
</connection>
<connection>
<sender>listSections</sender>
<signal>currentRowChanged(int)</signal>
<receiver>stackedWidget</receiver>
<slot>setCurrentIndex(int)</slot>
<hints>
<hint type="sourcelabel">
<x>180</x>
<y>83</y>
</hint>
<hint type="destinationlabel">
<x>524</x>
<y>102</y>
</hint>
</hints>
</connection>
</connections>
</ui>

13
fscomm/resources.qrc Normal file
View File

@ -0,0 +1,13 @@
<RCC>
<qresource prefix="/images">
<file alias="splash.png">resources/splash.png</file>
<file alias="pref_sip.png">resources/pref_sip.png</file>
<file alias="pref_audio.gif">resources/pref_audio.gif</file>
</qresource>
<qresource prefix="/confs">
<file alias="freeswitch.xml">conf/freeswitch.xml</file>
<file alias="example.xml">conf/accounts/example.xml</file>
<file alias="event_socket.conf.xml">conf/event_socket.conf.xml</file>
<file alias="portaudio.conf.xml">conf/portaudio.conf.xml</file>
</qresource>
</RCC>

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
fscomm/resources/splash.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB