summaryrefslogtreecommitdiff
path: root/misc/freeswitch/scripts/common/conference.lua
diff options
context:
space:
mode:
Diffstat (limited to 'misc/freeswitch/scripts/common/conference.lua')
-rw-r--r--misc/freeswitch/scripts/common/conference.lua239
1 files changed, 239 insertions, 0 deletions
diff --git a/misc/freeswitch/scripts/common/conference.lua b/misc/freeswitch/scripts/common/conference.lua
new file mode 100644
index 0000000..d2bf829
--- /dev/null
+++ b/misc/freeswitch/scripts/common/conference.lua
@@ -0,0 +1,239 @@
+-- Gemeinschaft 5 module: conference class
+-- (c) AMOOMA GmbH 2012
+--
+
+module(...,package.seeall)
+
+Conference = {}
+
+MEMBERS_MAX = 100;
+PIN_LENGTH_MAX = 10;
+PIN_LENGTH_MIN = 2;
+PIN_TIMEOUT = 4000;
+ANNOUNCEMENT_MAX_LEN = 10
+ANNOUNCEMENT_SILENCE_THRESHOLD = 500
+ANNOUNCEMENT_SILENCE_LEN = 3
+
+-- create conference object
+function Conference.new(self, arg)
+ arg = arg or {}
+ object = arg.object or {}
+ setmetatable(object, self);
+ self.__index = self;
+ self.class = 'conference';
+ self.log = arg.log;
+ self.database = arg.database;
+ self.record = arg.record;
+ self.max_members = 0;
+ return object;
+end
+
+-- find conference by id
+function Conference.find_by_id(self, id)
+ local sql_query = 'SELECT * FROM `conferences` WHERE `id`= ' .. tonumber(id) .. ' LIMIT 1';
+ local conference = nil;
+
+ self.database:query(sql_query, function(conference_entry)
+ conference = Conference:new(self);
+ conference.record = conference_entry;
+ conference.id = tonumber(conference_entry.id);
+ conference.uuid = conference_entry.uuid;
+ conference.max_members = tonumber(conference.record.max_members) or MEMBERS_MAX;
+ end)
+
+ return conference;
+end
+
+-- find invitee by phone numbers
+function Conference.find_invitee_by_numbers(self, phone_numbers)
+ if not self.record then
+ return false
+ end
+
+ local sql_query = string.format(
+ "SELECT `conference_invitees`.`pin` AS `pin`, `conference_invitees`.`speaker` AS `speaker`, `conference_invitees`.`moderator` AS `moderator` " ..
+ "FROM `conference_invitees` JOIN `phone_numbers` ON `phone_numbers`.`phone_numberable_id` = `conference_invitees`.`id` " ..
+ "WHERE `phone_numbers`.`phone_numberable_type` = 'ConferenceInvitee' AND `conference_invitees`.`conference_id` = %d " ..
+ "AND `phone_numbers`.`number` IN ('%s') LIMIT 1", self.record.id, table.concat(phone_numbers, "','"));
+
+ local invitee = nil;
+
+ self.database:query(sql_query, function(conference_entry)
+ invitee = conference_entry;
+ end)
+
+ return invitee;
+end
+
+function Conference.count(self)
+ return tonumber(self.caller:result('conference ' .. self.record.id .. ' list count')) or 0;
+end
+
+-- Try to enter a conference
+function Conference.enter(self, caller, domain)
+ local cause = "NORMAL_CLEARING";
+ local pin = nil;
+ local flags = {'waste'};
+
+ self.caller = caller;
+
+ require "common.phone_number"
+ local phone_number_class = common.phone_number.PhoneNumber:new{log = self.log, database = self.database}
+ local phone_numbers = phone_number_class:list_by_owner(self.record.id, "Conference");
+
+ -- Set conference presence
+ require "dialplan.presence"
+ local presence = dialplan.presence.Presence:new();
+ presence:init{ log = log, accounts = phone_numbers, domain = domain, uuid = "conference_" .. self.record.id };
+
+ local conference_count = self:count();
+
+ -- Check if conference is full
+ if conference_count >= self.max_members then
+ presence:early();
+ self.log:debug(string.format("full conference %s (\"%s\"), members: %d, members allowed: %d", self.record.id, self.record.name, conference_count, self.max_members));
+
+ if (tonumber(self.record.conferenceable_id) == caller.account_owner_id)
+ and (self.record.conferenceable_type == caller.account_owner_type) then
+ self.log:debug("Allow owner of this conterence to enter a full conference");
+ else
+ cause = "CALL_REJECTED";
+ caller:hangup(cause);
+ return cause;
+ end;
+ end
+
+ -- Check if conference is within time frame
+ if self.record.start and self.record['end'] then
+ local d = {}
+ _,_,d.year,d.month,d.day,d.hour,d.min,d.sec=string.find(self.record.start, "(%d+)-(%d+)-(%d+) (%d+):(%d+):(%d+)");
+
+ local conference_start = os.time(d);
+ _,_,d.year,d.month,d.day,d.hour,d.min,d.sec=string.find(self.record['end'], "(%d+)-(%d+)-(%d+) (%d+):(%d+):(%d+)");
+ local conference_end = os.time(d);
+ local now = os.time(os.date("!*t", os.time()));
+
+ log:debug("conference - open: " .. os.date("%c",conference_start) .. " by " .. os.date("%c",conference_end) .. ", now: " .. os.date("%c",now));
+
+ if now < conference_start or now > conference_end then
+ cause = "CALL_REJECTED";
+ caller:hangup(cause);
+ return cause;
+ end
+ end
+
+ require 'common.str'
+ -- Owner ist always moderator
+ if (tonumber(self.record.conferenceable_id) == caller.account_owner_id) and (self.record.conferenceable_type == caller.account_owner_type) then
+ table.insert(flags, 'moderator');
+ log:debug("is owner - conference: " .. self.record.id .. ", owner: " .. caller.account_owner_type .. ":" .. caller.account_owner_id);
+ else
+ local invitee = self:find_invitee_by_numbers(caller.caller_phone_numbers);
+
+ if not common.str.to_b(self.record.open_for_anybody) and not invitee then
+ log:debug(string.format("conference %s (\"%s\"), caller %s not allowed to enter this conference", self.record.id, self.record.name, caller.caller_phone_number));
+ cause = "CALL_REJECTED";
+ caller:hangup(cause);
+ return cause;
+ end
+
+ if invitee then
+ log:debug("conference " .. self.record.id .. " member invited - speaker: " .. invitee.speaker .. ", moderator: " .. invitee.moderator);
+ if common.str.to_b(invitee.moderator) then
+ table.insert(flags, 'moderator');
+ end
+ if not common.str.to_b(invitee.speaker) then
+ table.insert(flags, 'mute');
+ end
+ pin = invitee.pin;
+ else
+ log:debug("conference " .. self.record.id .. " caller not invited");
+ end
+ end
+
+ if not pin and self.record.pin then
+ pin = self.record.pin
+ end
+
+ caller:answer();
+ caller:sleep(1000);
+ caller.session:streamFile('conference/conf-welcome.wav');
+
+ if pin and pin ~= "" then
+ local digits = "";
+ for i = 1, 3, 1 do
+ if digits == pin then
+ break
+ elseif digits ~= "" then
+ caller.session:streamFile('conference/conf-bad-pin.wav');
+ end
+ digits = caller.session:read(PIN_LENGTH_MIN, PIN_LENGTH_MAX, 'conference/conf-enter_conf_pin.wav', PIN_TIMEOUT, '#');
+ end
+ if digits ~= pin then
+ caller.session:streamFile("conference/conf-goodbye.wav");
+ return "CALL_REJECTED";
+ end
+ end
+
+ self.log:debug(string.format("entering conference %s - name: \"%s\", flags: %s, members: %d, max. members: %d",
+ self.record.id, self.record.name, table.concat(flags, ','), conference_count, self.max_members));
+
+ -- Members count will be incremented in a few milliseconds, set presence
+ if (conference_count + 1) >= self.max_members then
+ presence:early();
+ else
+ presence:confirmed();
+ end
+
+ -- Enter the conference
+ local name_file = nil;
+
+ -- Record caller's name
+ if common.str.to_b(self.record.announce_new_member_by_name) or common.str.to_b(self.record.announce_left_member_by_name) then
+ local uid = session:get_uuid();
+ name_file = "/tmp/conference_caller_name_" .. uid .. ".wav";
+ caller.session:streamFile("voicemail/vm-record_name1.wav");
+ caller.session:execute("playback", "tone_stream://%(1000,0,500)");
+ session:recordFile(name_file, ANNOUNCEMENT_MAX_LEN, ANNOUNCEMENT_SILENCE_THRESHOLD, ANNOUNCEMENT_SILENCE_LEN);
+ caller.session:streamFile(name_file);
+ end
+
+ -- Play entering caller's name if recorded
+ if name_file and (self:count() > 0) and common.str.to_b(self.record.announce_new_member_by_name) then
+ caller.session:execute('set',"result=${conference(" .. self.record.id .. " play ".. name_file .. ")}");
+ caller.session:execute('set',"result=${conference(" .. self.record.id .. " play conference/conf-has_joined.wav)}");
+ else
+ -- Ensure a surplus "#" digit is not passed to the conference
+ caller.session:read(1, 1, '', 1000, "#");
+ end
+
+ local result = caller.session:execute('conference', self.record.id .. "@profile_" .. self.record.id .. "++flags{" .. table.concat(flags, '|') .. "}");
+ self.log:debug('exited conference - result: ' .. tostring(result));
+ caller.session:streamFile("conference/conf-goodbye.wav")
+
+ -- Play leaving caller's name if recorded
+ if name_file then
+ if (self:count() > 0) and common.str.to_b(self.record.announce_left_member_by_name) then
+ if (self:count() == 1) then
+ caller.session:sleep(3000);
+ end
+ caller.session:execute('set',"result=${conference(" .. self.record.id .. " play ".. name_file .. ")}");
+ caller.session:execute('set',"result=${conference(" .. self.record.id .. " play conference/conf-has_left.wav)}");
+ end
+ os.remove(name_file);
+ end
+
+ -- Set presence according to member count
+ conference_count = self:count();
+ if conference_count >= self.max_members then
+ presence:early();
+ elseif conference_count > 0 then
+ presence:confirmed();
+ else
+ presence:terminated();
+ end
+
+ cause = "NORMAL_CLEARING";
+ caller.session:hangup(cause);
+ return cause;
+end