fusionpbx/includes/install/scripts/conference_center.lua

413 lines
15 KiB
Lua

-- 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
--prepare the api object
api = freeswitch.API();
--define the trim function
function trim(s)
return s:gsub("^%s+", ""):gsub("%s+$", "")
end
--define the session hangup
function session_hangup_hook()
--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)
num_rows = string.lower(row["num_rows"]);
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
local sql = {}
table.insert(sql, "INSERT INTO v_conference_session_details ");
table.insert(sql, "(");
table.insert(sql, "conference_session_detail_uuid, ");
table.insert(sql, "domain_uuid, ");
table.insert(sql, "conference_session_uuid, ");
table.insert(sql, "meeting_uuid, ");
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, ");
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_detail_uuid .."', ");
table.insert(sql, "'".. domain_uuid .."', ");
table.insert(sql, "'".. conference_session_uuid .."', ");
table.insert(sql, "'".. meeting_uuid .."', ");
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 .."', ");
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
--make sure the session is ready
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
--add the domain to the recording directory
if (domain_count > 1) then
recordings_dir = recordings_dir.."/"..domain_name;
end
--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
--sounds
enter_sound = "tone_stream://%(200,0,500,600,700)";
exit_sound = "tone_stream://%(500,0,300,200,100,50,25)";
--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
AND p.domain_uuid = ']] .. domain_uuid ..[['
AND p.member_pin = ']] .. pin_number ..[['
AND enabled = 'true' ]];
if (debug["sql"]) then
freeswitch.consoleLog("notice", "[conference] SQL: " .. sql .. "\n");
end
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"];
mute = row["mute"];
sounds = row["sounds"];
created = row["created"];
created_by = row["created_by"];
enabled = row["enabled"];
description = row["description"];
end);
--set the meeting uuid
session:setVariable("meeting_uuid", meeting_uuid);
if (conference_center_uuid == nil) then
--invalid pin number
session:streamFile("phrase:voicemail_fail_auth:#");
session:hangup("NORMAL_CLEARING");
else
--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
--set a conference parameter
if (max_members ~= nil) then
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
end
end
end
end
--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
--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
--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);
--loop until the conference exists
x = 0;
y = 0;
while true do
--sleep a moment to prevent using unecessary resources
session:sleep(3000);
--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 (sounds == "true") then
session:execute("set","conference_exit_sound="..exit_sound);
end
--set flags and moderator controls
if (mute == "true") then
if (member_type == "participant") then
flags = flags .. "mute";
end
end
if (member_type == "moderator") then
--set as the moderator
flags = flags .. "|moderator";
--when the moderator leaves end the conference
--flags = flags .. "|endconf";
--set the moderator controls
session:execute("set","conference_controls=moderator");
end
--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
cmd = "conference "..meeting_uuid.."-"..domain_name.." record "..recordings_dir.."/archive/"..os.date("%Y").."/"..os.date("%b").."/"..os.date("%d") .."/"..conference_session_uuid..".wav";
response = api:executeString(cmd);
--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);
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 (sounds == "true") 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