...
- Write this in a sane language with proper ESL support. Lua + PHP + fs_ivrd isn't really suited for tasks this big.
- Integrate with sipXconfig, etc.
- Multi-tenant/multi-server
- Call-Info field for compatibility with snom, others
- Probably a lot more
Setup
Warning |
---|
THIS GUIDE ASSUMES YOU ARE INSTALLING ON A FRESH CentOS 5.5 x86_64 SERVER WITHOUT sipXecs ON IT AND THAT YOU'VE ALREADY BUILT FreeSWITCH FROM SOURCE |
Note |
---|
WAV files used in this example are attached |
To start fs_ivrd you'll need to use this init script. Place it in /etc/init.d and mark it executable.
I'm not going to go through the particulars of setting up FreeSWITCH or installing the supporting database. I will give as much detail as possible.
...
Code Block |
---|
CREATE DATABASE conftest; CREATE TABLE page_data (entry_id integer NOT NULL, page_group character varying(255) NOT NULL, sip_uri character varying(255) NOT NULL, page_timeout timestamp without time zone NOT NULL); CREATE USER conftest WITH PASSWORD 'password123'; GRANT ALL PRIVILEGES ON DATABASE conftest to conftest; |
Now you need to allow conftest to log in to the database. To do this you will need to set a password on the posgresql user:
Code Block |
---|
ALTER USER postgres WITH PASSWORD 'password123'; |
Now edit /var/lib/pgsql/data/pg_hba.conf to be exactly like:
...
Here is an example of the data that should be entered in this database:
entry_id | page_group | sip_uri | page_timeout |
---|---|---|---|
1 | 3402 | 7001@sipx.domain.tld | 2011-05-10 14:19:30 |
2 | 3402 | 7002@sipx.domain.tld | 2011-05-10 14:19:30 |
3 | 3402 | 7003@sipx.domain.tld | 2011-05-10 14:19:30 |
Now you need to allow conftest to log in to the database. To do this you will need to set a password on the posgresql user:
Code Block |
---|
ALTER USER postgres WITH PASSWORD 'password123'; |
Now edit /var/lib/pgsql/data/pg_hba.conf to be exactly like:
Code Block |
---|
local all all password
host all all 127.0.0.1/32 password
host all all ::1/128 ident sameuser
local all conftest crypt |
Now restart postgresql
FreeSWITCH
Create a new conference profile called intercom in 8/usr/local/freeswitch/conference.conf.xml* and set it to the following:
Code Block |
---|
<profile name="intercom"> <param name="domain" value="$${domain}"/> <param name="rate" value="16000"/> <param name="interval" value="20"/> <param name="energy-level" value="300"/> <param name="sound-prefix" value="$${sounds_dir}/en/us/callie"/> <param name="muted-sound" value="conference/conf-muted.wav"/> <param name="unmuted-sound" value="conference/conf-unmuted.wav"/> <param name="alone-sound" value="conference/conf-alone.wav"/> <param name="moh-sound" value="$${hold_music}"/> <param name="enter-sound" value=""/> <param name="exit-sound" value=""/> <param name="kicked-sound" value=""/> <param name="locked-sound" value="conference/conf-locked.wav"/> <param name="is-locked-sound" value="conference/conf-is-locked.wav"/> <param name="is-unlocked-sound" value="conference/conf-is-unlocked.wav"/> <param name="pin-sound" value="conference/conf-pin.wav"/> <param name="bad-pin-sound" value="conference/conf-bad-pin.wav"/> <param name="caller-id-name" value="$${outbound_caller_name}"/> <param name="caller-id-number" value="$${outbound_caller_id}"/> all <param name="comfort-noise" value="true"/> ::1/128 </profile> |
Note |
---|
Be sure to create a gateway pointing to you FreeSWITCH server in sipXecs and point the appropriate numbers to it |
Add the following to your FreeSWITCH dialpan (change expressions to meet your needs):
Code Block |
---|
<extension name="Page Test"> <condition ident sameuser local all conftest crypt |
Now restart postgresql
FreeSWITCH
Add the following to your FreeSWITCH dialpan:
Code Block |
---|
<extension name="Page Test">field="destination_number" expression="^(3402)$"> <action application="lua" data="/usr/local/freeswitch/scripts/page_outcall.lua $1"/> <condition<action fieldapplication="destination_numberset" expression="^(3402)$"data="ivr_path=/usr/local/freeswitch/scripts/page_int.php"/> <action application="luasocket" data="/usr/local/freeswitch/scripts/page_outcall.lua $1"/"127.0.0.1:9090 async full"/> </condition> </extension> <extension name="outbound-socket"> <action<condition applicationfield="setdestination_number" data="ivr_path=/usr/local/freeswitch/scripts/page_int.php"/expression="^(3403)$"> <action application="socketlua" data="127.0.0.1:9097 async full/usr/local/freeswitch/scripts/page_time_set.lua"/> </condition> </extension> <extension name="outbound-socket"> <condition field="destination_number" expression="^(3403)$"> <action application="lua" data="/usr/local/freeswitch/scripts/page_time_set.lua"/> </condition> </extension> |
Add the following scripts to your /usr/local/freeswitch/scripts folder:
Code Block | ||
---|---|---|
| ||
#!/usr/bin/php -q <?php // set a couple of things so we dont kill the system ob_implicit_flush(true); set_time_limit(30); // Open stdin so we can read the data in $in = fopen("php://stdin", "r"); // Connect to conference /extension> |
now reload FreeSWITCH
Add the following scripts to your /usr/local/freeswitch/scripts folder:
Code Block | ||
---|---|---|
| ||
#!/usr/bin/php -q <?php // set a couple of things so we dont kill the system ob_implicit_flush(true); set_time_limit(30); // Open stdin so we can read the data in $in = fopen("php://stdin", "r"); // Connect to conference echo "sendmsg\n"; echo "call-command: execute\n"; echo "execute-app-name: set\n"; echo "execute-app-arg: conference_auto_outcall_flags=mute\n\n"; echo "sendmsg\n"; echo "call-command: execute\n"; echo "execute-app-name: set\n"; echo "execute-app-arg: api_hangup_hook=conference $1 kick all\n\n"; echo "sendmsg\n"; echo "call-command: execute\n"; echo "execute-app-name: conference\n"; echo "execute-app-arg: $1@intercom\n\n"; echo "sendmsg\n"; echo "call-command: execute\n"; echo "execute-app-name: setsleep\n"; echo "execute-app-arg: conference_auto_outcall_flags=mute\n\n"; 350\n"; echo "event-lock:true\n\n"; // Play a prompt at the beginning of the page/conference echo "sendmsg\n"; echo "call-command: execute\n"; echo "execute-app-name: set\n"; echo "execute-app-arg: api_hangup_hook=tmp=\${conference $1 kick allplay /usr/local/freeswitch/sounds/tones/norstar.wav}\n\n"; echo "sendmsg\n"; echo "call-command: execute\n"; echo "execute-app-name: conference\n"; echo "execute-app-arg: $1@default\n\n"; echo "sendmsg\n"; echo "call-command: execute\n"; echo "execute-app-name: sleep\n"; echo "execute-app-arg: 350\n"; echo "event-lock:true\n\n"; // Play a prompt at the beginning of the page/conference echo "sendmsg\n"; echo "call-command: execute\n"; echo "execute-app-name: set\n"; echo "execute-app-arg: tmp=\${conference $1 play /usr/local/freeswitch/sounds/tones/norstar.wav}\n\n"; fclose($in); ?> | ||
Code Block | ||
| ||
require "luasql.postgres" -- Exit if no argument if argv[1] == nil then print ("One argument is required") os.exit(0) end -- Get current epoch today = os.time() -- Connect to DB, get page info env = assert (luasql.postgres()) con = assert (env:connect("conftest","conftest","fail2sxp","localhost")) cur = assert (con:execute("SELECT entry_id, page_group, sip_uri, extract(epoch FROM page_timeout) FROM page_data WHERE page_group = " .. argv[1])) row = cur:fetch ({}, "a") page_table = {} i = 1 -- iterate through list of extensions to be paged and discard those on timeout while row do if tonumber(row.date_part) > today then fclose($in); ?> |
Code Block | ||
---|---|---|
| ||
require "luasql.postgres"
-- Exit if no argument
if argv[1] == nil then
print ("One argument is required")
os.exit(0)
end
-- Get current epoch
today = os.time()
-- Connect to DB, get page info
env = assert (luasql.postgres())
con = assert (env:connect("conftest","conftest","password123","localhost"))
cur = assert (con:execute("SELECT entry_id, page_group, sip_uri, extract(epoch FROM page_timeout) FROM page_data WHERE page_group = " .. argv[1]))
row = cur:fetch ({}, "a")
page_table = {}
i = 1
-- iterate through list of extensions to be paged and discard those on timeout
while row do
if tonumber(row.date_part) > today then
print ("Skipping")
-- keeps system from paging the pager :-P
elseif row.sip_uri == sipuri then
print ("Skipping")
else
page_table[i] = row.sip_uri
end
row = cur:fetch(row, "a")
i = i + 1
end
-- Close DB connection as we won't be needing it anymore
cur:close()
con:close()
env:close()
session:answer()
cidname = session:getVariable("caller_id_name")
session:execute("export", "sip_invite_params=intercom=true")
session:execute("export", "sip_auto_answer=true")
session:execute("set", "conference_auto_outcall_caller_id_name=Page From " .. cidname)
session:execute("set", "conference_auto_outcall_caller_id_number=" .. argv[1])
session:execute("set", "conference_auto_outcall_timeout=60")
-- Make the calls
for i,v in pairs (page_table) do
session:execute("conference_set_auto_outcall", "{alert_info=sipXpage}sofia/custom_dialplan/" .. v .. ";sipx-noroute=VoiceMail;sipx-userforward=false+flags")
end
|
Code Block | ||
---|---|---|
| ||
require "luasql.postgres" -- Get caller's SIP URI sipuri = session:getVariable("sip_from_uri") -- Connect to DB env = assert (luasql.postgres()) con = assert (env:connect("conftest","conftest","fail2sxppassword123","localhost")) cur = assert (con:execute("SELECT sip_uri FROM page_data WHERE sip_uri = '" .. sipuri .. "'")) row = cur:fetch ({}, "a") uri_table = {} i = 1 while row do uri_table[i] = row.sip_uri row = cur:fetch(row, "a") i = i + 1 end -- WAKE UP! :-) session:answer() session:sleep(1000) -- If user isn't in DB then they don't need to set a timeout, now do they? if uri_table[1] == nil then session:streamFile("/usr/local/freeswitch/sounds/en/us/callie/voicemail/16000/vm-that_was_an_invalid_ext.wav") else -- Get amount of minutes user wants to be on timeout for digits = session:playAndGetDigits(1, 2, 1, 3000, "#", "/usr/local/freeswitch/sounds/tones/enter-minutes.wav", "/usr/local/freeswitch/sounds/en/us/callie/voicemail/16000/vm-abort.wav", ".+") end -- Get current epoch today = os.time() -- If user doesn't enter anything then why continue? if tonumber(digits) == nil then session:hangup() -- Update DB, split out at 20 to make file playback easier elseif tonumber(digits) < 20 then new_time = today + (tonumber(digits) * 60) session:streamFile("/usr/local/freeswitch/sounds/en/us/callie/digits/16000/" .. digits .. ".wav") session:streamFile("/usr/local/freeswitch/sounds/en/us/callie/time/16000/minutes.wav") res = assert (con:execute("UPDATE page_data SET page_timeout=to_timestamp(" .. new_time .. ") WHERE sip_uri = '" .. sipuri .. "'")) else new_time = today + (tonumber(digits) * 60) digsplit = {} for dig in digits:gmatch("%d") do table.insert(digsplit, dig) end session:streamFile("/usr/local/freeswitch/sounds/en/us/callie/digits/16000/" .. digsplit[1] .. "0.wav") session:streamFile("/usr/local/freeswitch/sounds/en/us/callie/digits/16000/" .. digsplit[2] .. ".wav") session:streamFile("/usr/local/freeswitch/sounds/en/us/callie/time/16000/minutes.wav") res = assert (con:execute("UPDATE page_data SET page_timeout=to_timestamp(" .. new_time .. ") WHERE sip_uri = '" .. sipuri .. "'")) end session:sleep(500) session:hangup() -- Kill DB cur:close() con:close() env:close() |