2012-09-13 02:52:43 +00:00
-- conference.lua
-- Part of FusionPBX
-- Copyright (C) 2012 Mark J Crane <markjcrane@fusionpbx.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:
--
-- 1. Redistributions of source code must retain the above copyright notice,
-- this list of conditions and the following disclaimer.
--
-- 2. 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.
--
-- THIS SOFTWARE IS PROVIDED ``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
-- AUTHOR 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.
--set variables
flags = "" ;
max_tries = 3 ;
digit_timeout = 5000 ;
--include the lua script
scripts_dir = string.sub ( debug.getinfo ( 1 ). source , 2 , string.len ( debug.getinfo ( 1 ). source ) - ( string.len ( argv [ 0 ]) + 1 ));
include = assert ( loadfile ( scripts_dir .. "/resources/config.lua" ));
include ();
--connect to the database
--ODBC - data source name
if ( dsn_name ) then
dbh = freeswitch.Dbh ( dsn_name , dsn_username , dsn_password );
end
--FreeSWITCH core db handler
if ( db_type == "sqlite" ) then
dbh = freeswitch.Dbh ( "core:" .. db_path .. "/" .. db_name );
end
2012-10-13 17:08:19 +00:00
--prepare the api object
api = freeswitch.API ();
2012-10-16 01:42:44 +00:00
--define the trim function
function trim ( s )
return s : gsub ( "^%s+" , "" ): gsub ( "%s+$" , "" )
end
2012-10-13 17:08:19 +00:00
--define the session hangup
function session_hangup_hook ()
2012-10-16 01:42:44 +00:00
--get the session variables
conference_session_detail_uuid = api : executeString ( "create_uuid" );
--conference_name = session:getVariable("conference_name");
conference_session_uuid = session : getVariable ( "conference_uuid" );
conference_recording = session : getVariable ( "conference_recording" );
conference_moderator = session : getVariable ( "conference_moderator" );
--start_epoch = session:getVariable("start_epoch");
--set the epoch
end_epoch = os.time ();
--get the conference sessions
sql = [[SELECT count(*) as num_rows
FROM v_conference_sessions
WHERE conference_session_uuid = ']] .. conference_session_uuid .. [[']] ;
status = dbh : query ( sql , function ( row )
2012-10-13 17:08:19 +00:00
num_rows = string.lower ( row [ "num_rows" ]);
2012-10-16 01:42:44 +00:00
end );
freeswitch.consoleLog ( "notice" , "[conference] SQL: " .. sql .. " Rows:" .. num_rows .. " \n " );
if ( num_rows == "0" ) then
local sql = {}
table.insert ( sql , "INSERT INTO v_conference_sessions " );
table.insert ( sql , "(" );
table.insert ( sql , "conference_session_uuid, " );
table.insert ( sql , "domain_uuid, " );
table.insert ( sql , "meeting_uuid, " );
table.insert ( sql , "profile, " );
if ( conference_recording ) then
table.insert ( sql , "recording, " );
end
--if (wait_mod) then
-- table.insert(sql, "wait_mod, ");
--end
table.insert ( sql , "start_epoch, " );
table.insert ( sql , "end_epoch " );
table.insert ( sql , ") " );
table.insert ( sql , "VALUES " );
table.insert ( sql , "( " );
table.insert ( sql , "'" .. conference_session_uuid .. "', " );
table.insert ( sql , "'" .. domain_uuid .. "', " );
table.insert ( sql , "'" .. meeting_uuid .. "', " );
table.insert ( sql , "'" .. profile .. "', " );
if ( conference_recording ) then
table.insert ( sql , "'" .. conference_recording .. "', " );
end
--if (wait_mod) then
-- table.insert(sql, "'".. wait_mod .."', ");
--end
table.insert ( sql , "'" .. start_epoch .. "', " );
table.insert ( sql , "'" .. end_epoch .. "' " );
table.insert ( sql , ") " );
SQL_STRING = table.concat ( sql , " \n " );
dbh : query ( SQL_STRING );
freeswitch.consoleLog ( "notice" , "[conference] SQL: " .. SQL_STRING .. " \n " );
else
freeswitch.consoleLog ( "notice" , "[conference] number is greater than 0 \n " );
end
2012-10-13 17:08:19 +00:00
local sql = {}
2012-10-16 01:42:44 +00:00
table.insert ( sql , "INSERT INTO v_conference_session_details " );
2012-10-13 17:08:19 +00:00
table.insert ( sql , "(" );
2012-10-16 01:42:44 +00:00
table.insert ( sql , "conference_session_detail_uuid, " );
2012-10-13 17:08:19 +00:00
table.insert ( sql , "domain_uuid, " );
2012-10-16 01:42:44 +00:00
table.insert ( sql , "conference_session_uuid, " );
2012-10-13 17:08:19 +00:00
table.insert ( sql , "meeting_uuid, " );
2012-10-16 01:42:44 +00:00
table.insert ( sql , "username, " );
table.insert ( sql , "caller_id_name, " );
table.insert ( sql , "caller_id_number, " );
table.insert ( sql , "network_addr, " );
table.insert ( sql , "uuid, " );
if ( conference_moderator ) then
table.insert ( sql , "moderator, " );
2012-10-13 17:08:19 +00:00
end
table.insert ( sql , "start_epoch, " );
table.insert ( sql , "end_epoch " );
table.insert ( sql , ") " );
table.insert ( sql , "VALUES " );
table.insert ( sql , "( " );
2012-10-16 01:42:44 +00:00
table.insert ( sql , "'" .. conference_session_detail_uuid .. "', " );
2012-10-13 17:08:19 +00:00
table.insert ( sql , "'" .. domain_uuid .. "', " );
2012-10-16 01:42:44 +00:00
table.insert ( sql , "'" .. conference_session_uuid .. "', " );
2012-10-13 17:08:19 +00:00
table.insert ( sql , "'" .. meeting_uuid .. "', " );
2012-10-16 01:42:44 +00:00
table.insert ( sql , "'" .. username .. "', " );
table.insert ( sql , "'" .. caller_id_name .. "', " );
table.insert ( sql , "'" .. caller_id_number .. "', " );
table.insert ( sql , "'" .. network_addr .. "', " );
table.insert ( sql , "'" .. uuid .. "', " );
if ( conference_moderator ) then
table.insert ( sql , "'" .. conference_moderator .. "', " );
2012-10-13 17:08:19 +00:00
end
table.insert ( sql , "'" .. start_epoch .. "', " );
table.insert ( sql , "'" .. end_epoch .. "' " );
table.insert ( sql , ") " );
SQL_STRING = table.concat ( sql , " \n " );
dbh : query ( SQL_STRING );
end
2012-09-13 02:52:43 +00:00
--make sure the session is ready
2012-10-16 01:42:44 +00:00
if ( session : ready ()) then
session : answer ();
session : setHangupHook ( "session_hangup_hook" );
sounds_dir = session : getVariable ( "sounds_dir" );
hold_music = session : getVariable ( "hold_music" );
domain_name = session : getVariable ( "domain_name" );
pin_number = session : getVariable ( "pin_number" );
--get the domain_uuid
if ( domain_name ~= nil ) then
sql = "SELECT domain_uuid FROM v_domains " ;
sql = sql .. "WHERE domain_name = '" .. domain_name .. "' " ;
if ( debug [ "sql" ]) then
freeswitch.consoleLog ( "notice" , "[conference] SQL: " .. sql .. " \n " );
end
status = dbh : query ( sql , function ( rows )
domain_uuid = string.lower ( rows [ "domain_uuid" ]);
end );
end
2012-10-16 06:02:05 +00:00
--add the domain to the recording directory
if ( domain_count > 1 ) then
recordings_dir = recordings_dir .. "/" .. domain_name ;
end
2012-10-16 01:42:44 +00:00
--set the sounds path for the language, dialect and voice
default_language = session : getVariable ( "default_language" );
default_dialect = session : getVariable ( "default_dialect" );
default_voice = session : getVariable ( "default_voice" );
if ( not default_language ) then default_language = 'en' ; end
if ( not default_dialect ) then default_dialect = 'us' ; end
if ( not default_voice ) then default_voice = 'callie' ; end
--get the variables
username = session : getVariable ( "username" );
caller_id_name = session : getVariable ( "caller_id_name" );
caller_id_number = session : getVariable ( "caller_id_number" );
callee_id_name = session : getVariable ( "callee_id_name" );
callee_id_number = session : getVariable ( "callee_id_number" );
dialplan = session : getVariable ( "dialplan" );
network_addr = session : getVariable ( "network_addr" );
uuid = session : getVariable ( "uuid" );
--context = session:getVariable("context");
chan_name = session : getVariable ( "chan_name" );
--if the pin number is provided then require it
if ( not pin_number ) then
min_digits = 3 ;
max_digits = 12 ;
pin_number = session : playAndGetDigits ( min_digits , max_digits , max_tries , digit_timeout , "#" , "phrase:voicemail_enter_pass:#" , "" , " \\ d+" );
end
--get the conference sessions
sql = [[SELECT * FROM v_conference_rooms as s, v_meeting_pins as p
WHERE s.domain_uuid = ']] .. domain_uuid .. [['
AND s.meeting_uuid = p.meeting_uuid
2012-10-19 23:41:52 +00:00
AND p.domain_uuid = ']] .. domain_uuid .. [['
2012-10-16 01:42:44 +00:00
AND p.member_pin = ']] .. pin_number .. [['
AND enabled = 'true' ]] ;
2012-09-13 02:52:43 +00:00
if ( debug [ "sql" ]) then
freeswitch.consoleLog ( "notice" , "[conference] SQL: " .. sql .. " \n " );
end
2012-10-16 01:42:44 +00:00
status = dbh : query ( sql , function ( row )
conference_room_uuid = string.lower ( row [ "conference_room_uuid" ]);
conference_center_uuid = string.lower ( row [ "conference_center_uuid" ]);
meeting_uuid = string.lower ( row [ "meeting_uuid" ]);
record = string.lower ( row [ "record" ]);
profile = string.lower ( row [ "profile" ]);
max_members = row [ "max_members" ];
wait_mod = row [ "wait_mod" ];
member_type = row [ "member_type" ];
announce = row [ "announce" ];
enter_sound = row [ "enter_sound" ];
mute = row [ "mute" ];
created = row [ "created" ];
created_by = row [ "created_by" ];
enabled = row [ "enabled" ];
description = row [ "description" ];
2012-09-13 02:52:43 +00:00
end );
2012-10-16 01:42:44 +00:00
--set the meeting uuid
session : setVariable ( "meeting_uuid" , meeting_uuid );
2012-10-13 17:08:19 +00:00
2012-10-16 01:42:44 +00:00
if ( conference_center_uuid == nil ) then
--invalid pin number
session : streamFile ( "phrase:voicemail_fail_auth:#" );
session : hangup ( "NORMAL_CLEARING" );
2012-10-13 17:08:19 +00:00
else
2012-10-16 01:42:44 +00:00
--check if the conference exists
cmd = "conference " .. meeting_uuid .. "-" .. domain_name .. " xml_list" ;
result = trim ( api : executeString ( cmd ));
if ( string.sub ( result , - 9 ) == "not found" ) then
conference_exists = false ;
else
conference_exists = true ;
end
2012-09-13 02:52:43 +00:00
2012-10-16 01:42:44 +00:00
--set a conference parameter
if ( max_members ~= nil ) then
2012-10-27 00:10:48 +00:00
if ( tonumber ( max_members ) > 0 ) then
--max members must be 2 or more
session : execute ( "set" , "conference_max_members=" .. max_members );
if ( conference_exists ) then
cmd = "conference " .. meeting_uuid .. "-" .. domain_name .. " get count" ;
count = trim ( api : executeString ( cmd ));
if ( count ~= nil ) then
if ( tonumber ( count ) >= tonumber ( max_members )) then
session : execute ( "playback" , sounds_dir .. "/" .. default_language .. "/" .. default_dialect .. "/" .. default_voice .. "/conference/conf-locked.wav" );
session : hangup ( "CALL_REJECTED" );
end
2012-10-16 01:42:44 +00:00
end
end
end
end
2012-09-13 02:52:43 +00:00
2012-10-16 01:42:44 +00:00
--announce the caller
if ( announce == "true" ) then
--prompt for the name of the caller
session : execute ( "playback" , sounds_dir .. "/" .. default_language .. "/" .. default_dialect .. "/" .. default_voice .. "/ivr/ivr-say_name.wav" );
session : execute ( "playback" , "tone_stream://v=-7;%%(500,0,500.0)" );
--record the response
max_len_seconds = 5 ;
silence_threshold = "500" ;
silence_secs = "2" ;
session : recordFile ( "/tmp/conference-" .. uuid .. ".wav" , max_len_seconds , silence_threshold , silence_secs );
end
2012-10-13 17:08:19 +00:00
2012-11-06 22:53:13 +00:00
--play a message that the conference is being a recorded
if ( record == "true" ) then
session : execute ( "playback" , sounds_dir .. "/" .. default_language .. "/" .. default_dialect .. "/" .. default_voice .. "/ivr/ivr-recording_started.wav" );
end
2012-10-16 01:42:44 +00:00
--wait for moderator
if ( wait_mod == "true" ) then
if ( conference_exists ) then
--continue
else
if ( member_type == "participant" ) then
--set music on hold variable
cmd = "uuid_setvar " .. uuid .. " hold_music " .. hold_music ;
result = api : executeString ( cmd );
--put the call on hold
--cmd = "uuid_hold "..uuid;
--result = api:executeString(cmd);
2012-09-13 02:52:43 +00:00
2012-10-16 01:42:44 +00:00
--loop until the conference exists
x = 0 ;
y = 0 ;
while true do
--sleep a moment to prevent using unecessary resources
session : sleep ( 3000 );
2012-10-13 17:08:19 +00:00
2012-10-16 01:42:44 +00:00
--play a tone
if ( x > 2 ) then
session : execute ( "playback" , "tone_stream://L=2;%(25,200,440,40);" );
--session:execute("playback", "ivr/ivr-stay_on_line_call_answered_momentarily.wav");
x = 1 ;
end
--check if the conference exists
cmd = "conference " .. meeting_uuid .. "-" .. domain_name .. " xml_list" ;
result = trim ( api : executeString ( cmd ));
if ( string.sub ( result , - 9 ) == "not found" ) then
--continue the loop
else
--set hold to off
--cmd = "uuid_hold off "..uuid;
--result = api:executeString(cmd);
--exit the loop;
break ;
end
--end the conference when the limit is reached
park_timeout_seconds = 1200 ;
if ( y > tonumber ( park_timeout_seconds )) then
break ;
end
--increment the value of x and y
x = x + 1 ;
y = y + 1 ;
end
end
end
end
--set the exit sound
if ( exit_sound ~= nil ) then
session : execute ( "set" , "conference_exit_sound=" .. exit_sound );
end
--else
-- session:execute("set","conference_exit_sound=");
--end
--set flags and moderator controls
if ( mute == "true" ) then
flags = flags .. "mute" ;
end
if ( member_type == "moderator" ) then
--set as the moderator
flags = flags .. "|moderator" ;
--when the moderator leaves end the conference
2012-11-06 22:55:12 +00:00
--flags = flags .. "|endconf";
2012-10-16 01:42:44 +00:00
--set the moderator controls
session : execute ( "set" , "conference_controls=moderator" );
end
2012-09-13 02:52:43 +00:00
2012-10-16 01:42:44 +00:00
--set the start epoch
start_epoch = os.time ();
--get the session uuid
if ( record == "true" ) then
--get the conference xml_list
cmd = "conference " .. meeting_uuid .. "-" .. domain_name .. " xml_list" ;
result = trim ( api : executeString ( cmd ));
if ( conference_exists ) then
--get the content to the <conference> tag
result = string.match ( result , [[<conference (.-)>]] , 1 );
--get the uuid out of the xml tag contents
conference_session_uuid = string.match ( result , [[uuid="(.-)"]] , 1 );
--log entry
freeswitch.consoleLog ( "INFO" , "conference_session_uuid: " .. conference_session_uuid .. " \n " );
--record the conference
2012-10-16 06:02:05 +00:00
cmd = "conference " .. meeting_uuid .. "-" .. domain_name .. " record " .. recordings_dir .. "/archive/" .. os.date ( "%Y" ) .. "/" .. os.date ( "%b" ) .. "/" .. os.date ( "%d" ) .. "/" .. conference_session_uuid .. ".wav" ;
2012-10-16 01:42:44 +00:00
response = api : executeString ( cmd );
2012-11-06 22:53:13 +00:00
--play a message that the conference is being a recorded
cmd = "conference " .. meeting_uuid .. "-" .. domain_name .. " play " .. sounds_dir .. "/" .. default_language .. "/" .. default_dialect .. "/" .. default_voice .. "/ivr/ivr-recording_started.wav" ;
freeswitch.consoleLog ( "notice" , "[conference] " .. cmd .. " \n " );
response = api : executeString ( cmd );
2012-10-16 01:42:44 +00:00
end
end
--announce the caller
if ( announce == "true" ) then
--announce the caller - play the recording
cmd = "conference " .. meeting_uuid .. "-" .. domain_name .. " play /tmp/conference-" .. uuid .. ".wav" ;
freeswitch.consoleLog ( "notice" , "[conference] " .. cmd .. " \n " );
response = api : executeString ( cmd );
--play has entered the conference
cmd = "conference " .. meeting_uuid .. "-" .. domain_name .. " play " .. sounds_dir .. "/" .. default_language .. "/" .. default_dialect .. "/" .. default_voice .. "/conference/conf-has_joined.wav" ;
freeswitch.consoleLog ( "notice" , "[conference] " .. cmd .. " \n " );
response = api : executeString ( cmd );
else
if ( enter_sound ~= nil ) then
cmd = "conference " .. meeting_uuid .. "-" .. domain_name .. " play " .. enter_sound ;
response = api : executeString ( cmd );
end
end
--send the call to the conference
cmd = meeting_uuid .. "-" .. domain_name .. "@" .. profile .. "+flags{" .. flags .. "}" ;
session : execute ( "conference" , cmd );
end
end