Probleme beim Heranholen/Pickup/BLF mit Rufgruppen

209 views
Skip to first unread message

Bernd Kast

unread,
Apr 26, 2014, 3:21:37 PM4/26/14
to gs5-...@googlegroups.com
Hallo,

ich habe ein Problem beim Zusammenspiel von Rufgruppen und Heranholen von anrufen.

Ein Telefon und eine Zusatzklingel sollen gleichzeitig läuten, weshalb sie in einer Huntgroup sind.
Rufe ich die Nummer des Telefons direkt an, kann ich das Gespräch von einem anderen Telefon aus mit dem BLF heranholen.
Wird die Huntgroup angerufen klingeln Telefon und Klingel, auch BLF blinkt, das Heranholen schlägt allerdings fehl.
Im Log erscheint dann
EXECUTE sofia/gemeinschaft/ea80ae07ae1f51781494@192.168.3.1:5060 respond(200 OK)
2014-04-26 20:25:00.277942 [DEBUG] mod_sofia.c:2634 Responding with 200 [OK]
2014-04-26 20:25:00.277942 [WARNING] mod_sofia.c:2695 Cannot respond.
2014-04-26 20:25:00.277942 [DEBUG] switch_core_session.c:830 Send signal sofia/gemeinschaft/ea80ae07ae1f51781494@192.168.3.1:5060 [BREAK]
2014-04-26 20:25:00.286750 [DEBUG] switch_cpp.cpp:668 CoreSession::hangup
Am Telefon, mit dem man das Heranholen versucht hat, hört man den Besetztton.
Die anderen Telefone klingeln weiter wie ohne den Versuch.

Als Alternative habe ich noch getestet, ob es mit f-ig- anstatt f-ia klappt, allerdings mit dem selben Ergebniss: wird der Account direkt angerufen kann dieser Anruf von einem anderen Telefon herangeholt werden, andernfalls ertönt das Besetztzeichen und es erscheint im Log der exakt gleiche Fehler.

Hat jemand anders ein änliches Problem oder funktioniert es bei jemandem?
Hier: https://groups.google.com/forum/#!searchin/gs5-users/pickup/gs5-users/UBg_DkXx0R0/VxH_nAr4JtUJ schreibt jemand, dass Group pickup bei ihm funktioniert. Allerdings stehen keine genaueren Informationen darüber, ob es auch funktioniert, wenn über eine Huntgroup angerufen wurde.
Für das Grouppickup habe ich eine neue Gruppe unter {IP}/groups/ angelegt, die zwei SIP Accounts als Mitglieder und Pickuprechte auf alle anderen Gruppen hat. Allerdings kann ich weder mit dem Account innerhalb der Gruppe den Anruf auf den anderen Heranholen noch mit einem Account von außerhalb der Gruppe.

Die einzigste Alternative die mir momentan noch bleibt ist zu versuchen ohne Rufgruppen auszukommen. Dazu müssten mehrere Geräte sich auf einem SIP-Account einloggen. Da klingelt dann aber nur das, das sich zuletzt angemeldet hat.

Weiß jemand was ich falsch mache und kann mir helfen?

Grüße
Bernd


Bernd Kast

unread,
Apr 27, 2014, 10:18:43 AM4/27/14
to gs5-...@googlegroups.com
Hallo,

ich habe eine (Übergangs-)Lösung gefunden.
Beim Vergleich des Logs zwischen einem Anruf an eine Gruppe und an einen SIP-Account ist die unterschiedliche call_url aufgefallen, bei der bei dem Gruppenanruf keine "pickup/sXX" bzw "pickup/gXX" enthalten sind.
Generiert wird diese URL anscheinend in misc/freeswitch/scripts/dialplan/sip_call.lua
Diese Datei habe ich jetzt angepasst:
-- Gemeinschaft 5 module: sip call class
-- (c) AMOOMA GmbH 2012-2013
--

module(...,package.seeall);

SipCall = {}

-- Create SipCall object
function SipCall.new(self, arg)
  arg
= arg or {}
 
object = arg.object or {}
  setmetatable
(object, self);
 
self.__index = self;
 
self.log = arg.log;
 
self.session = arg.session;
 
self.record = arg.record;
 
self.database = arg.database;
 
self.domain = arg.domain;
 
self.caller = arg.caller;
 
self.on_answer = arg.on_answer;
 
self.calling_object = arg.calling_object;
 
return object;
end


function SipCall.wait_answer(self, caller_session, callee_session, timeout, start_time)
 
if caller_session:ready() and callee_session:ready() then
    callee_session
:waitForAnswer(caller_session);
 
end

 
while true do
   
if not caller_session:ready() then
     
return 'ORIGINATOR_CANCEL';
    elseif
not callee_session:ready() then
     
return 'UNSPECIFIED';
    elseif
(os.time() - start_time) > timeout then
     
return 'NO_ANSWER';
    elseif callee_session
:answered() then
     
return 'SUCCESS';
   
end
   
   
self.caller:sleep(500);
 
end
end


function SipCall.wait_hangup(self, caller_session, callee_session)
 
local hangup_on = {
    CS_HANGUP  
= true,
    CS_DESTROY
= true,
 
}

 
while true do
   
local state_caller = caller_session:getState();
   
local state_callee = callee_session:getState();
   
if hangup_on[state_caller] or hangup_on[state_callee] then
     
break;
   
end
    caller_session
:sleep(500);
 
end
end


function SipCall.call_waiting_busy(self, sip_account)
 
require 'common.str'
 
if common.str.to_b(sip_account.record.call_waiting) then
   
self.log:info('CALL_WAITING - status: enabled');
   
return false;
 
else
   
local state = sip_account:call_state();
   
self.log:info('CALL_WAITING - status: disabled, sip_account state: ', state);
   
return state;
 
end
end


function SipCall.fork(self, destinations, arg )
 
local dial_strings = {};
 
local pickup_groups = {};
 
local bernd_pickups = {};

 
require 'common.sip_account'
 
require 'common.str'

 
local sip_account_class = common.sip_account.SipAccount:new{ log = self.log, database = self.database };

 
local call_result = { code = 404, phrase = 'No destination' };
 
local some_destinations_busy = false;

 
for index, destination in ipairs(destinations) do
   
local origination_variables = { 'gs_fork_index=' .. index }

   
self.log:info('FORK ', index, '/', #destinations, ' - ', destination.type, '=', destination.id, '/', destination.uuid, '@', destination.node_id, ', number: ', destination.number, ', caller_id: "', destination.caller_id_name, '" <', destination.caller_id_number, '>');
   
   
if not common.str.to_b(arg.update_callee_display) then
      table
.insert(origination_variables, 'ignore_display_updates=true');
   
end

   
if not destination.node_local or destination.type == 'node' then
     
require 'common.node'
     
local node = nil;

     
if not destination.node_local then
        node
= common.node.Node:new{ log = self.log, database = self.database }:find_by_id(destination.node_id);
     
else
        node
= common.node.Node:new{ log = self.log, database = self.database }:find_by_id(destination.id);
     
end
     
if node then
        table
.insert(origination_variables, 'sip_h_X-GS_node_id=' .. self.caller.local_node_id);
        table
.insert(origination_variables, 'sip_h_X-GS_account_uuid=' .. tostring(self.caller.account_uuid));
        table
.insert(origination_variables, 'sip_h_X-GS_account_type=' .. tostring(self.caller.account_type));
        table
.insert(origination_variables, 'sip_h_X-GS_auth_account_type=' .. tostring(self.caller.auth_account_type));
        table
.insert(origination_variables, 'sip_h_X-GS_auth_account_uuid=' .. tostring(self.caller.auth_account_uuid));
        table
.insert(origination_variables, 'sip_h_X-GS_loop_count=' .. tostring(self.caller.loop_count));
        table
.insert(dial_strings, '[' .. table.concat(origination_variables , ',') .. ']sofia/gateway/' .. node.record.name .. '/' .. destination.number);
     
end
    elseif destination
.type == 'sipaccount' then
     
local callee_id_params = '';
     
local sip_account = sip_account_class:find_by_id(destination.id);
      table
.insert(bernd_pickups, 'pickup/s' .. common.str.to_i(destination.account.id));
     
if not sip_account then
       
self.log:notice('FORK - sip_account not found - sip_account=', destination.id);
      elseif common
.str.blank(sip_account.record.profile_name) or common.str.blank(sip_account.record.sip_host) then
        call_result
= { code = 480, phrase = 'User offline', disposition = 'USER_NOT_REGISTERED' };
     
else
       
local call_waiting = self:call_waiting_busy(sip_account);
       
if not call_waiting then
          destinations
[index].numbers = sip_account:phone_numbers();

         
if not arg.callee_id_name then
            table
.insert(origination_variables, "effective_callee_id_name='" .. sip_account.record.caller_name .. "'");
         
end
         
if not arg.callee_id_number then
            table
.insert(origination_variables, "effective_callee_id_number='" .. destination.number .. "'");
         
end
         
if destination.alert_info then
            table
.insert(origination_variables, "alert_info='" .. destination.alert_info .. "'");
         
end
         
if destination.account then
            table
.insert(origination_variables, "gs_account_type='" .. common.str.to_s(destination.account.class) .. "'");
            table
.insert(origination_variables, "gs_account_id='" .. common.str.to_i(destination.account.id) .. "'");
            table
.insert(origination_variables, "gs_account_uuid='" .. common.str.to_s(destination.account.uuid) .. "'");
         
end
         
if self.caller.auth_account then
            table
.insert(origination_variables, "gs_auth_account_type='" .. common.str.to_s(self.caller.auth_account.class) .. "'");
            table
.insert(origination_variables, "gs_auth_account_id='" .. common.str.to_i(self.caller.auth_account.id) .. "'");
            table
.insert(origination_variables, "gs_auth_account_uuid='" .. common.str.to_s(self.caller.auth_account.uuid) .. "'");
         
end

          table
.insert(dial_strings, '[' .. table.concat(origination_variables , ',') .. ']sofia/' .. sip_account.record.profile_name .. '/' .. sip_account.record.auth_name .. '%' .. sip_account.record.sip_host);
         
if destination.pickup_groups and #destination.pickup_groups > 0 then
           
for key=1, #destination.pickup_groups do
              pickup_groups
[destination.pickup_groups[key]] = true;
           
end
         
end
       
else
          some_destinations_busy
= true;
          call_result
= { code = 486, phrase = 'User busy', disposition = 'USER_BUSY' };
       
end
     
end
    elseif destination
.type == 'gateway' then
     
require 'common.gateway'
     
local gateway = common.gateway.Gateway:new{ log = self.log, database = self.database}:find_by_id(destination.id);

     
if gateway and gateway.outbound then
       
if destination.caller_id_number then
          table
.insert(origination_variables, "origination_caller_id_number='" .. destination.caller_id_number .. "'");
       
end
       
if destination.caller_id_name then
          table
.insert(origination_variables, "origination_caller_id_name='" .. destination.caller_id_name .. "'");
       
end
       
if destination.channel_variables then
         
for key, value in pairs(destination.channel_variables) do
            table
.insert(origination_variables, tostring(key) .. "='" .. tostring(value) .. "'");
         
end
       
end

        table
.insert(dial_strings, '[' .. table.concat(origination_variables , ',') .. ']' .. gateway:call_url(destination.number));
     
else
       
self.log:notice('FORK - gateway not found - gateway=', destination.id);
     
end
    elseif destination
.type == 'dial' then
     
if destination.caller_id_number then
        table
.insert(origination_variables, "origination_caller_id_number='" .. destination.caller_id_number .. "'");
     
end
     
if destination.caller_id_name then
        table
.insert(origination_variables, "origination_caller_id_name='" .. destination.caller_id_name .. "'");
     
end
      table
.insert(dial_strings, '[' .. table.concat(origination_variables , ',') .. ']' .. destination.number);
   
else
     
self.log:info('FORK ', index, '/', #destinations, ' - unhandled destination type: ', destination.type, ', number: ', destination.number);
   
end
 
end

 
if #dial_strings == 0 then
   
self.log:notice('FORK - no active destinations - result: ', call_result.code, ' ', call_result.phrase);
   
return call_result;
 
end

 
self.caller:set_callee_id(arg.callee_id_number, arg.callee_id_name);

 
self.caller:set_variable('call_timeout', arg.timeout );
 
self.log:info('FORK DIAL - destinations: ', #dial_strings, ', timeout: ', arg.timeout);
 
 
--Bernd: ffuer Huntgroups eine Sonderbehandlung
 
if common.str.to_s(self.caller.auth_account.class)  == 'huntgroup' then
     
--Bernd: hier bei allen Gruppenmitgliedern alle nummern eintragen
   
--table.insert(dial_strings, 'pickup/s22');
    table
.insert(dial_strings, table.concat(bernd_pickups, ','));
 
else
     
for pickup_group, value in pairs(pickup_groups) do
       table
.insert(dial_strings, 'pickup/' .. pickup_group);
     
end
 
end
   
 
if arg.send_ringing then
   
self.caller:execute('ring_ready');
 
end

 
local session_dialstring = '{local_var_clobber=true}' .. table.concat(dial_strings, ',');
 
self.log:debug('FORK SESSION_START - call_url: ', session_dialstring);
 
local start_time = os.time();
 
local session_callee = freeswitch.Session(session_dialstring, self.caller.session);
 
self.log:debug('FORK SESSION_INIT - dial_time: ', os.time() - start_time);
 
local answer_result = self:wait_answer(self.caller.session, session_callee, arg.timeout, start_time);
 
local fork_index = nil;
 
self.log:info('FORK ANSWER - status: ', answer_result, ', dial_time: ', os.time() - start_time);
 
if answer_result == 'SUCCESS' then
    session_callee
:setAutoHangup(false);
    fork_index
= tonumber(session_callee:getVariable('gs_fork_index')) or 0;
   
local destination = destinations[fork_index];

   
if not destination then
      destination
= {
       
['type'] = session_callee:getVariable('gs_account_type');
        id
= session_callee:getVariable('gs_account_id');
        uuid
= session_callee:getVariable('gs_account_uuid');
        pickup_group_pick
= session_callee:getVariable('gs_pickup_group_pick');
     
}
     
self.log:notice('FORK - call picked off by: ', destination.type, '=', destination.id, '/', destination.uuid, ', pickup_group: ', destination.pickup_group_pick);
   
end

   
if arg.detect_dtmf_after_bridge_caller and self.caller.auth_account then
     
if not string.match(self.caller:to_s('switch_r_sdp'), '101 telephone%-event') then
       
self.log:notice('FORK A_LEG inband dtmf detection - channel_uuid: ', session:get_uuid());
        session
:execute('start_dtmf');
     
end
   
end
   
   
if arg.detect_dtmf_after_bridge_callee and destination.type == 'sipaccount' then
     
if not string.match(tostring(session_callee:getVariable('switch_r_sdp')), '101 telephone%-event') then
       
self.log:notice('FORK B_LEG inband dtmf detection - channel_uuid: ', session_callee:get_uuid());
        session_callee
:execute('start_dtmf');
     
end
   
end

   
if arg.bypass_media_network then
     
local callee_uuid = session_callee:get_uuid();

     
if callee_uuid and self.caller.uuid and freeswitch then
       
require 'common.ipcalc'
       
local callee_network_str = self.caller:to_s('bleg_network_addr');
       
local caller_network_str = self.caller:to_s('network_addr');
       
local callee_network_addr = common.ipcalc.ipv4_to_i(callee_network_str);
       
local caller_network_addr = common.ipcalc.ipv4_to_i(caller_network_str);
       
local network, netmask = common.ipcalc.ipv4_to_network_netmask(arg.bypass_media_network);
       
if network and netmask and callee_network_addr and caller_network_addr
         
and common.ipcalc.ipv4_in_network(callee_network_addr, network, netmask)
         
and common.ipcalc.ipv4_in_network(caller_network_addr, network, netmask) then
         
self.log:info('FORK ', fork_index, ' BYPASS_MEDIA - caller_ip: ', caller_network_str,
           
', callee_ip: ', callee_network_str,
           
', subnet: ', arg.bypass_media_network,
           
', uuid: ', self.caller.uuid, ', bleg_uuid: ', callee_uuid);
          freeswitch
.API():execute('uuid_media', 'off ' .. self.caller.uuid);
          freeswitch
.API():execute('uuid_media', 'off ' .. callee_uuid);
       
end
     
end
   
end

   
if self.on_answer then
     
self.on_answer(self.calling_object, destination);
   
end

   
self.caller:set_variable('gs_destination_type', destination.type);
   
self.caller:set_variable('gs_destination_id', destination.id);
   
self.caller:set_variable('gs_destination_uuid', destination.uuid);

   
if arg.detect_dtmf_after_bridge_callee then
      session_callee
:setInputCallback('input_call_back_callee', 'session_callee');
   
end

   
self.log:info('FORK ', fork_index,
     
' BRIDGE - destination: ', destination.type, '=', destination.id, '/', destination.uuid,'@', destination.node_id,
     
', number: ', destination.number,
     
', dial_time: ', os.time() - start_time);

    freeswitch
.bridge(self.caller.session, session_callee);
   
self:wait_hangup(self.caller.session, session_callee);
 
end

 
-- if session_callee:ready() then
   
-- self.log:info('FORK - hangup destination channel');
   
-- session_callee:hangup('ORIGINATOR_CANCEL');
 
-- end

  call_result
= {};
  call_result
.disposition = session_callee:hangupCause();
  call_result
.fork_index = fork_index;

 
if some_destinations_busy and call_result.disposition == 'USER_NOT_REGISTERED' then
    call_result
.phrase = 'User busy';
    call_result
.code = 486;
    call_result
.disposition = 'USER_BUSY';
  elseif call_result
.disposition == 'USER_NOT_REGISTERED' then
    call_result
.phrase = 'User offline';
    call_result
.code = 480;
  elseif call_result
.disposition == 'NO_ANSWER' then
    call_result
.phrase = 'No answer';
    call_result
.code = 408;
  elseif call_result
.disposition == 'NORMAL_TEMPORARY_FAILURE' then
    call_result
.phrase = 'User offline';
    call_result
.code = 480;
 
else
    call_result
.cause = self.caller:to_s('last_bridge_hangup_cause');
    call_result
.code = self.caller:to_i('last_bridge_proto_specific_hangup_cause');
    call_result
.phrase = self.caller:to_s('sip_hangup_phrase');
 
end

 
self.log:info('FORK EXIT - disposition: ', call_result.disposition,
   
', cause: ', call_result.cause,
   
', code: ', call_result.code,
   
', phrase: ', call_result.phrase,
   
', dial_time: ', os.time() - start_time);
 
 
return call_result;
end

-- Return call forwarding settngs
function SipCall.conditional_call_forwarding(self, cause, call_forwarding)
 
local condition_map = {USER_NOT_REGISTERED="offline", NO_ANSWER="noanswer", USER_BUSY="busy"}
 
local condition = condition_map[cause]
 
if call_forwarding and condition and call_forwarding[condition] then
    log
:debug('call forwarding on ' .. condition .. ' - destination: ' .. call_forwarding[condition].destination .. ', type: ' .. call_forwarding[condition].call_forwardable_type);
   
return call_forwarding[condition]
 
end
end

function SipCall.set_callee_variables(self, sip_account)
 
self.session:setVariable("gs_callee_account_id", sip_account.id);
 
self.session:setVariable("gs_callee_account_type", "SipAccount");
 
self.session:setVariable("gs_callee_account_owner_type", sip_account.sip_accountable_type);
 
self.session:setVariable("gs_callee_account_owner_id", sip_account.sip_accountable_id);
end
Wird die Rufgruppe nun angerufen kann mit jedem blinkenden BLF der Anruf entgegengenommen werden.

Dieses Verhalten hätte ich schon als Standard erwartet. Ist es ein Bug,  hatte ich etwas falsch konfiguriert oder ist es noch nicht geplant gewesen?
Falls es ein Bug ist, oder das ursprüngliche Verhalten so nicht vorgesehen war - was müsste man tun, damit es in eine neue Version mit einfließen kann (nachdem jemand mit Ahnung darüber geschaut hat und die Variablen umbenannt wurden)?

Gruß
Bernd

sittin...@googlemail.com

unread,
Apr 30, 2014, 9:15:54 AM4/30/14
to gs5-...@googlegroups.com
Hallo ich hab das gleiche prob und bin da auch nicht weitergekommen können sie ihre einstelung mal posten oder zuzukommen lassen

Mfg Markus
Reply all
Reply to author
Forward
0 new messages