96_SIP: fix repeat function , add auto port

git-svn-id: https://svn.fhem.de/fhem/trunk/fhem@13872 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
Wzut 2017-04-01 17:28:10 +00:00
parent ee96c023c0
commit e65f8ea649

View File

@ -54,7 +54,7 @@ use Net::Domain qw(hostname hostfqdn);
use Blocking; # http://www.fhemwiki.de/wiki/Blocking_Call use Blocking; # http://www.fhemwiki.de/wiki/Blocking_Call
#use Data::Dumper; #use Data::Dumper;
my $sip_version ="V1.5 / 31.03.17"; my $sip_version ="V1.51 / 01.04.17";
my $ua; # SIP user agent my $ua; # SIP user agent
my @fifo; my @fifo;
@ -98,7 +98,7 @@ sub SIP_Initialize($$)
"sip_listen:none,dtmf,wfp,echo ". # "sip_listen:none,dtmf,wfp,echo ". #
"sip_filter ". # "sip_filter ". #
"sip_blocking ". # "sip_blocking ". #
"sip_elbc:no,yes ". # "sip_elbc:yes,no ". #
"sip_force_interval ". # "sip_force_interval ". #
"T2S_Device ". # "T2S_Device ". #
"T2S_Timeout ". # "T2S_Timeout ". #
@ -119,13 +119,12 @@ sub SIP_Define($$)
$hash->{".reset"} = 0; $hash->{".reset"} = 0;
$attr{$name}{sip_ringtime} = '3' unless (exists($attr{$name}{sip_ringtime})); $attr{$name}{sip_ringtime} = '3' unless (exists($attr{$name}{sip_ringtime}));
$attr{$name}{sip_user} = '620' unless (exists($attr{$name}{sip_user})); $attr{$name}{sip_user} = '620' unless (exists($attr{$name}{sip_user}));
$attr{$name}{sip_port} = '5060' unless (exists($attr{$name}{sip_port}));
$attr{$name}{sip_registrar} = 'fritz.box' unless (exists($attr{$name}{sip_registrar})); $attr{$name}{sip_registrar} = 'fritz.box' unless (exists($attr{$name}{sip_registrar}));
$attr{$name}{sip_listen} = 'none' unless (exists($attr{$name}{sip_listen})); $attr{$name}{sip_listen} = 'none' unless (exists($attr{$name}{sip_listen}));
$attr{$name}{sip_dtmf_size} = '2' unless (exists($attr{$name}{sip_dtmf_size})); $attr{$name}{sip_dtmf_size} = '2' unless (exists($attr{$name}{sip_dtmf_size}));
$attr{$name}{sip_dtmf_loop} = 'once' unless (exists($attr{$name}{sip_dtmf_loop})); $attr{$name}{sip_dtmf_loop} = 'once' unless (exists($attr{$name}{sip_dtmf_loop}));
$attr{$name}{sip_dtmf_send} = 'audio' unless (exists($attr{$name}{sip_dtmf_send})); $attr{$name}{sip_dtmf_send} = 'audio' unless (exists($attr{$name}{sip_dtmf_send}));
$attr{$name}{sip_elbc} = 'no' unless (exists($attr{$name}{sip_elbc})); $attr{$name}{sip_elbc} = 'yes' unless (exists($attr{$name}{sip_elbc}));
$attr{$name}{sip_from} = 'sip:'.$attr{$name}{sip_user}.'@'.$attr{$name}{sip_registrar} unless (exists($attr{$name}{sip_from})); $attr{$name}{sip_from} = 'sip:'.$attr{$name}{sip_user}.'@'.$attr{$name}{sip_registrar} unless (exists($attr{$name}{sip_from}));
unless (exists($attr{$name}{sip_ip})) unless (exists($attr{$name}{sip_ip}))
@ -307,24 +306,23 @@ sub SIP_Register($$$)
my $name = $hash->{NAME}; my $name = $hash->{NAME};
my $logname = $name."[".$$."]"; my $logname = $name."[".$$."]";
my $ip = AttrVal($name,"sip_ip",""); my $ip = AttrVal($name,"sip_ip","");
return "missing attr sip_ip" if (!$ip); return "missing attribute sip_ip" if (!$ip);
return "this is the IP address of your registrar , not your FHEM !" if ($ip eq AttrVal($name,"sip_registrar",""));
return "invalid IP address $ip" if (($ip eq "0.0.0.0") || ($ip eq "127.0.0.1"));
my $leg = IO::Socket::INET->new( my $leg = IO::Socket::INET->new(Proto => 'udp', LocalHost => $ip, LocalPort => $port);
Proto => 'udp',
LocalHost => $ip,
LocalPort => $port);
# if port is already used try another one # if port is already used try another one
if (!$leg) if (!$leg)
{ {
Log3 $name,2,"$logname, cannot open port $port at $ip: $!"; Log3 $name,2,"$logname, cannot open port $port at $ip: $!";
$port += 10; $port += 10;
$leg = IO::Socket::INET->new( $leg = IO::Socket::INET->new(
Proto => 'udp', Proto => 'udp',
LocalHost => $ip, LocalHost => $ip,
LocalPort => $port) || return "cannot open port ".($port-10)." or $port at $ip: $!"; LocalPort => $port) || return "can't open port ".($port-10)." or $port at $ip: $!";
Log3 $name,2,"$logname, using port $port"; Log3 $name,2,"$logname, using secundary port $port with IP $ip";
} }
close($leg); close($leg);
$leg = $ip.":".$port; $leg = $ip.":".$port;
@ -351,7 +349,7 @@ sub SIP_Register($$$)
my $result = qx($cmd); my $result = qx($cmd);
if (index($result,"perl") == -1) if (index($result,"perl") == -1)
{ {
Log3 $name, 2 , $logname.", can´t find my parent ".$hash->{parent}." in process list !"; Log3 $name,1,"$logname, can´t find my parent ".$hash->{parent}." in process list !";
die; die;
} }
Log3 $name,4,"$logname, register new expire : ".localtime(time()+$expire); Log3 $name,4,"$logname, register new expire : ".localtime(time()+$expire);
@ -383,7 +381,7 @@ sub SIP_CALLStart($)
$ua = undef; $ua = undef;
my $rtp_done = 0; my $rtp_done = 0;
my $dtmf = 'ABCD*#123--4567890'; my $dtmf = 'ABCD*#123--4567890';
my $port = AttrVal($name,"sip_port","5060"); my $port = AttrVal($name,"sip_port",0);
my $delay = AttrVal($name,"sip_call_audio_delay",0); # Verzoegerung in 1/4 Sekunden Schritten my $delay = AttrVal($name,"sip_call_audio_delay",0); # Verzoegerung in 1/4 Sekunden Schritten
my $fi = 0; my $fi = 0;
#$repeat = 0 if (!$repeat); #$repeat = 0 if (!$repeat);
@ -412,6 +410,13 @@ sub SIP_CALLStart($)
$hash->{telnetPort} = SIP_telnetPort(); $hash->{telnetPort} = SIP_telnetPort();
return $name."|no telnet port without password found" if (!$hash->{telnetPort}); return $name."|no telnet port without password found" if (!$hash->{telnetPort});
if (!$port)
{
srand $$;
$port = int(rand(500)+44000);
Log3 $name,4,"$logname, using random port $port";
}
my $error = SIP_Register($hash,$port,"calling"); my $error = SIP_Register($hash,$port,"calling");
return $name."|0|CallRegister: $error" if ($error); return $name."|0|CallRegister: $error" if ($error);
@ -584,8 +589,8 @@ sub SIP_CALLDone($)
Log3 $name, 4,"$name, CALLDone -> $string"; Log3 $name, 4,"$name, CALLDone -> $string";
delete($hash->{helper}{CALL_PID}) if (defined($hash->{helper}{CALL_PID})); delete($hash->{helper}{CALL_PID}) if (defined($hash->{helper}{CALL_PID}));
delete($hash->{CPID}) if (defined($hash->{CPID})); delete($hash->{CPID}) if (defined($hash->{CPID}));
delete $hash->{lastnr} if (defined($hash->{lastnr}));
if ($error ne "1") if ($error ne "1")
{ {
@ -651,6 +656,7 @@ sub SIP_Set($@)
my $name = $hash->{NAME}; my $name = $hash->{NAME};
my $cmd = (defined($a[1])) ? $a[1] : "?"; my $cmd = (defined($a[1])) ? $a[1] : "?";
my $subcmd; my $subcmd;
my $ret;
return join(" ", sort keys %sets) if ($cmd eq "?"); return join(" ", sort keys %sets) if ($cmd eq "?");
@ -675,21 +681,19 @@ sub SIP_Set($@)
if (exists($hash->{CPID})) if (exists($hash->{CPID}))
{ {
#return "there is already a call activ for target $nr" if (defined($hash->{lastnr}) && ($hash->{lastnr} eq $nr)); return "there is already a call activ for target $nr" if (defined($hash->{lastnr}) && ($hash->{lastnr} eq $nr));
my $call = join(" ",@a); my $call = join(" ",@a);
push (@fifo,$call); push (@fifo,$call);
Log3 $name ,4,"$name, add call -> $call to fifo we will do it later"; Log3 $name ,4,"$name, add call $call to fifo so we can do it later !";
return undef; return undef;
} }
my $anz = @a; my $anz = @a;
$anz--; # letztes Element $anz--; # letztes Element
my $force = ($a[$anz] eq "&") ? 1 : 0; my $force = ($a[$anz] eq "&") ? 1 : 0;
$anz-- if ($force); # checken wir dann noch auf repeat $anz-- if ($force == 1); # checken wir dann noch auf repeat
my $repeat; my $repeat = 0;
if (substr($a[$anz],0,1) ne "*") if (substr($a[$anz],0,1) eq "*")
{ $repeat = 0; }
else
{ {
$repeat = $a[$anz]; $repeat = $a[$anz];
$repeat =~ s/^\*//; $repeat =~ s/^\*//;
@ -701,7 +705,7 @@ sub SIP_Set($@)
if (exists($hash->{LPID}) && (AttrVal($name,"sip_elbc","no") ne "no")) if (exists($hash->{LPID}) && (AttrVal($name,"sip_elbc","no") ne "no"))
{ {
Log3 $name,4,"$name, listen process $hash->{LPID} must be killed befor starting call !"; Log3 $name,4,"$name, listen process $hash->{LPID} must be killed befor we start a new call !";
BlockingKill($hash->{helper}{LISTEN_PID}); BlockingKill($hash->{helper}{LISTEN_PID});
delete $hash->{helper}{LISTEN_PID}; delete $hash->{helper}{LISTEN_PID};
delete $hash->{LPID}; delete $hash->{LPID};
@ -735,7 +739,6 @@ sub SIP_Set($@)
readingsSingleUpdate($hash,"call_state","waiting T2S",0); readingsSingleUpdate($hash,"call_state","waiting T2S",0);
Log3 $name,1,"$name :set repeat $repeat";
RemoveInternalTimer($hash); RemoveInternalTimer($hash);
# geben wir T2S mal ein paar Sekunden # geben wir T2S mal ein paar Sekunden
InternalTimer(gettimeofday()+int(AttrVal($name,"T2S_Timeout",5)), "SIP_wait_for_t2s", $hash); InternalTimer(gettimeofday()+int(AttrVal($name,"T2S_Timeout",5)), "SIP_wait_for_t2s", $hash);
@ -743,12 +746,14 @@ sub SIP_Set($@)
} }
elsif (-e $msg) elsif (-e $msg)
{ {
Log3 $name, 4, $name.", message $msg found"; Log3 $name, 4, $name.", audio file $msg found";
return "unknown message type, please use only .alaw or .ulaw" if (($msg !~ /\.al(.+)$/) && ($msg !~ /\.ul(.+)$/)); return "unknown audio type, please use only .alaw or .ulaw" if (($msg !~ /\.al(.+)$/) && ($msg !~ /\.ul(.+)$/));
} }
else else
{ {
Log3 $name, 3, $name.", message $msg NOT found !"; $ret = "audio file $msg not found";
readingsBulkUpdate($hash, "last_error",$ret);
Log3 $name, 3, "$name, $ret !";
$hash->{repeat} = 0; $hash->{repeat} = 0;
$hash->{forcecall} = 0; $hash->{forcecall} = 0;
$msg = ""; $msg = "";
@ -756,7 +761,9 @@ sub SIP_Set($@)
} }
else { Log3 $name, 4, $name.", calling $nr, ringtime: $ringtime , no message"; } else { Log3 $name, 4, $name.", calling $nr, ringtime: $ringtime , no message"; }
$hash->{lastnr} = $nr;
my $arg = "$name|$nr|$ringtime|$msg|$repeat"; # da muss force nicht mit my $arg = "$name|$nr|$ringtime|$msg|$repeat"; # da muss force nicht mit
Log3 $name, 4, "$name, $arg";
#BlockingCall($blockingFn, $arg, $finishFn, $timeout, $abortFn, $abortArg); #BlockingCall($blockingFn, $arg, $finishFn, $timeout, $abortFn, $abortArg);
$hash->{helper}{CALL_PID} = BlockingCall("SIP_CALLStart",$arg, "SIP_CALLDone") unless(exists($hash->{helper}{CALL_PID})); $hash->{helper}{CALL_PID} = BlockingCall("SIP_CALLStart",$arg, "SIP_CALLDone") unless(exists($hash->{helper}{CALL_PID}));
@ -764,8 +771,10 @@ sub SIP_Set($@)
{ {
$hash->{CPID} = $hash->{helper}{CALL_PID}{pid}; $hash->{CPID} = $hash->{helper}{CALL_PID}{pid};
$hash->{CALL} = $arg."|$force"; # hier retten wir aber force $hash->{CALL} = $arg."|$force"; # hier retten wir aber force
Log3 $name, 4, "$name, call -> ".$hash->{CALL}; Log3 $name, 4, "$name, call -> ".$hash->{CALL};
Log3 $name, 5, "$name, call has pid ".$hash->{CPID}; Log3 $name, 5, "$name, call has pid ".$hash->{CPID};
readingsBeginUpdate($hash); readingsBeginUpdate($hash);
readingsBulkUpdate($hash, "call_state","invite"); readingsBulkUpdate($hash, "call_state","invite");
readingsBulkUpdate($hash, "call",$nr); readingsBulkUpdate($hash, "call",$nr);
@ -776,33 +785,30 @@ sub SIP_Set($@)
else else
{ # das war wohl nix :( { # das war wohl nix :(
Log3 $name, 3, "$name, CALL process start failed, arg : $arg"; Log3 $name, 3, "$name, CALL process start failed, arg : $arg";
my $txt = "can't execute call number $nr as NonBlockingCall"; $ret = "can't execute call number $nr as NonBlockingCall";
readingsBeginUpdate($hash); readingsBeginUpdate($hash);
readingsBulkUpdate($hash, "last_error",$txt); readingsBulkUpdate($hash, "last_error",$ret);
readingsBulkUpdate($hash, "call_state","fail"); readingsBulkUpdate($hash, "call_state","fail");
readingsEndUpdate($hash, 1); readingsEndUpdate($hash, 1);
delete $hash->{lastnr} if (defined($hash->{lastnr})); delete $hash->{lastnr} if (defined($hash->{lastnr}));
return $txt; return $ret;
} }
} }
elsif ($cmd eq "listen") elsif ($cmd eq "listen")
{ {
my $type = AttrVal($name,"sip_listen","none"); my $type = AttrVal($name,"sip_listen","none");
return "there is already a listen process running with pid ".$hash->{LPID} if exists($hash->{LPID}); return "there is already a listen process running with pid ".$hash->{LPID} if exists($hash->{LPID});
return "please set attr sip_listen to dtmf or wfp or echo first" if (AttrVal($name,"sip_listen","none") eq "none"); return "please set attr sip_listen to dtmf or wfp or echo first" if (AttrVal($name,"sip_listen","none") eq "none");
my $error = SIP_try_listen($hash); $ret = SIP_try_listen($hash);
if ($error) if ($ret)
{ {
Log3 $name, 1, $name.", listen -> $error"; Log3 $name, 1, $name.", listen -> $ret";
readingsBeginUpdate($hash); readingsBeginUpdate($hash);
readingsBulkUpdate($hash,"state","error"); readingsBulkUpdate($hash,"state","error");
readingsBulkUpdate($hash,"last_error",$error); readingsBulkUpdate($hash,"last_error",$ret);
readingsEndUpdate($hash, 1 ); readingsEndUpdate($hash, 1 );
return $error; return $ret;
} }
#else {readingsSingleUpdate($hash, "state","listen_for_$type",1);}
return undef; return undef;
} }
elsif (($cmd eq "dtmf_event") && defined($a[2])) elsif (($cmd eq "dtmf_event") && defined($a[2]))
@ -913,8 +919,14 @@ sub SIP_ListenStart($)
return $name."|no telnet port without password found" if (!$hash->{telnetPort}); return $name."|no telnet port without password found" if (!$hash->{telnetPort});
my $port = AttrVal($name,"sip_port","5060"); my $port = AttrVal($name,"sip_port",0);
$port += 10; if (!$port)
{
srand $$;
$port = int(rand(500)+44500);
Log3 $name,4,"$logname, using random port $port";
}
else { $port += 10; }
$ua = undef; $ua = undef;
my $error = SIP_Register($hash,$port,"listen_".AttrVal($name,"sip_listen","")); my $error = SIP_Register($hash,$port,"listen_".AttrVal($name,"sip_listen",""));
return $name."|ListenRegister: $error" if ($error); return $name."|ListenRegister: $error" if ($error);
@ -1440,18 +1452,21 @@ sub SIP_wait_for_t2s($)
} }
# nun aber calling # nun aber calling
$hash->{repeat} = "*".$hash->{repeat}; my $repeat = "*".$hash->{repeat};
$hash->{forcecall} = ($hash->{forcecall}) ? "&" : "";
my @a = ($name,"call",$hash->{callnr}, $hash->{ringtime},$msg,$hash->{repeat},$hash->{forcecall}) ; my $force = ($hash->{forcecall}) ? "&" : "";
my $test = join(" ",@a); my @a;
Log3 $name ,1,"$name, Test : $test"; if ($force)
{ @a = ($name,"call",$hash->{callnr}, $hash->{ringtime},$msg,$repeat,$force) ; }
else
{ @a = ($name,"call",$hash->{callnr}, $hash->{ringtime},$msg,$repeat) ; }
delete($hash->{callnr}); delete($hash->{callnr});
delete($hash->{ringtime}); delete($hash->{ringtime});
delete($hash->{forcecall}); delete($hash->{forcecall});
delete($hash->{repeat}); delete($hash->{repeat});
my $ret = SIP_Set($hash , @a); my $ret = SIP_Set($hash , @a);
Log3 $name,3,"$name, T2S Call : $ret" if defined($ret); Log3 $name,3,"$name, error T2S Call : $ret" if defined($ret);
return undef; return undef;
} }
@ -1731,7 +1746,8 @@ sub SIP_readPassword($)
external IP address of the FHEM server. external IP address of the FHEM server.
</li> </li>
<li><a name="#sip_port">sip_port</a><br> <li><a name="#sip_port">sip_port</a><br>
Port used for sip client, defaults to 5060 and will be automatically increased by 10 if not available. Optionally portnumber used for sip client<br>
If attribute is not set a random port number between 44000 and 45000 will be used
</li> </li>
<li><a name="#sip_registrar">sip_registrar</a><br> <li><a name="#sip_registrar">sip_registrar</a><br>
Hostname or IP address of the SIP server you are connecting to, defaults to fritz.box. Hostname or IP address of the SIP server you are connecting to, defaults to fritz.box.
@ -1824,7 +1840,8 @@ sub SIP_readPassword($)
Die IP-Addresse von FHEM im Heimnetz. Solange das Attribut nicht gesetzt ist versucht das Modul diese beim Start zu ermitteln. Die IP-Addresse von FHEM im Heimnetz. Solange das Attribut nicht gesetzt ist versucht das Modul diese beim Start zu ermitteln.
</li> </li>
<li><a name="#sip_port">sip_port</a><br> <li><a name="#sip_port">sip_port</a><br>
Port der vom Modul genutzt wird. Default ist 5060 und wird automatisch um 10 erh&oml;ht wenn der Port nicht frei sein sollte. Optinale Portnummer die vom Modul benutzt wird.<br>
Wenn dem Attribut kein Wert zugewiesen wurde verwendet das Modul eine zuf&auml;llige Portnummer zwichen 44000 und 45000
</li> </li>
<li><b>Audiofiles</b> <li><b>Audiofiles</b>