96_SIP.pm 67 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091
  1. ###############################################################################
  2. #
  3. # $Id: 96_SIP.pm 15827 2018-01-08 18:36:07Z Wzut $
  4. # 96_SIP.pm
  5. # Based on FB_SIP from werner.meines@web.de
  6. #
  7. # Forum : https://forum.fhem.de/index.php/topic,67443.0.html
  8. #
  9. ###############################################################################
  10. #
  11. # (c) 2017 Copyright: Wzut & plin
  12. # All rights reserved
  13. #
  14. # This script is free software; you can redistribute it and/or modify
  15. # it under the terms of the GNU General Public License as published by
  16. # the Free Software Foundation; either version 2 of the License, or
  17. # (at your option) any later version.
  18. #
  19. # The GNU General Public License can be found at
  20. # http://www.gnu.org/copyleft/gpl.html.
  21. # A copy is found in the textfile GPL.txt and imPORTant notices to the license
  22. # from the author is found in LICENSE.txt distributed with these scripts.
  23. #
  24. # This script is distributed in the hope that it will be useful,
  25. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  26. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  27. # GNU General Public License for more details.
  28. #
  29. ##################################################################################
  30. #######################################################################
  31. # need: Net::SIP (cpan install Net::SIP)
  32. #
  33. #
  34. # convert audio to PCM 8000 :
  35. # sox <file>.wav -t raw -r 8000 -c 1 -e a-law <file>.alaw
  36. # oder
  37. # sox <file> -r 8000 -c 1 -e a-law <file>.wav
  38. #
  39. ########################################################################
  40. package main;
  41. use strict;
  42. use warnings;
  43. use POSIX qw( strftime );
  44. use Net::SIP qw//;
  45. use Net::SIP::Packet;
  46. use IO::Socket;
  47. use Socket;
  48. use Net::Domain qw(hostname hostfqdn);
  49. use Blocking; # http://www.fhemwiki.de/wiki/Blocking_Call
  50. #use Data::Dumper;
  51. my $sip_version ="V1.76 / 08.01.18";
  52. my $ua; # SIP user agent
  53. my @fifo;
  54. my %sets = (
  55. "call" => "",
  56. "listen:noArg" => "",
  57. "reject:noArg" => "",
  58. "reset:noArg" => "",
  59. "fetch:noArg" => "",
  60. "password" => ""
  61. );
  62. sub SIP_Initialize($$)
  63. {
  64. my ($hash) = @_;
  65. $hash->{DefFn} = "SIP_Define";
  66. $hash->{UndefFn} = "SIP_Undef";
  67. $hash->{ShutdownFn} = "SIP_Undef";
  68. $hash->{SetFn} = "SIP_Set";
  69. #$hash->{GetFn} = "SIP_Get";
  70. $hash->{NotifyFn} = "SIP_Notify";
  71. $hash->{AttrFn} = "SIP_Attr";
  72. $hash->{AttrList} = "sip_watch_listen ". #
  73. "sip_ringtime ". #
  74. "sip_waittime ". #
  75. "sip_ip ". #
  76. "sip_port ". #
  77. "sip_user ". #
  78. "sip_registrar ". #
  79. "sip_from ". #
  80. "sip_call_audio_delay:0,0.25,0.5,0.75,1,1.25,1.5,1.75,2,2.25,2.5,2.75,3 ". #
  81. "sip_audiofile_call ". #
  82. "sip_audiofile_dtmf ". #
  83. "sip_audiofile_ok ". #
  84. "sip_audiofile_wfp ". # CE
  85. "sip_dtmf_size:1,2,3,4 ". #
  86. "sip_dtmf_send:audio,rfc2833 ". #
  87. "sip_dtmf_loop:once,loop ". #
  88. "sip_listen:none,dtmf,wfp,echo ". #
  89. "sip_filter ". #
  90. "sip_blocking ". #
  91. "sip_elbc:yes,no ". #
  92. "sip_force_interval ". #
  93. "sip_force_max ". #
  94. "T2S_Device ". #
  95. "T2S_Timeout ". #
  96. "audio_converter:sox,ffmpeg ". #
  97. "disabled:0,1 ".$readingFnAttributes;
  98. }
  99. sub SIP_Define($$)
  100. {
  101. my ($hash, $def) = @_;
  102. my @a = split("[ \t][ \t]*", $def);
  103. my $name = shift @a;
  104. my $addr = "0.0.0.0";
  105. $hash->{STATE} = "defined";
  106. $hash->{VERSION} = $sip_version;
  107. $hash->{NOTIFYDEV} = "global";
  108. $hash->{".reset"} = 0;
  109. $attr{$name}{sip_ringtime} = '3' unless (exists($attr{$name}{sip_ringtime}));
  110. $attr{$name}{sip_user} = '620' unless (exists($attr{$name}{sip_user}));
  111. $attr{$name}{sip_registrar} = 'fritz.box' unless (exists($attr{$name}{sip_registrar}));
  112. $attr{$name}{sip_listen} = 'none' unless (exists($attr{$name}{sip_listen}));
  113. $attr{$name}{sip_dtmf_size} = '2' unless (exists($attr{$name}{sip_dtmf_size}));
  114. $attr{$name}{sip_dtmf_loop} = 'once' unless (exists($attr{$name}{sip_dtmf_loop}));
  115. $attr{$name}{sip_dtmf_send} = 'audio' unless (exists($attr{$name}{sip_dtmf_send}));
  116. $attr{$name}{sip_elbc} = 'yes' unless (exists($attr{$name}{sip_elbc}));
  117. $attr{$name}{sip_from} = 'sip:'.$attr{$name}{sip_user}.'@'.$attr{$name}{sip_registrar} unless (exists($attr{$name}{sip_from}));
  118. unless (exists($attr{$name}{sip_ip}))
  119. {
  120. eval { $addr = inet_ntoa(scalar(gethostbyname(hostfqdn()))); };
  121. if ($@)
  122. {
  123. Log3 $name,2,"$name, please check your FQDN hostname -> $@";
  124. eval { $addr = inet_ntoa(scalar(gethostbyname(hostname()))); };
  125. Log3 $name,2,"$name, please check your hostname -> ".$@ if ($@);
  126. }
  127. $attr{$name}{sip_ip} = $addr;
  128. }
  129. RemoveInternalTimer($hash);
  130. InternalTimer(gettimeofday()+5, "SIP_updateConfig", $hash);
  131. return undef;
  132. }
  133. sub SIP_Notify($$)
  134. {
  135. # $hash is my hash, $dev_hash is the hash of the changed device
  136. my ($hash, $dev_hash) = @_;
  137. my $events = deviceEvents($dev_hash,0);
  138. return undef if ($dev_hash->{NAME} ne AttrVal($hash->{NAME},"T2S_Device",""));
  139. my $val = ReadingsVal($dev_hash->{NAME},"lastFilename","");
  140. return undef if ((!$val) || (index(@{$events}[0],"lastFilename") == -1));
  141. if (defined($hash->{audio1}) ||
  142. defined($hash->{audio2}) ||
  143. defined($hash->{audio3}) ||
  144. (defined($hash->{callnr}) && defined($hash->{ringtime})))
  145. { SIP_wait_for_t2s($hash);}
  146. return undef;
  147. }
  148. sub SIP_Attr (@)
  149. {
  150. my ($cmd, $name, $attrName, $attrVal) = @_;
  151. my $hash = $defs{$name};
  152. if ($cmd eq "set")
  153. {
  154. if (substr($attrName ,0,4) eq "sip_")
  155. {
  156. $_[3] = $attrVal;
  157. $hash->{".reset"} = 1 if defined($hash->{LPID});
  158. }
  159. elsif (($attrName eq "disable") && ($attrVal == 1))
  160. {
  161. readingsSingleUpdate($hash,"state","disabled",1);
  162. $_[3] = $attrVal;
  163. $hash->{".reset"} = 1 if defined($hash->{LPID});
  164. }
  165. elsif ($attrName eq "audio_converter")
  166. {
  167. my $res = qx(which $attrVal);
  168. $res =~ s/\n//;
  169. $hash->{AC} = ($res) ? $res : undef;
  170. }
  171. elsif ($attrName eq "T2S_Device")
  172. {
  173. $_[3] = $attrVal;
  174. $hash->{NOTIFYDEV} = $attrVal;
  175. }
  176. }
  177. elsif ($cmd eq "del")
  178. {
  179. if (substr($attrName,0,4) eq "sip_")
  180. {
  181. $_[3] = $attrVal;
  182. $hash->{".reset"} = 1 if defined($hash->{LPID});
  183. }
  184. elsif ($attrName eq "audio_converter")
  185. {
  186. $_[3] = $attrVal;
  187. delete $hash->{AC};
  188. }
  189. elsif ($attrName eq "T2S_Device")
  190. {
  191. $_[3] = $attrVal;
  192. delete $hash->{NOTIFYDEV};
  193. }
  194. }
  195. if ($hash->{".reset"})
  196. {
  197. Log3 $name,5,"$name , SIP_Attr : reset";
  198. InternalTimer(gettimeofday()+1,"SIP_updateConfig",$hash);
  199. }
  200. return undef;
  201. }
  202. sub SIP_updateConfig($)
  203. {
  204. # this routine is called 5 sec after the last define of a restart
  205. # this gives FHEM sufficient time to fill in attributes
  206. my ($hash) = @_;
  207. my $name = $hash->{NAME};
  208. my $error;
  209. if (!$init_done)
  210. {
  211. RemoveInternalTimer($hash);
  212. InternalTimer(gettimeofday()+5,"SIP_updateConfig", $hash);
  213. return;
  214. }
  215. ## kommen wir via reset Kommando ?
  216. if ($hash->{".reset"})
  217. {
  218. $hash->{".reset"} = 0;
  219. RemoveInternalTimer($hash);
  220. if(defined($hash->{LPID}))
  221. {
  222. Log3 $name,4, "$name, Listen Kill PID : ".$hash->{LPID};
  223. BlockingKill($hash->{helper}{LISTEN_PID});
  224. delete $hash->{helper}{LISTEN_PID};
  225. delete $hash->{LPID};
  226. readingsSingleUpdate($hash,"listen_alive","no",1);
  227. Log3 $name,4,"$name, Reset Listen done";
  228. }
  229. if(defined($hash->{CPID}))
  230. {
  231. Log3 $name,4, "$name, CALL Kill PID : ".$hash->{CPID};
  232. BlockingKill($hash->{helper}{CALL_PID});
  233. delete $hash->{helper}{CALL_PID};
  234. delete $hash->{CPID};
  235. Log3 $name,4,"$name, Reset Call done";
  236. }
  237. }
  238. if (IsDisabled($name))
  239. {
  240. readingsSingleUpdate($hash,"state","disabled",1);
  241. return undef;
  242. }
  243. my $t2s = AttrVal($name,"T2S_Device",undef);
  244. $hash->{NOTIFYDEV} = $t2s if defined($t2s);
  245. if (AttrVal($name,"audio_converter","") && defined($t2s))
  246. {
  247. my $converter = AttrVal($name,"audio_converter","");
  248. my $res = qx(which $converter);
  249. $res =~ s/\n//;
  250. $hash->{AC} = ($res) ? $res : undef;
  251. }
  252. if (AttrVal($name,"sip_listen", "none") ne "none")
  253. {
  254. $error = SIP_try_listen($hash);
  255. if ($error)
  256. {
  257. Log3 $name, 1, $name.", listen -> $error";
  258. readingsBeginUpdate($hash);
  259. readingsBulkUpdate($hash,"state","error");
  260. readingsBulkUpdate($hash,"last_error",$error);
  261. readingsBulkUpdate($hash,"listen_alive","no");
  262. readingsEndUpdate($hash, 1 );
  263. return undef;
  264. }
  265. }
  266. else
  267. {
  268. readingsBeginUpdate($hash);
  269. readingsBulkUpdate($hash,"state","initialized");
  270. readingsBulkUpdate($hash,"listen_alive","no");
  271. readingsEndUpdate($hash, 1 );
  272. }
  273. return undef;
  274. }
  275. sub SIP_Register($$)
  276. {
  277. my ($hash,$type) = @_;
  278. my $name = $hash->{NAME};
  279. $hash->{LPID} = $$;
  280. my $logname = $name."[".$hash->{LPID}."]";
  281. my $ip = AttrVal($name,"sip_ip","");
  282. my $port = int(AttrVal($name,"sip_port",0));
  283. my $leg;
  284. return "missing attribute sip_ip" if (!$ip);
  285. return "this is the IP address of your registrar , not your FHEM !" if ($ip eq AttrVal($name,"sip_registrar",""));
  286. return "invalid IP address $ip" if (($ip eq "0.0.0.0") || ($ip eq "127.0.0.1"));
  287. if ($port)
  288. {
  289. $port +=10 if ($type eq "calling");
  290. Log3 $name,4,"$logname, trying to use port $port";
  291. $leg = IO::Socket::INET->new(Proto => 'udp', LocalHost => $ip, LocalPort => $port);
  292. # if port is already used try another one
  293. if (!$leg)
  294. {
  295. Log3 $name,1,"$logname, cannot open port $port at $ip : ".$!;
  296. $port += 10;
  297. $leg = IO::Socket::INET->new(Proto => 'udp', LocalHost => $ip, LocalPort => $port) || return "can't open port $port at $ip : ".$!;
  298. Log3 $name,2,"$logname, using secundary port $port with IP $ip";
  299. }
  300. close($leg);
  301. $leg = $ip.":".$port;
  302. }
  303. else
  304. {
  305. $leg = $ip;
  306. Log3 $name,4,"$logname, using Leg.pm to find a free port";
  307. }
  308. my $registrar = AttrVal($name,"sip_registrar","fritz.box");
  309. my $user = AttrVal($name,"sip_user","620");
  310. my $from = AttrVal($name,"sip_from","sip:".$user."@".$registrar);
  311. # create new agent
  312. $ua = Net::SIP::Simple->new(
  313. registrar => $registrar,
  314. domain => $registrar,
  315. leg => $leg,
  316. from => $from,
  317. auth => [ $user , SIP_readPassword($name) ]);
  318. # Register agent
  319. # optional registration
  320. my $sub_register;
  321. $sub_register = sub
  322. {
  323. my $expire = $ua->register(registrar => $registrar ) || return "registration failed: ".$ua->error;
  324. my $cmd = "ps -e | grep '".$hash->{parent}." '";
  325. my $result = qx($cmd);
  326. if (index($result,"perl") == -1)
  327. {
  328. Log3 $name,1,"$logname, can´t find my parent ".$hash->{parent}." in process list !";
  329. die;
  330. }
  331. Log3 $name,4,"$logname, register new expire : ".FmtDateTime(time()+$expire);
  332. if (AttrVal($name,"sip_listen","none") ne "none")
  333. {
  334. BlockingInformParent("SIP_rBU", [$name,"state:$type|listen_alive:".$hash->{LPID}."|expire:$expire"],0);
  335. }
  336. else
  337. {
  338. BlockingInformParent("SIP_rSU", [$name, "state:$type"], 0);
  339. }
  340. # need to refresh registration periodically
  341. $ua->add_timer( $expire/2, $sub_register );
  342. };
  343. $sub_register->();
  344. if($ua->register) # returned expires time or undef if failed
  345. {
  346. #Log3 $name,4,Dumper($ua);
  347. return 0;
  348. }
  349. my $ret = ($ua->error) ? $ua->error : "registration error";
  350. return $ret;
  351. }
  352. sub SIP_CALLStart($)
  353. {
  354. my ($arg) = @_;
  355. return unless(defined($arg));
  356. my ($name,$nr,$ringtime,$msg,$repeat) = split("\\|",$arg);
  357. my $hash = $defs{$name};
  358. my $logname = $name."[".$$."]";
  359. $ua = undef;
  360. my $rtp_done = 0;
  361. my $dtmf = 'ABCD*#123--4567890';
  362. my $delay = AttrVal($name,"sip_call_audio_delay",0); # Verzoegerung in 1/4 Sekunden Schritten
  363. my $w = ($delay) ? -1 : 0;
  364. my $fi = 0;
  365. #$repeat = 0 if (!$repeat);
  366. my $packets = int($delay*50);
  367. my $timeout = 0;
  368. my $final;
  369. my $peer_hangup;
  370. my $peer_hangup2;
  371. my $stopvar;
  372. my $state;
  373. my $no_answer;
  374. my $call;
  375. my $codec;
  376. my $call_established = 0;
  377. my @files;
  378. my $anz;
  379. my $stat;
  380. my $ph_ok = 0;
  381. my $sound_of_silence = sub
  382. {
  383. return unless $packets-- > 0;
  384. return chr(0) x 160; # 160 bytes for PCMU/8000 = 1/50 Sekunde Sound
  385. };
  386. $hash->{parent} = getppid();
  387. Log3 $name,4,"$logname, my parent is ".$hash->{parent};
  388. my $error = SIP_Register($hash,"calling");
  389. return $name."|0|CallRegister: $error" if ($error);
  390. if ((substr($msg,0,1) ne "-") && $msg)
  391. {
  392. $codec = "PCMA/8000" if ($msg =~ /\.al(.+)$/);
  393. $codec = "PCMU/8000" if ($msg =~ /\.ul(.+)$/);
  394. return $name."|0|CallStart: please use filetype .alaw (for a-law) or .ulaw (for u-law)" if !defined($codec);
  395. push @files,$sound_of_silence if ($delay);
  396. if ($repeat < 0) { $repeat = $repeat * -1; $ph_ok= 1; }
  397. for(my $i=0; $i<=$repeat; $i++) { push @files,$msg; }
  398. $anz = @files;
  399. Log3 $name,4,"$logname, CallStart with $anz files - first file : $files[0] - $codec , repeat $repeat";
  400. $call = $ua->invite( $nr,
  401. init_media => $ua->rtp('send_recv', $files[0]),
  402. cb_rtp_done => \$rtp_done,
  403. cb_final => sub { my ($status,$self,%info) = @_;
  404. $final = $info{code};
  405. $stat = $status;
  406. Log3 $name,4,"$logname, cb_final - status : $status" if (!defined($final));
  407. Log3 $name,4,"$logname, cb_final - status : $status - final : $final" if (defined($final));
  408. if (($status eq "FAIL") && defined($final))
  409. {
  410. if (int($final) == 481) { BlockingInformParent("SIP_rSU", [$name, "call_state:ringing"], 0);} # bis Net::SIP 0.808
  411. elsif (int($final) == 486) { $fi=1; } # canceled
  412. elsif (int($final) == 603) { $fi=1; } # declined - ab Net::SIP 0.812
  413. }
  414. elsif (($status eq "OK") && !defined($final) && !$call_established) # der Angrufene hat abgenommen
  415. {
  416. Log3 $name,4, $logname.", call established";
  417. BlockingInformParent("SIP_rSU", [$name, "call_state:established"], 0);
  418. $call_established++; # nur 1x , bei mehr als einem File kommen wir ofters hier vorbei
  419. }
  420. },
  421. recv_bye => \$peer_hangup,
  422. #ring_time => 5,
  423. #cb_noanswer => \$no_answer, klappt hier nicht wir gehen ueber add_timer
  424. rtp_param => [8, 160, 160/8000, $codec]) || return $name."|0|invite failed: ".$ua->error;
  425. }
  426. else
  427. {
  428. $dtmf = (substr($msg,0,1) eq "-") ? substr($msg,1) : $dtmf;
  429. Log3 $name,4,"$logname, CallStart DTMF : $dtmf";
  430. $delay = 0; # wenn delay sein muss dann ueber DTMF ----
  431. $repeat = 0; # keine Wiederholungen
  432. $call = $ua->invite($nr,
  433. init_media => $ua->rtp( 'recv_echo',undef,0 ),
  434. rtp_param => [0, 160, 160/8000, 'PCMU/8000'],
  435. cb_final => sub { my ($status,$self,%info) = @_;
  436. $final = $info{code};
  437. Log3 $name,4,"$logname, cb_final - Status : $status" if (!defined($final));
  438. Log3 $name,4,"$logname, cb_final - status : $status - final : $final" if (defined($final));
  439. if (($status eq "FAIL") && defined($final))
  440. {
  441. if (int($final) == 481) { BlockingInformParent("SIP_rSU", [$name, "call_state:ringing"], 0); } # bis Net::SIP 0.808
  442. elsif (int($final) == 486) { $fi=1; } # canceled
  443. elsif (int($final) == 603) { $fi=1; } # declined - ab Net::SIP 0.812
  444. }
  445. elsif (($status eq "OK") && !defined($final)) # der Angrufene hat abgenommen
  446. {
  447. Log3 $name,4, $logname.", call established";
  448. BlockingInformParent("SIP_rSU", [$name, "call_state:established"], 0);
  449. $call_established = 1; # setzen für die spätere Entscheidung bye oder cancel
  450. }
  451. },
  452. #cb_noanswer => \$no_answer,
  453. #ring_time => 5, siehe oben -> add_timer
  454. cb_cleanup => sub {0},
  455. recv_bye => \$peer_hangup) || return $name."|0|invite failed ".$ua->error;
  456. if (AttrVal($name,"sip_dtmf_send","audio") eq "audio")
  457. { $call->dtmf( $dtmf, methods => 'audio', duration => 500, cb_final => \$rtp_done); }
  458. else { $call->dtmf( $dtmf, cb_final => \$rtp_done); }
  459. }
  460. return "$name|0|invite call failed ".$call->error if ($call->error);
  461. Log3 $name,4,"$logname, calling : $nr";
  462. BlockingInformParent("SIP_rSU", [$name, "call_state:calling $nr"], 0);
  463. #return "$name|1|no answer" if ($no_answer);
  464. $ua->add_timer($ringtime,\$stopvar);
  465. $ua->loop( \$stopvar,\$peer_hangup,\$rtp_done,\$fi );
  466. $timeout = 1 if defined($stopvar); # hat der bereits zugeschlagen ?
  467. Log3 $name,5,"$logname, 0. Ende des ersten Loops";
  468. Log3 $name,5,"$logname, 1. rtp_done : $rtp_done" if defined($rtp_done);
  469. Log3 $name,5,"$logname, 2. fi : $fi" if defined($fi);
  470. Log3 $name,5,"$logname, 3. Final : $final" if defined($final);
  471. Log3 $name,5,"$logname, 4. timeout : ".$timeout;
  472. Log3 $name,5,"$logname, 5. peer_hangup : $peer_hangup" if defined($peer_hangup);
  473. Log3 $name,5,"$logname, 6. call_established : ".$call_established;
  474. Log3 $name,5,"$logname, 7. no_answer : $no_answer" if defined($no_answer);
  475. # Lebt der Call noch und gibt es ueberhaupt etwas zum wiederholen ?
  476. while ( !$peer_hangup && !$peer_hangup2 && !$fi && !$stopvar && $msg && ($anz > 1))
  477. {
  478. shift(@files); # done with file
  479. @files || last; # raus hier sobald kein File mehr da ist
  480. Log3 $name,4,"$logname, next file : $files[0]" if defined($files[0]);
  481. Log3 $name,3,"$logname, opps no file" if !defined($files[0]);
  482. # re-invite on current call for next file
  483. $rtp_done = undef; # wichtig ! u.U. haengen wir hier fest wenn der Anrufer jetzt auflegt
  484. select(undef, undef, undef, 0.1); # minimale pause
  485. $call->reinvite(
  486. init_media => $ua->rtp('send_recv', $files[0]),
  487. #rtp_param => [0, 160, 160/8000, 'PCMU/8000'], unebeding weglassen ! fuehrt zu Verzerrungen bei der Wiedergabe
  488. cb_rtp_done => \$rtp_done,
  489. recv_bye => \$peer_hangup2, # FIXME: do we need to repeat this? Wzut : I think so ...
  490. ) || return $name."|0|reinvite failed: ".$ua->error;
  491. $ua->loop( \$rtp_done,\$peer_hangup2,\$peer_hangup,\$stopvar );
  492. Log3 $name,4,"$logname, loop rtp_done : $rtp_done" if defined($rtp_done);
  493. $w++;
  494. }
  495. $timeout = 1 if defined($stopvar); # nach eventuellen reinvte nochmal testen
  496. # timeout or dtmf done, hang up
  497. if ( $timeout || $rtp_done)
  498. {
  499. $stopvar = undef;
  500. if ($timeout && !$call_established)
  501. {
  502. Log3 $name,5,"$logname, call->cancel";
  503. $call->cancel( cb_final => \$stopvar );
  504. }
  505. else
  506. {
  507. Log3 $name,5,"$logname, call->bye";
  508. $call->bye( cb_final => \$stopvar );
  509. }
  510. $ua->loop( \$stopvar );
  511. }
  512. Log3 $name,5,"$logname, RTP done : $rtp_done" if defined($rtp_done);
  513. Log3 $name,5,"$logname, Hangup : $peer_hangup" if defined($peer_hangup);
  514. Log3 $name,5,"$logname, Hangup2 : $peer_hangup2" if defined($peer_hangup2);
  515. Log3 $name,5,"$logname, Timeout : $timeout";
  516. Log3 $name,5,"$logname, Final : $final" if defined($final);
  517. Log3 $name,5,"$logname, while : $w" if defined($w);
  518. Log3 $name,5,"$logname, Status : $stat" if defined($stat);
  519. if (defined($rtp_done))
  520. {
  521. if ($rtp_done eq "OK") {return $name."|1|ok";} # kein Audio
  522. else
  523. {
  524. if (defined($final))
  525. {
  526. my $txt;
  527. $txt = "canceled" if (int($final) == 486);
  528. $txt = "no answer" if (int($final) == 487);
  529. $txt = "declined" if (int($final) == 603);
  530. return $name."|1|$txt" if $txt;
  531. }
  532. else {return $name."|1|ok" if ($rtp_done !=0);}
  533. }
  534. }
  535. # immer noch kein richtiger Text zur Rueckgabe ?
  536. $final = "unknown" if (!defined($final) && !$timeout);
  537. $final = "timeout" if (!defined($final) && $timeout);
  538. $final = "peer hangup" if defined($peer_hangup);
  539. $final = "peer_hangup" if defined($peer_hangup2); # ts,ts hat der doch glatt im reinvite noch abgebochen
  540. # geben wir doch ok zurueck wenn er sich die Nachricht min 1x angehört hat
  541. return $name."|1|ok peer hangup" if ($ph_ok && defined($peer_hangup2) && ($stat eq "OK") && ($w>0)); # bei delay 1x mehr !
  542. return $name."|1|".$final;
  543. }
  544. sub SIP_CALLDone($)
  545. {
  546. my ($string) = @_;
  547. return unless(defined($string));
  548. my @r = split("\\|",$string);
  549. my $hash = $defs{$r[0]};
  550. my $error = (defined($r[1])) ? $r[1] : "0";
  551. my $final = (defined($r[2])) ? $r[2] : "???";
  552. my $name = $hash->{NAME};
  553. my $success = (substr($final,0,2) eq "ok") ? 1 : 0;
  554. my $calltime = 0;
  555. my (undef,$nr,$ringtime,$msg,$repeat,$force) = split("\\|",$hash->{CALL}); # zerlegen wir den Original Call
  556. my @a;
  557. my @fo = (300,0,0);
  558. Log3 $name, 4,"$name, CALLDone -> $string";
  559. delete($hash->{helper}{CALL_PID}) if (defined($hash->{helper}{CALL_PID}));
  560. delete($hash->{CPID}) if (defined($hash->{CPID}));
  561. delete $hash->{lastnr} if (defined($hash->{lastnr}));
  562. if (defined($hash->{helper}{CALL_START}))
  563. {
  564. $calltime = time() - $hash->{helper}{CALL_START};
  565. delete($hash->{helper}{CALL_START});
  566. }
  567. if ($force)
  568. {
  569. $force =~ s/^\&//;
  570. @fo = split(",",$force);
  571. $fo[2]++ if(!$success); # Anzahl bisheriger Durchläufe
  572. }
  573. if ($error ne "1")
  574. {
  575. readingsBeginUpdate($hash);
  576. readingsBulkUpdate($hash, "call","done");
  577. readingsBulkUpdate($hash, "call_time",int($calltime)) if defined($calltime);
  578. readingsBulkUpdate($hash, "last_error",$final);
  579. readingsBulkUpdate($hash, "call_state","fail");
  580. readingsBulkUpdate($hash, "call_success","0");
  581. readingsBulkUpdate($hash, "call_attempt",$fo[2]) if ($force);
  582. readingsBulkUpdate($hash, "call_attempt","0") if (!$force);
  583. readingsBulkUpdate($hash, "state",$hash->{'.oldstate'}) if defined($hash->{'.oldstate'});
  584. readingsEndUpdate($hash, 1);
  585. }
  586. else
  587. {
  588. readingsBeginUpdate($hash);
  589. readingsBulkUpdate($hash, "call","done");
  590. readingsBulkUpdate($hash, "call_state",lc($final));
  591. readingsBulkUpdate($hash, "call_success",$success);
  592. readingsBulkUpdate($hash, "call_time",int($calltime)) if defined($calltime);
  593. readingsBulkUpdate($hash, "state",$hash->{'.oldstate'}) if defined($hash->{'.oldstate'});
  594. readingsBulkUpdate($hash, "call_attempt",$fo[2]) if ($force);
  595. readingsBulkUpdate($hash, "call_attempt","0") if (!$force);
  596. readingsEndUpdate($hash, 1);
  597. }
  598. if ($force && !$success)
  599. {
  600. $repeat++; $repeat--;
  601. my $nr2 = $nr;
  602. $nr2 =~ tr/0-9//cd;
  603. $nr2 .= "_";
  604. $nr2 .= unpack ("%16C*",$msg);
  605. if ($fo[2] < $fo[1]) # bisherige Anzahl kleiner max Wiederholungen ?
  606. {
  607. $force = "&".join(",", @fo);
  608. my $time_s = strftime("\%H:\%M:\%S", gmtime($fo[0]));
  609. $error = CommandDefine(undef, "at_forcecall_".$nr2." at +".$time_s." set $name call $nr $ringtime $msg *".$repeat." ".$force);
  610. if (!$error) { $attr{"at_forcecall_".$nr2}{room} = AttrVal($name,"room","Unsorted"); }
  611. else { Log3 $name,2,"$name, $error"; }
  612. Log3 $name,4,"$name, at_forcecall_".$nr2." at +".$time_s." set $name call $nr $ringtime $msg *".$repeat." ".$force;
  613. }
  614. else
  615. {
  616. Log3 $name,3,"$name, at_forcecall_".$nr2." max count $fo[1] reached giving up !";
  617. }
  618. } ### end force and !$success
  619. my $nextcall = shift @fifo; # sind da noch Calls in der Queue ?
  620. if ($nextcall)
  621. {
  622. @a = split(" ",$nextcall);
  623. $error = SIP_Set($hash,@a);
  624. Log3 $name,3,"$name, error setting nextcall $nextcall -> $error" if ($error);
  625. return undef;
  626. } else { Log3 $name,5,"$name, fifo is empty"; }
  627. if (exists($hash->{'.elbc'}))
  628. {
  629. @a = (undef,"listen");
  630. Log3 $name,4,"$name, try restarting listen process after call ends";
  631. $error = SIP_Set($hash,@a);
  632. Log3 $name,3,"$name, error restarting listen -> $error" if ($error);
  633. delete $hash->{'.elbc'};
  634. } else { Log3 $name,5,"$name, no elbc"; }
  635. delete $hash->{CALL};
  636. return undef;
  637. }
  638. #####################################
  639. sub SIP_Set($@)
  640. {
  641. my ($hash, @a) = @_;
  642. my $name = $hash->{NAME};
  643. my $cmd = (defined($a[1])) ? $a[1] : "?";
  644. my $subcmd;
  645. my $error;
  646. return join(" ", sort keys %sets) if ($cmd eq "?");
  647. if (($cmd eq "call") || ($cmd eq "listen"))
  648. {
  649. my $pwd = SIP_readPassword($name);
  650. unless (defined $pwd)
  651. {
  652. $error = "Error: no SIP user password set. Please define it with 'set $name password Your_SIP_User_Password'";
  653. Log3 $name,2,"$name, $error";
  654. return $error;
  655. }
  656. }
  657. if ($cmd eq "call")
  658. {
  659. my $nr = (defined($a[2])) ? $a[2] : "";
  660. my $ringtime = (defined($a[3])) ? $a[3] : 30;
  661. my $msg = (defined($a[4])) ? $a[4] : AttrVal($name, "sip_audiofile_call", "");
  662. return "missing target call number" if (!$nr);
  663. return "invalid max time : $ringtime" unless $ringtime =~ m/^\d+$/;
  664. if (exists($hash->{CPID}))
  665. {
  666. return "there is already a call activ for target $nr" if (defined($hash->{lastnr}) && ($hash->{lastnr} eq $nr));
  667. my $call = join(" ",@a);
  668. push (@fifo,$call);
  669. Log3 $name ,4,"$name, add call $call to fifo so we can do it later !";
  670. return undef;
  671. }
  672. my $anz = @a;
  673. $anz--; # letztes Element
  674. my $force = (substr($a[$anz],0,1) eq "&") ? $a[$anz] : 0;
  675. if ($force)
  676. {
  677. Log3 $name,3,"$name, force call $force";
  678. $force =~ s/^\&//;
  679. my @fo = split(",", $force);
  680. $fo[0] = int(AttrVal($name,"sip_force_interval",300)) if (!$fo[0]);
  681. $fo[1] = int(AttrVal($name,"sip_force_max",99)) if (!$fo[1]);
  682. $fo[2] = 0 if (!$fo[2]);
  683. $force = "&".join("," , @fo);
  684. $anz--; # checken wir dann noch auf repeat
  685. }
  686. my $repeat = 0;
  687. if ((substr($a[$anz],0,1) eq "*") && ($anz > 3))
  688. {
  689. $repeat = $a[$anz];
  690. $repeat =~ s/^\*//;
  691. $repeat ++; $repeat --;
  692. } # * weg , Rest als Int
  693. Log3 $name,4,"$name, msg will be repeat $repeat times" if ($repeat);
  694. if (exists($hash->{LPID}) && (AttrVal($name,"sip_elbc","no") eq "yes"))
  695. {
  696. Log3 $name,4,"$name, listen process ".$hash->{LPID}." must be killed befor we start a new call !";
  697. BlockingKill($hash->{helper}{LISTEN_PID});
  698. delete $hash->{helper}{LISTEN_PID};
  699. delete $hash->{LPID};
  700. readingsSingleUpdate($hash,"listen_alive","no",1);
  701. $hash->{'.elbc'} = 1; # haben wir gerade einen listen Prozess abgeschossen ?
  702. }
  703. if ($msg)
  704. {
  705. if (substr($msg,0,1) eq "-")
  706. {
  707. Log3 $name, 4, $name.", message DTMF = $msg";
  708. }
  709. elsif (substr($msg,0,1) eq "!") # Text2Speech Text ?
  710. {
  711. if ($msg eq AttrVal($name,"sip_audiofile_call", ""))
  712. {
  713. @a = split(" ",AttrVal($name,"sip_audiofile_call", ""));
  714. unshift (@a, ('t2s_name','tts')); # zwei Platzhalter einfügen , Text beginnt jetzt in $a[2]
  715. }
  716. else
  717. {
  718. shift @a;
  719. shift @a;
  720. pop @a if ($force); # das & muss ggf. auch noch weg
  721. pop @a if ($repeat); # das * muss ggf. auch weg
  722. $a[0] = "t2s_name";
  723. $a[1] = "tts"; # Kommando des Set Befehls
  724. }
  725. $a[2] =~ s/^\!//; # das ! muss weg
  726. if (!$a[2]) # ist denn jetzt noch etwas übrig geblieben ?
  727. {
  728. Log3 $name,4,"name, no valid text found in message : $msg";
  729. return "No message text after [!] found";
  730. }
  731. # gibt es denn Text schon als mp3 ?
  732. my $filename = SIP_check_T2S_File($hash,@a);
  733. if($filename)
  734. {
  735. $cmd = "$name call $nr $ringtime $filename";
  736. $cmd .= " *".$repeat if ($repeat);
  737. $cmd .= " ".$force if ($force);
  738. Log3 $name,5,"$name, set call new -> $cmd";
  739. return CommandSet(undef,$cmd);
  740. }
  741. # die nächsten vier brauchen wir unbedingt fuer T2S
  742. $hash->{callnr} = $nr;
  743. $hash->{ringtime} = $ringtime;
  744. $hash->{forcecall} = $force;
  745. $hash->{repeat} = $repeat;
  746. $error = SIP_create_T2S_File($hash,@a); # na dann lege schon mal los
  747. return $error if defined($error); # Das ging leider schief
  748. readingsSingleUpdate($hash,"call_state","waiting T2S",1);
  749. RemoveInternalTimer($hash);
  750. # geben wir T2S mal ein paar Sekunden
  751. InternalTimer(gettimeofday()+int(AttrVal($name,"T2S_Timeout",5)), "SIP_wait_for_t2s", $hash);
  752. return undef;
  753. }
  754. elsif (-e $msg)
  755. {
  756. Log3 $name, 4, $name.", audio file $msg found";
  757. $error = SIP_MP3_conv($hash,$msg,$name) if ($msg =~/\.mp3$/);
  758. if (!$error)
  759. {
  760. $msg =~ s/mp3/alaw/;
  761. $error = "unknown audio type, please use only .alaw , .ulaw or .mp3" if (($msg !~ /\.al(.+)$/) && ($msg !~ /\.ul(.+)$/));
  762. $error = "audio file $msg not found" if(!-e $msg);
  763. }
  764. }
  765. else
  766. {
  767. $error = "audio file $msg not found";
  768. }
  769. if ($error)
  770. {
  771. readingsSingleUpdate($hash, "last_error",$error,1);
  772. Log3 $name, 3, "$name, $error !";
  773. $hash->{repeat} = 0;
  774. $hash->{forcecall} = 0;
  775. return $error;
  776. }
  777. }
  778. else { Log3 $name, 4, $name.", calling $nr, ringtime: $ringtime , no message"; }
  779. $hash->{lastnr} = $nr;
  780. my $arg = "$name|$nr|$ringtime|$msg|$repeat"; # da muss force nicht mit
  781. Log3 $name, 4, "$name, $arg";
  782. #BlockingCall($blockingFn, $arg, $finishFn, $timeout, $abortFn, $abortArg);
  783. $hash->{helper}{CALL_PID} = BlockingCall("SIP_CALLStart",$arg, "SIP_CALLDone") unless(exists($hash->{helper}{CALL_PID}));
  784. if($hash->{helper}{CALL_PID})
  785. {
  786. $hash->{CPID} = $hash->{helper}{CALL_PID}{pid};
  787. $hash->{CALL} = $arg."|$force"; # hier retten wir aber force
  788. Log3 $name, 4, "$name, call -> ".$hash->{CALL};
  789. Log3 $name, 5, "$name, call has pid ".$hash->{CPID};
  790. $hash->{helper}{CALL_START} = time();
  791. readingsBeginUpdate($hash);
  792. readingsBulkUpdate($hash, "call_state","invite");
  793. readingsBulkUpdate($hash, "call",$nr);
  794. readingsEndUpdate($hash, 1);
  795. $hash->{'.oldstate'} = ReadingsVal($name,"state",undef);
  796. return undef;
  797. }
  798. else
  799. { # das war wohl nix :(
  800. Log3 $name, 3, "$name, CALL process start failed, arg : $arg";
  801. $error = "can't execute call number $nr as NonBlockingCall";
  802. readingsBeginUpdate($hash);
  803. readingsBulkUpdate($hash, "last_error",$error);
  804. readingsBulkUpdate($hash, "call_state","fail");
  805. readingsEndUpdate($hash, 1);
  806. delete $hash->{lastnr} if (defined($hash->{lastnr}));
  807. return $error;
  808. }
  809. }
  810. elsif ($cmd eq "listen")
  811. {
  812. my $type = AttrVal($name,"sip_listen","none");
  813. return "there is already a listen process running with pid ".$hash->{LPID} if exists($hash->{LPID});
  814. return "please set attr sip_listen to dtmf or wfp or echo first" if (AttrVal($name,"sip_listen","none") eq "none");
  815. $error = SIP_try_listen($hash);
  816. if ($error)
  817. {
  818. Log3 $name, 1, $name.", listen -> $error";
  819. readingsBeginUpdate($hash);
  820. readingsBulkUpdate($hash,"state","error");
  821. readingsBulkUpdate($hash,"last_error",$error);
  822. readingsBulkUpdate($hash,"listen_alive","no");
  823. readingsEndUpdate($hash, 1 );
  824. return $error;
  825. }
  826. return undef;
  827. }
  828. elsif (($cmd eq "dtmf_event") && defined($a[2]))
  829. {
  830. readingsSingleUpdate($hash, "dtmf",$a[2],1);
  831. return undef;
  832. }
  833. elsif ($cmd eq "fetch")
  834. {
  835. readingsSingleUpdate($hash, "caller","fetch",1);
  836. return undef;
  837. }
  838. elsif ($cmd eq "reject")
  839. {
  840. readingsSingleUpdate($hash, "caller","reject",1);
  841. return undef;
  842. }
  843. elsif ($cmd eq "reset")
  844. {
  845. $hash->{".reset"} = 1;
  846. SIP_updateConfig($hash);
  847. return undef;
  848. }
  849. # die ersten beiden brauchen wir nicht mehr
  850. shift @a;
  851. shift @a;
  852. # den Rest als ein String
  853. $subcmd = join(" ",@a);
  854. if ($cmd eq "password")
  855. {
  856. return SIP_storePassword($name,$subcmd);
  857. }
  858. return "Unknown argument: $cmd, choose one of ".join(" ", sort keys %sets);
  859. }
  860. #sub SIP_Get($@)
  861. #{
  862. # my ($hash, @a) = @_;
  863. # my $name = $hash->{NAME};
  864. # my $cmd = $a[1];
  865. # return ReadingsVal($name,"caller","???") if ($cmd eq "caller");
  866. #return "Unknown argument: $cmd, choose one of caller:noArg";
  867. # return undef;
  868. #}
  869. sub SIP_Undef($$)
  870. {
  871. my ($hash, $name) = @_;
  872. $ua->cleanup if (defined($ua));
  873. BlockingKill($hash->{helper}{LISTEN_PID}) if (defined($hash->{helper}{LISTEN_PID}));
  874. #RemoveInternalTimer($hash);
  875. #RemoveInternalTimer($name);
  876. return undef;
  877. }
  878. sub SIP_ListenStart($)
  879. {
  880. my ($name) = @_;
  881. return unless(defined($name));
  882. my $logname = $name."[".$$."]";
  883. my $hash = $defs{$name}; # $hash / $name gueltig in diesem Block
  884. $hash->{parent} = getppid();
  885. Log3 $name,4,"$logname, my parent is ".$hash->{parent};
  886. my $dtmfloop; # Ende-Flag für die DTMF-Schleife
  887. my $okloop; # Ende-Flag für die OK-Ansage
  888. my $okloopbye = 0; # Ende-Flag für recv_bye währne der OK-Ansage
  889. my $byebye = 0; # Anrufer hat aufgelegt
  890. my $packets = 50;
  891. my $block_it;
  892. my $sub_create;
  893. my $sub_invite_wfp;
  894. my $sub_filter;
  895. my $sub_bye;
  896. my $sub_dtmf;
  897. my $send_something;
  898. $ua = undef;
  899. my $error = SIP_Register($hash,"listen_".AttrVal($name,"sip_listen",""));
  900. return $name."|ListenRegister: $error" if ($error);
  901. my $msg1 = AttrVal($name, "sip_audiofile_dtmf", "");
  902. my $msg2 = AttrVal($name, "sip_audiofile_ok", "");
  903. my $msg3 = AttrVal($name, "sip_audiofile_wfp", "");
  904. $msg1 = SIP_check_file($hash,$hash->{audio1}) if (defined($hash->{audio1}));
  905. $msg1 = SIP_check_file($hash,$msg1) if (!defined($hash->{audio1}) && $msg1);
  906. $msg2 = SIP_check_file($hash,$hash->{audio2}) if (defined($hash->{audio2}));
  907. $msg2 = SIP_check_file($hash,$msg2) if (!defined($hash->{audio2}) && $msg2);
  908. $msg3 = SIP_check_file($hash,$hash->{audio3}) if (defined($hash->{audio3}));
  909. $msg3 = SIP_check_file($hash,$msg3) if (!defined($hash->{audio3}) && $msg3);
  910. Log3 $name,4,"$logname, using $msg1 for audio_dtmf" if ($msg1);
  911. Log3 $name,4,"$logname, using $msg2 for audio_ok" if ($msg2);
  912. Log3 $name,4,"$logname, using $msg3 for audio_wfp" if ($msg3);
  913. $hash->{dtmf} = 0;
  914. $hash->{dtmf_event} = "";
  915. $hash->{old} ="-";
  916. $send_something = sub
  917. {
  918. return unless $packets-- > 0;
  919. my $buf = sprintf "%010d",$packets;
  920. $buf .= "1234567890" x 15;
  921. return $buf; # 160 bytes for PCMU/8000
  922. };
  923. $sub_dtmf = sub
  924. {
  925. my ($event,$dur) = @_;
  926. Log3 $name,5,"$logname, DTMF Event: $event - $dur ms";
  927. return if (int($dur) < 100);
  928. if ($event eq "#")
  929. {
  930. $hash->{dtmf} = 1;
  931. $hash->{dtmf_event} = "";
  932. $hash->{old} = $event;
  933. return;
  934. }
  935. if (($event ne $hash->{old}) && $hash->{dtmf})
  936. {
  937. $hash->{dtmf} ++;
  938. $hash->{old} = $event;
  939. $hash->{dtmf_event} .= $event;
  940. Log3 $name,5,"$logname, DTMF: ".$hash->{dtmf_event}." , Anz: ".$hash->{dtmf};
  941. if ($hash->{dtmf} > int(AttrVal($name,"sip_dtmf_size",2)))
  942. {
  943. BlockingInformParent("SIP_rSU", [$name, "dtmf_event:".$hash->{dtmf_event}], 0);
  944. $hash->{dtmf} = 0;
  945. $hash->{dtmf_event} = "";
  946. $hash->{old} = "-";
  947. $dtmfloop = 1;
  948. }
  949. }
  950. return;
  951. };
  952. $sub_create = sub
  953. {
  954. my ($call,$request,$leg,$from) = @_;
  955. $hash->{call} = $call;
  956. $hash->{request} = $request;
  957. $hash->{leg} = $leg;
  958. $hash->{from} = $from;
  959. Log3 $name,4,"$logname, cb_create : ".$request->method;
  960. my $response = ($block_it) ? $request->create_response('487','Request Terminated') : $request->create_response('180','Ringing');
  961. $call->{endpoint}->new_response( $call->{ctx},$response,$leg,$from );
  962. 1;
  963. };
  964. $sub_invite_wfp = sub
  965. {
  966. my ($a,$b,$c,$d) = @_;
  967. my $waittime = int(AttrVal($name, "sip_waittime", 10));
  968. my $i;
  969. $packets = 50;
  970. for($i=1; $i<=$waittime; $i++)
  971. {
  972. if ($block_it) #und gleich wieder weg
  973. {
  974. sleep int(AttrVal($name, "sip_waittime", 2)); # kleine Pause
  975. last;
  976. }
  977. Log3 $name, 4,"$logname, SIP_invite -> ringing $i";
  978. select(undef, undef, undef, 1); # 1 Sekunde Pause
  979. my $action = BlockingInformParent("SIP_rSU", [$name, "caller_state:ringing $i"], 1);
  980. if(defined($action))
  981. {
  982. Log3 $name, 5,"$logname, action : $action";
  983. if ( $action eq "fetch" )
  984. {
  985. Log3 $name, 4,"$logname, SIP_invite fetch !";
  986. BlockingInformParent("SIP_rSU", [$name, "caller_state:fetching"], 0);
  987. last;
  988. }
  989. elsif ( $action eq "reject" )
  990. {
  991. Log3 $name, 4,"$logname, SIP_invite block !";
  992. BlockingInformParent("SIP_rSU", [$name, "caller_state:rejected"], 0);
  993. my $call = $hash->{call};
  994. my $request = $hash->{request};
  995. my $leg = $hash->{leg};
  996. my $from = $hash->{from};
  997. my $response = $request->create_response('603','Declined');
  998. $call->{endpoint}->new_response( $call->{ctx},$response,$leg,$from );
  999. last;
  1000. }
  1001. }
  1002. }
  1003. BlockingInformParent("SIP_rBU", [$name, "caller:none|caller_state:waiting"], 0) if (($i>$waittime) || $block_it);
  1004. return 0;
  1005. };
  1006. $sub_filter = sub
  1007. {
  1008. my ($a,$b) = @_;
  1009. Log3 $name, 5, "$logname, SIP_filter : a:$a | b:$b";
  1010. $block_it = 0; #
  1011. my ($caller,undef) = split("\;", $a);
  1012. my @callers;
  1013. $caller =~ s/\"//g;
  1014. $caller =~ s/\>//g;
  1015. $caller =~ s/\<//g; # fhem mag keine <> in ReadingsVal :(
  1016. $caller = "???" if (!$caller);
  1017. BlockingInformParent("SIP_rSU", [$name,"caller:".$caller],0);
  1018. my ($callnr,undef) = split("\@", $caller);
  1019. my $block = AttrVal($name,"sip_blocking",undef);
  1020. if (defined($block))
  1021. {
  1022. my @blockers = split (/,/,$block);
  1023. foreach (@blockers)
  1024. {
  1025. if ((index($callnr, $_) > -1) || ($_ eq ".*"))
  1026. {
  1027. BlockingInformParent("SIP_rSU", [$name, "caller_state:blocking"], 0);
  1028. Log3 $name, 4, "$logname, blocking $callnr found on $block";
  1029. $block_it = 1;
  1030. #$byebye = 1;
  1031. }
  1032. }
  1033. }
  1034. my $filter = AttrVal($name,"sip_filter",undef);
  1035. if (defined($filter))
  1036. {
  1037. @callers = split (/,/,$filter);
  1038. foreach (@callers) { return 1 if (index($callnr, $_) > -1); }
  1039. BlockingInformParent("SIP_rSU", [$name, "caller_state:ignoring"], 0);
  1040. Log3 $name, 4, "$logname, ignoring $callnr number not found in $filter";
  1041. return 0;
  1042. }
  1043. return 1;
  1044. };
  1045. $sub_bye = sub
  1046. {
  1047. my ($event) = @_;
  1048. Log3 $name, 5, "$logname, SIP_bye : $event";
  1049. my $calltime = 0;
  1050. $calltime = int(time()-$hash->{CALL_START}) if ($hash->{CALL_START});
  1051. BlockingInformParent("SIP_rBU", [$name, "caller:none|caller_state:hangup|caller_time:$calltime"], 0);
  1052. $byebye = 1;
  1053. return 1;
  1054. };
  1055. ################
  1056. if (AttrVal($name,"sip_listen", "none") eq "dtmf")
  1057. {
  1058. $hash->{dtmf} = 0;
  1059. $dtmfloop = 0; # Ende-Flag für die DTMF-Schleife
  1060. $okloop = 0; # Ende-Flag für die OK-Ansage
  1061. $okloopbye = 0; # Ende-Flag für recv_bye währne der OK-Ansage
  1062. $byebye = 0; # Anrufer hat aufgelegt
  1063. while(1)
  1064. {
  1065. my $call;
  1066. $hash->{dtmf} = 0;
  1067. $hash->{dtmf_event} = "";
  1068. $hash->{old} ="-";
  1069. BlockingInformParent("SIP_rBU", [$name, "caller:none|caller_state:waiting"], 0);
  1070. $ua->listen (cb_create => \&$sub_create,
  1071. cb_invite => sub {
  1072. if (!$block_it)
  1073. {
  1074. BlockingInformParent("SIP_rSU", [$name,"caller_state:ringing"],0);
  1075. sleep int(AttrVal($name, "sip_ringtime", 3)); #Anrufer hört das typische Klingeln wenn die Gegenseite nicht abnimmt
  1076. }
  1077. },
  1078. filter => \&$sub_filter,
  1079. cb_established => sub {
  1080. (my $status,$call) = @_;
  1081. if (!$block_it)
  1082. {
  1083. $hash->{CALL_START} = time();
  1084. BlockingInformParent("SIP_rSU", [$name,"caller_state:established"],0);
  1085. }
  1086. else {
  1087. sleep 1;
  1088. #SIP_telnet($hash, "set $name caller none\nset $name caller_state waitting\nexit\n") ;
  1089. return 0; }
  1090. } # sobald invite verlassen wird, wird in cb_established verzweigt
  1091. );
  1092. $ua->loop(\$call);
  1093. # Der SIP-Client ist jetzt im echo-Modus und zwar so lange, bis der Anrufer auflegt,
  1094. # das bekommen wir durch recv_bye mit
  1095. my $dtmf_loop = 1; # für jeden Anruf neu setzen
  1096. while ($dtmf_loop) # Schleife für Code-Ansage, DTMF-Erkennung, okay-Ansage
  1097. {
  1098. $dtmfloop = 0;
  1099. $okloop = 0;
  1100. $okloopbye = 0;
  1101. $call->reinvite(
  1102. init_media => $ua->rtp('send_recv',($msg1) ? $msg1 : $send_something),
  1103. rtp_param => [8, 160, 160/8000, 'PCMA/8000'],
  1104. cb_rtp_done => sub { $packets = 25; },
  1105. cb_dtmf => \&$sub_dtmf,
  1106. recv_bye => \&$sub_bye,
  1107. );
  1108. $ua->loop(\$dtmfloop, \$byebye);
  1109. if (!$byebye)
  1110. { # Anrufer hat nicht aufgelegt
  1111. $call->reinvite(
  1112. init_media => $ua->rtp('send_recv',($msg2) ? $msg2 : $send_something),
  1113. rtp_param => [8, 160, 160/8000, 'PCMA/8000'],
  1114. cb_rtp_done => sub { select(undef, undef, undef, 0.1); $okloop = 1; $packets = 50;},
  1115. recv_bye => sub { $okloopbye = 1; },
  1116. cb_cleanup => sub {0},
  1117. );
  1118. $ua->loop(\$okloop,\$okloopbye); # ohne diese loop endet der Anruf sofort
  1119. }
  1120. else { $dtmf_loop = 0; } # Schleife beenden, Anrufer hat aufgelegt
  1121. if ( ( defined $okloopbye && $okloopbye ) || $byebye )
  1122. { # wenn jemand mitten im "okay" auflegt
  1123. $dtmf_loop = 0; # beende die inner loop
  1124. $byebye = 1;
  1125. }
  1126. else { $dtmf_loop = ((AttrVal($name,"sip_dtmf_loop","once") eq 'once')) ? 0 : 1;
  1127. my $calltime = int(time()-$hash->{CALL_START});
  1128. BlockingInformParent("SIP_rBU", [$name, "caller_state:hangup|caller_time:$calltime"], 0) if(!$dtmf_loop);
  1129. } # führt ggf. zum Schleifenende
  1130. } # end inner loop
  1131. if (!$byebye)
  1132. { # Anrufer hat nicht aufgelegt und nur ein DTMF angefordert
  1133. my $hanguploop;
  1134. $call->bye( cb_final => \$hanguploop );
  1135. $ua->loop( \$hanguploop );
  1136. }
  1137. } # while(1)
  1138. }
  1139. elsif (AttrVal($name,"sip_listen", "none") eq "wfp")
  1140. {
  1141. $ua->listen(
  1142. cb_create => \&$sub_create,
  1143. cb_invite => \&$sub_invite_wfp,
  1144. cb_established => sub { $hash->{CALL_START} = time(); },
  1145. filter => \&$sub_filter,
  1146. recv_bye => \&$sub_bye,
  1147. init_media => $ua->rtp('send_recv',($msg3) ? $msg3 : $send_something),
  1148. #cb_rtp_done => sub { $packets = 50; return 1;},
  1149. rtp_param => [8, 160, 160/8000, 'PCMA/8000']
  1150. ); # options are invite and hangup
  1151. }
  1152. elsif (AttrVal($name,"sip_listen", "none") eq "echo")
  1153. {
  1154. $ua->listen(
  1155. filter => \&$sub_filter,
  1156. cb_create => \&$sub_create,
  1157. cb_invite => sub {
  1158. if (!$block_it)
  1159. {
  1160. BlockingInformParent("SIP_rSU", [$name,"caller_state:ringing"],0);
  1161. sleep int(AttrVal($name, "sip_ringtime", 3)); #Anrufer hört das typische Klingeln wenn die Gegenseite nicht abnimmt
  1162. }
  1163. },
  1164. cb_established => sub { $hash->{CALL_START} = time(); },
  1165. init_media => $ua->rtp( 'recv_echo',undef,0 ),
  1166. rtp_param => [8, 160, 160/8000, 'PCMA/8000'],
  1167. recv_bye => \&$sub_bye,
  1168. );
  1169. }
  1170. else { return $name."|end"; }
  1171. $ua->loop;
  1172. return $name."|end"; # hier sollten wir eigentlich nie himkommen !
  1173. }
  1174. sub SIP_ListenDone($)
  1175. {
  1176. my ($string) = @_;
  1177. return unless(defined($string));
  1178. my @r = split("\\|",$string);
  1179. my $hash = $defs{$r[0]};
  1180. my $ret = (defined($r[1])) ? $r[1] : "unknown error";
  1181. my $name = $hash->{NAME};
  1182. Log3 $name, 5,"$name, ListenDone -> $string";
  1183. delete($hash->{helper}{LISTEN_PID});
  1184. delete $hash->{LPID};
  1185. RemoveInternalTimer($name);
  1186. if ($ret ne "end")
  1187. {
  1188. readingsBeginUpdate($hash);
  1189. readingsBulkUpdate($hash,"state","error");
  1190. readingsBulkUpdate($hash,"last_error",$ret);
  1191. readingsBulkUpdate($hash,"listen_alive","no");
  1192. readingsEndUpdate($hash, 1 );
  1193. Log3 $name, 3 , "$name, listen error -> $ret";
  1194. return if(IsDisabled($name));
  1195. InternalTimer(gettimeofday()+AttrVal($name, "sip_watch_listen", 60), "SIP_try_listen", $hash);
  1196. }
  1197. else
  1198. {
  1199. readingsBeginUpdate($hash);
  1200. readingsBulkUpdate($hash,"state","ListenDone");
  1201. readingsBulkUpdate($hash,"listen_alive","no");
  1202. readingsEndUpdate($hash, 1 );
  1203. return if(IsDisabled($name));
  1204. return if(!AttrVal($name, "sip_dtmf", 0));
  1205. SIP_try_listen($hash);
  1206. }
  1207. return;
  1208. }
  1209. sub SIP_try_listen($)
  1210. {
  1211. my ($hash) = @_;
  1212. my $name = $hash->{NAME};
  1213. my $waits = AttrVal($name, "sip_watch_listen", 60);
  1214. my $audio1 = AttrVal($name, "sip_audiofile_dtmf","-");
  1215. my $audio2 = AttrVal($name, "sip_audiofile_ok", "-");
  1216. my $audio3 = AttrVal($name, "sip_audiofile_wfp", "-");
  1217. my @a = ("tts","tts", "-");;
  1218. if (AttrVal($name,"sip_listen","none") eq "dtmf")
  1219. {
  1220. if ((substr($audio1,0,1) eq "!") && !defined($hash->{audio1})) # muss erst T2S gefragt werden ?
  1221. {
  1222. $audio1 =~ s/^\!//;
  1223. $hash->{audio1} = $audio1;
  1224. $a[2] = $audio1;
  1225. Log3 $name ,4,"$name, hole $audio1";
  1226. }
  1227. elsif ((substr($audio2,0,1) eq "!") && !defined($hash->{audio2})) # muss erst T2S gefragt werden ?
  1228. {
  1229. $audio2 =~ s/^\!//;
  1230. $hash->{audio2} = $audio2;
  1231. $a[2] = $audio2;
  1232. Log3 $name ,4,"$name, hole $audio2";
  1233. }
  1234. }
  1235. elsif ((substr($audio3,0,1) eq "!") && !defined($hash->{audio3}) && (AttrVal($name,"sip_listen","none") eq "wfp")) # muss erst T2S gefragt werden ?
  1236. {
  1237. $audio3 =~ s/^\!//;
  1238. $hash->{audio3} = $audio3;
  1239. $a[2] = $audio3;
  1240. Log3 $name ,4,"$name, hole $audio3";
  1241. }
  1242. if ($a[2] ne "-")
  1243. {
  1244. # prüfen ob es schon eine passende mp3 Datei gibt
  1245. my $filename = SIP_check_T2S_File($hash,@a);
  1246. if (!$filename)
  1247. {
  1248. my $ret = SIP_create_T2S_File($hash,@a);
  1249. if ($ret)
  1250. {
  1251. delete $hash->{audio1} if defined($hash->{audio1});
  1252. delete $hash->{audio2} if defined($hash->{audio2});
  1253. delete $hash->{audio3} if defined($hash->{audio3});
  1254. return $ret;
  1255. }
  1256. #starte die Überwachung von T2S
  1257. RemoveInternalTimer($hash);
  1258. InternalTimer(gettimeofday()+int(AttrVal($name,"T2S_Timeout",5)), "SIP_watchdog_T2S", $hash);
  1259. return undef;
  1260. }
  1261. else
  1262. {
  1263. Log3 $name, 4 , "$name, T2S not used $filename exits";
  1264. $hash->{audio1} = $filename if defined($hash->{audio1});
  1265. $hash->{audio2} = $filename if defined($hash->{audio2});
  1266. $hash->{audio3} = $filename if defined($hash->{audio3});
  1267. }
  1268. }
  1269. $hash->{helper}{LISTEN_PID} = BlockingCall("SIP_ListenStart",$name, "SIP_ListenDone") unless(exists($hash->{helper}{LISTEN_PID}));
  1270. if ($hash->{helper}{LISTEN_PID})
  1271. {
  1272. $hash->{LPID} = $hash->{helper}{LISTEN_PID}{pid};
  1273. Log3 $name, 4 , $name.", Listen new PID : ".$hash->{LPID};
  1274. RemoveInternalTimer($name);
  1275. InternalTimer(gettimeofday()+$waits, "SIP_watch_listen", $name); # starte die Überwachung
  1276. delete $hash->{audio1};
  1277. delete $hash->{audio2};
  1278. delete $hash->{audio3};
  1279. return 0;
  1280. }
  1281. else
  1282. {
  1283. Log3 $name, 2 , $name.", Listen Start failed, waiting $waits seconds for next try";
  1284. RemoveInternalTimer($hash);
  1285. InternalTimer(gettimeofday()+$waits, "SIP_try_listen", $hash);
  1286. return "Listen Start failed";
  1287. }
  1288. }
  1289. sub SIP_watch_listen($)
  1290. {
  1291. # Lebt denn der Listen Prozess überhaupt noch ?
  1292. my ($name) = @_;
  1293. my $hash = $defs{$name};
  1294. my $listen_dead = 0;
  1295. RemoveInternalTimer($name);
  1296. return if (IsDisabled($name));
  1297. return if (!defined($hash->{LPID}));
  1298. my $cmd = "ps -e | grep '".$hash->{LPID}." '";
  1299. my $result = qx($cmd);
  1300. my $age = int(ReadingsAge($name, "expire", 0));
  1301. my $maxage = int(ReadingsNum($name,"expire",300)*0.7);
  1302. my $alive = ReadingsVal($name,"listen_alive","no");
  1303. my $waits = AttrVal($name, "sip_watch_listen", 60);
  1304. if (($age > $maxage) && ($alive ne "no")) # nach expire/2 Sekunden sollte sich der listen Prozess erneut melden
  1305. {
  1306. Log3 $name, 2 , "$name, expire timestamp is $age seconds old, restarting listen process";
  1307. readingsSingleUpdate($hash,"listen_alive","no",1);
  1308. $alive = "no";
  1309. }
  1310. elsif (index($result,"perl") == -1)
  1311. {
  1312. Log3 $name, 2 , $name.", cant find listen process ".$hash->{LPID}." in process list !";
  1313. $alive = "no";;
  1314. }
  1315. else { Log3 $name, 5 , $name.", listen process ".$hash->{LPID}." found"; }
  1316. if ($alive eq "no")
  1317. {
  1318. BlockingKill($hash->{helper}{LISTEN_PID});
  1319. delete $hash->{helper}{LISTEN_PID};
  1320. delete $hash->{LPID};
  1321. InternalTimer(gettimeofday()+2, "SIP_try_listen", $hash, 0);
  1322. }
  1323. InternalTimer(gettimeofday()+$waits, "SIP_watch_listen", $name, 0);
  1324. return;
  1325. }
  1326. sub SIP_wait_for_t2s($)
  1327. {
  1328. my ($hash) = @_;
  1329. my $name = $hash->{NAME};
  1330. RemoveInternalTimer($hash);
  1331. my $t2s_name = AttrVal($name,"T2S_Device",undef);
  1332. my $file = ReadingsVal($t2s_name,"lastFilename","");
  1333. my $msg = "";
  1334. Log3 $name,4,"$name, wait_for_t2s file : $file";
  1335. if (-e $file)
  1336. {
  1337. Log3 $name,4,"$name, new T2S file $file";
  1338. my $out = $file;
  1339. $out =~ s/mp3/alaw/;
  1340. my $error = SIP_MP3_conv($hash,$file,$name);
  1341. $msg = $out if (!$error && (-e $out));
  1342. }
  1343. else
  1344. {
  1345. Log3 $name,3,"$name, timeout waiting for T2S";
  1346. if ($hash->{callnr})
  1347. {
  1348. readingsSingleUpdate($hash,"call_state","T2S timeout",1);
  1349. return undef;
  1350. }
  1351. }
  1352. if (!$hash->{callnr})
  1353. {
  1354. if (defined($hash->{audio3}))
  1355. {
  1356. $hash->{audio3} = $msg;
  1357. SIP_try_listen($hash);
  1358. return undef;
  1359. }
  1360. elsif (defined($hash->{audio2}))
  1361. {
  1362. $hash->{audio2} = $msg;
  1363. SIP_try_listen($hash);
  1364. return undef;
  1365. }
  1366. elsif (defined($hash->{audio1}))
  1367. {
  1368. $hash->{audio1} = $msg;
  1369. SIP_try_listen($hash);
  1370. return undef;
  1371. }
  1372. }
  1373. # nun aber calling
  1374. my $repeat = "*".$hash->{repeat};
  1375. my @a;
  1376. if ($hash->{forcecall})
  1377. { @a = ($name,"call",$hash->{callnr}, $hash->{ringtime},$msg,$repeat,$hash->{forcecall}) ; }
  1378. else
  1379. { @a = ($name,"call",$hash->{callnr}, $hash->{ringtime},$msg,$repeat) ; }
  1380. delete($hash->{callnr});
  1381. delete($hash->{ringtime});
  1382. delete($hash->{forcecall});
  1383. delete($hash->{repeat});
  1384. my $ret = SIP_Set($hash , @a);
  1385. Log3 $name,3,"$name, error T2S Call : $ret" if defined($ret);
  1386. return undef;
  1387. }
  1388. ######################################################
  1389. # storePW & readPW Code geklaut aus 72_FRITZBOX.pm :)
  1390. ######################################################
  1391. sub SIP_storePassword($$)
  1392. {
  1393. my ($name, $password) = @_;
  1394. my $index = "SIP_".$name."_passwd";
  1395. my $key = getUniqueId().$index;
  1396. my $e_pwd = "";
  1397. if (eval "use Digest::MD5;1")
  1398. {
  1399. $key = Digest::MD5::md5_hex(unpack "H*", $key);
  1400. $key .= Digest::MD5::md5_hex($key);
  1401. }
  1402. for my $char (split //, $password)
  1403. {
  1404. my $encode=chop($key);
  1405. $e_pwd.=sprintf("%.2x",ord($char)^ord($encode));
  1406. $key=$encode.$key;
  1407. }
  1408. my $error = setKeyValue($index, $e_pwd);
  1409. return "error while saving SIP user password : $error" if(defined($error));
  1410. return "SIP user password successfully saved in FhemUtils/uniqueID Key $index";
  1411. }
  1412. sub SIP_readPassword($)
  1413. {
  1414. my ($name) = @_;
  1415. my $index = "SIP_".$name."_passwd";
  1416. my $key = getUniqueId().$index;
  1417. my ($password, $error);
  1418. #Log3 $name,5,"$name, read SIP user password from FhemUtils/uniqueID Key $key";
  1419. ($error, $password) = getKeyValue($index);
  1420. if ( defined($error) )
  1421. {
  1422. Log3 $name,3, "$name, cant't read SIP user password from FhemUtils/uniqueID: $error";
  1423. return undef;
  1424. }
  1425. if ( defined($password) )
  1426. {
  1427. if (eval "use Digest::MD5;1")
  1428. {
  1429. $key = Digest::MD5::md5_hex(unpack "H*", $key);
  1430. $key .= Digest::MD5::md5_hex($key);
  1431. }
  1432. my $dec_pwd = '';
  1433. for my $char (map { pack('C', hex($_)) } ($password =~ /(..)/g))
  1434. {
  1435. my $decode=chop($key);
  1436. $dec_pwd.=chr(ord($char)^ord($decode));
  1437. $key=$decode.$key;
  1438. }
  1439. return $dec_pwd;
  1440. }
  1441. else
  1442. {
  1443. Log3 $name,3,"$name, no SIP user password found in FhemUtils/uniqueID";
  1444. return undef;
  1445. }
  1446. }
  1447. #####################################
  1448. sub SIP_check_file($$)
  1449. {
  1450. my ($hash,$file) = @_;
  1451. my $name = $hash->{NAME};
  1452. my $logname = $name."[".$$."]";
  1453. if (substr($file,0,1) eq "!")
  1454. {
  1455. Log3 $name,3,"$logname, Text : $file found, ignoring it";
  1456. return "";
  1457. }
  1458. if ($file =~/\.mp3$/)
  1459. {
  1460. my $ret = SIP_MP3_conv($hash,$file,$logname);
  1461. if ($ret)
  1462. {
  1463. Log3 $name,3,"$logname, $ret";
  1464. return "";
  1465. }
  1466. $file =~ s/mp3/alaw/;
  1467. }
  1468. if (($file !~ /\.al(.+)$/) && ($file !~ /\.ul(.+)$/))
  1469. {
  1470. Log3 $name,3,"$logname, audio file $file not type .alaw or .ulaw, ignoring it";
  1471. return "";
  1472. }
  1473. if (!-e $file)
  1474. {
  1475. Log3 $name,3,"$logname, audio file $file not found, ignoring it";
  1476. return "";
  1477. }
  1478. Log3 $name,5,"$logname, audio file $file found";
  1479. return $file;
  1480. }
  1481. sub SIP_create_T2S_File($@)
  1482. {
  1483. my ($hash,@a) = @_;
  1484. my $name = $hash->{NAME};
  1485. my $t2s_name = AttrVal($name,"T2S_Device",undef);
  1486. return "attr T2S_Device not set !" if !defined($t2s_name);
  1487. my $t2s_hash = (defined($defs{$t2s_name})) ? $defs{$t2s_name} : undef;
  1488. return "T2S_Device $t2s_name not found" if !defined($t2s_hash);
  1489. return "attr audio_converter not set" if !AttrVal($name,"audio_converter","");
  1490. return "external sox or ffmpeg programm not found, please install sox or ffmpeg first and set attr audio_converter" if !defined($hash->{AC});
  1491. my $t2s_file = ReadingsVal($t2s_name,"lastFilename",undef);
  1492. Log3 $name,3,"$name, Reading lastFilename not found at device $t2s_name, are you using a old version ?" if !defined($t2s_file);
  1493. readingsSingleUpdate($t2s_hash,"lastFilename","",0);
  1494. my $ret = Text2Speech_Set($t2s_hash, @a); # na dann lege schon mal los
  1495. if (defined($ret))
  1496. {
  1497. Log3 $name,3,"$name, T2S error : $ret";
  1498. readingsSingleUpdate($hash,"last_error",$ret,0);
  1499. return $ret; # Das ging leider schief
  1500. }
  1501. return undef; # alles klar
  1502. }
  1503. sub SIP_check_T2S_File($@)
  1504. {
  1505. my ($hash,@a) = @_;
  1506. my $name = $hash->{NAME};
  1507. my $t2s_name = AttrVal($hash->{NAME},"T2S_Device","");
  1508. return 0 if (!$t2s_name);
  1509. shift @a;
  1510. shift @a;
  1511. my $txt = join(" ",@a);
  1512. my $filename = (eval "use Digest::MD5;1") ? md5_hex("de|".$txt).".mp3" : "";
  1513. if ($filename)
  1514. {
  1515. my $file = AttrVal($t2s_name,"TTS_CacheFileDir", "cache"). "/".$filename;
  1516. Log3 $name,5,"$name, MD5: $txt -> $filename";
  1517. return $file if (-e $file);
  1518. }
  1519. Log3 $name,5,"$name, mp3 File file not found in cache";
  1520. return 0;
  1521. }
  1522. sub SIP_watchdog_T2S($)
  1523. {
  1524. my ($hash) = @_;
  1525. my $name = $hash->{NAME};
  1526. Log3 $name,3,"$name, Timeout waiting for T2S";
  1527. if (defined($hash->{audio1}))
  1528. {
  1529. $hash->{audio1}="!T2S Timeout";
  1530. SIP_try_listen($hash);
  1531. return undef;
  1532. }
  1533. if (defined($hash->{audio2}))
  1534. {
  1535. $hash->{audio2}="!T2S Timeout";
  1536. SIP_try_listen($hash);
  1537. return undef;
  1538. }
  1539. if (defined($hash->{audio3}))
  1540. {
  1541. $hash->{audio3}="!T2S Timeout";
  1542. SIP_try_listen($hash);
  1543. return undef;
  1544. }
  1545. }
  1546. #####################################
  1547. # Benutzt um Infos aus dem Blockingprozess in die Readings zu schreiben
  1548. #####################################
  1549. sub SIP_rSU($$) {
  1550. my ($name, $line) = @_;
  1551. my $hash = $defs{$name};
  1552. my ($reading,$val) = split(":",$line);
  1553. Log3 $hash, 5, "$name, readingS:$reading Val:$val";
  1554. readingsSingleUpdate($hash, $reading, $val, 1);
  1555. # Sonderfall bei wfp , Abfrage des caller auf fetch oder reject
  1556. return ReadingsVal($name,"caller","???") if (($reading eq "caller_state") && (substr($val,0,7) eq "ringing"));
  1557. return undef;
  1558. }
  1559. sub SIP_rBU($$) {
  1560. my ($name, $line) = @_;
  1561. my $hash = $defs{$name};
  1562. readingsBeginUpdate($hash);
  1563. my @pair = split("\\|",$line);
  1564. foreach (@pair)
  1565. {
  1566. my ($reading,$val) = split(":",$_);
  1567. {
  1568. Log3 $hash, 5, "$name, readingB:$reading Val:$val";
  1569. readingsBulkUpdate($hash, $reading, $val);
  1570. }
  1571. }
  1572. readingsEndUpdate($hash, 1 );
  1573. return undef;
  1574. }
  1575. sub SIP_MP3_conv($$$)
  1576. {
  1577. my ($hash,$file,$logname) = @_;
  1578. my $name = $hash->{NAME};
  1579. my $ret;
  1580. my $status;
  1581. my $cmd;
  1582. my $out = $file;
  1583. $out =~ s/mp3/alaw/;
  1584. if (-e $out)
  1585. {
  1586. Log3 $name,5,"$logname, not converted - using $out from cache";
  1587. return undef;
  1588. }
  1589. else
  1590. {
  1591. return "external sox or ffmpeg programm not found, please install sox or ffmpeg first and set attr audio_converter" if (!defined($hash->{AC}));
  1592. my $converter = AttrVal($name,"audio_converter","");
  1593. return "attr audio_converter not set" if(!$converter);
  1594. if ($converter eq "sox")
  1595. {
  1596. $cmd = $hash->{AC}." ".$file." -t raw -r 8000 -c 1 -e a-law ".$out." 2>&1";
  1597. Log3 $name,5,"$logname, $cmd";
  1598. $ret = qx($cmd);
  1599. if ($ret)
  1600. {
  1601. unlink $out;
  1602. $ret =~ s/\n//g;
  1603. Log3 $name,5,"$logname, sox output : $ret";
  1604. }
  1605. }
  1606. elsif ($converter eq "ffmpeg")
  1607. {
  1608. $cmd = $hash->{AC}." -v quiet -y -i ".$file." -f alaw -ar 8000 ".$out;
  1609. Log3 $name,5,"$logname, $cmd";
  1610. $ret = qx($cmd);
  1611. }
  1612. else { return "unknow audio_converter"; }
  1613. return "$converter : $ret" if ($ret);
  1614. return "converted file $out not found" if (!-e $out);
  1615. return undef;
  1616. }
  1617. }
  1618. 1;
  1619. =pod
  1620. =item helper
  1621. =item summary SIP device
  1622. =item summary_DE SIP Ger&auml;t
  1623. =begin html
  1624. <a name="SIP"></a>
  1625. <h3>SIP</h3>
  1626. <ul>
  1627. Define a SIP-Client device.<br>
  1628. Wiki : <a href="https://wiki.fhem.de/wiki/SIP-Client">https://wiki.fhem.de/wiki/SIP-Client</a>
  1629. <br>
  1630. Forum : <a href="https://forum.fhem.de/index.php/topic,67443.0.html">https://forum.fhem.de/index.php/topic,67443.0.html</a>
  1631. <br><br>
  1632. <a name="SIPdefine"></a>
  1633. <b>Define</b>
  1634. <ul>
  1635. <code>define &lt;name&gt; SIP</code>
  1636. <br><br>
  1637. Example:
  1638. <ul>
  1639. <code>define MySipClient SIP</code><br>
  1640. </ul>
  1641. </ul>
  1642. <br>
  1643. <a name="SIPset"></a>
  1644. <b>Set</b>
  1645. <ul>
  1646. <li>
  1647. <code>set &lt;name&gt; &lt;SIP password&gt;</code><br>
  1648. Stores the password for the SIP users. Without stored password the functions set call and set listen are blocked !<br>
  1649. IMPORTANT : if you rename the fhem Device you must set the password again!
  1650. </li>
  1651. <li>
  1652. <code>set &lt;name&gt; reset</code><br>
  1653. Stop any listen process and initialize device.<br>
  1654. </li>
  1655. <li>
  1656. <code>set &lt;name&gt; call &lt;number&gt [&lt;maxtime&gt;] [&lt;message&gt;]</code><br>
  1657. Start a call to the given number.<br>
  1658. Optionally you can supply a max time. Default is 30.
  1659. Optionally you can supply a message which is either a full path to an audio file or a relativ path starting from the home directory of the fhem.pl.
  1660. </li>
  1661. <li>
  1662. <code>set &lt;name&gt; listen</code><br>
  1663. attr sip_listen = dtmf :<br>
  1664. Start a listening process that receives calls. The device goes into an echo mode when a call comes in. If you press # on the keypad followed by 2 numbers and hang up the reading <b>dtmf</b> will reflect that number.<br>
  1665. attr sip_listen = wfp :<br>
  1666. Start a listening process that waits for incoming calls. If a call comes in for the SIP-Client the state will change to <b>ringing</b>. If you manually set the state to <b>fetch</b> the call will be picked up and the sound file given in attribute sip_audiofile will be played to the caller. After that the devive will go gack into state <b>listenwfp</b>.<br>
  1667. </li>
  1668. </ul>
  1669. <br>
  1670. <a name="SIPattr"></a>
  1671. <b>Attributes</b>
  1672. <ul>
  1673. <li><a href="#sip_audiofile_wfp">sip_audiofile_wfp</a><br>
  1674. Audio file that will be played after <b>fetch</b> command. The audio file has to be generated via <br>
  1675. sox &lt;file&gt;.wav -t raw -r 8000 -c 1 -e a-law &lt;file&gt;.al<br>
  1676. since only raw audio format is supported.
  1677. </li>
  1678. <li><a href="#sip_audiofile_call">sip_audiofile_call</a></li>
  1679. <li><a href="#sip_audiofile_dtmf">sip_audiofile_dtmf</a></li>
  1680. <li><a href="#sip_audiofile_ok">sip_audiofile_ok</a></li>
  1681. <li><a href="#sip_listen">sip_listen</a>(none , dtmf , wfp)</li>
  1682. <li><a name="#sip_from">sip_from</a><br>
  1683. My sip client info, defaults to sip:620@fritz.box
  1684. </li>
  1685. <li><a name="#sip_ip">sip_ip</a><br>
  1686. external IP address of the FHEM server.
  1687. </li>
  1688. <li><a name="#sip_port">sip_port</a><br>
  1689. Optionally portnumber used for sip client<br>
  1690. If attribute is not set a random port number between 44000 and 45000 will be used
  1691. </li>
  1692. <li><a name="#sip_registrar">sip_registrar</a><br>
  1693. Hostname or IP address of the SIP server you are connecting to, defaults to fritz.box.
  1694. </li>
  1695. <li><a name="#sip_ringtime">sip_ringtime</a><br>
  1696. Ringtime for incomming calls (dtmf &wfp)
  1697. </li>
  1698. <li><a name="#sip_user">sip_user</a><br>
  1699. User name of the SIP client, defaults to 620.
  1700. </li>
  1701. <li><a name="#sip_waittime">sip_waittime</a><br>
  1702. Maximum waiting time in state listen_for_wfp it will wait to pick up the call.
  1703. </li>
  1704. <li><a name="#sip_dtmf_size">sip_dtmf_size</a><br>
  1705. 1 to 4 , default is 2 ...
  1706. </li>
  1707. <li><a name="#sip_dtmf_loop">sip_dtmf_loop</a><br>
  1708. once or loop , default once ...
  1709. </li>
  1710. <li><a name="#sip_force_interval">sip_force_interval</a><br>
  1711. default 300
  1712. </li>
  1713. <li><a name="#sip_force_max">sip_force_max</a><br>
  1714. default 99
  1715. </li>
  1716. </ul>
  1717. <br>
  1718. </ul>
  1719. =end html
  1720. =begin html_DE
  1721. <a name="SIP"></a>
  1722. <h3>SIP</h3>
  1723. <ul>
  1724. Definiert ein SIP-Client Device.<br>
  1725. Wiki : <a href="https://wiki.fhem.de/wiki/SIP-Client">https://wiki.fhem.de/wiki/SIP-Client</a>
  1726. <br>
  1727. Forum : <a href="https://forum.fhem.de/index.php/topic,67443.0.html">https://forum.fhem.de/index.php/topic,67443.0.html</a>
  1728. <br><br>
  1729. <a name="SIPdefine"></a>
  1730. <b>Define</b>
  1731. <ul>
  1732. <code>define &lt;name&gt; SIP</code>
  1733. <br><br>
  1734. Beispiel:
  1735. <ul>
  1736. <code>define MySipClient SIP</code><br>
  1737. </ul>
  1738. </ul>
  1739. <br>
  1740. <a name="SIPset"></a>
  1741. <b>Set</b>
  1742. <ul>
  1743. <li>
  1744. <code>set &lt;name&gt; &lt;SIP Passwort&gt;</code><br>
  1745. Speichert das Passwort des SIP Users. Ohne gespeichertes Passwort sind die set call und set listen Funktionen gesperrt !<br>
  1746. WICHTIG : wird das SIP Device umbenannt muss dieser Befehl unbedingt wiederholt werden !
  1747. </li>
  1748. <li>
  1749. <code>set &lt;name&gt; reset</code><br>
  1750. Stoppt laufende listen-Prozess und initalisiert das Device.<br>
  1751. </li>
  1752. <li>
  1753. <code>set &lt;name&gt; call &lt;nummer&gt; [&lt;maxtime&gt;] [&lt;nachricht&gt;]</code><br>
  1754. Startet einen Anruf an die angegebene Nummer.<br>
  1755. Optional kann die maximale Zeit angegeben werden. Default ist 30.<br>
  1756. Optional kann eine Nachricht in Form eines Audiofiles angegeben werden . Das File ist mit dem vollen Pfad oder dem relativen ab dem Verzeichnis mit fhem.pl anzugeben..
  1757. </li>
  1758. <li>
  1759. <code>set &lt;name&gt; listen</code><br>
  1760. Attribut sip_listen = dtmf :
  1761. Der SIP-Client wird in einen Status versetzt in dem er Anrufe annimmt. Der Ton wird als Echo zurückgespielt. Über die Eingabe von # gefolgt von 2 unterschiedlichen Zahlen und anschließendem Auflegen kann eine Zahl in das Reading <b>dtmf</b> übergeben werden.<br>
  1762. Attribut sip_listen = wfp :
  1763. Der SIP-Client wird in einen Status versetzt in dem er auf Anrufe wartet. Erfolgt an Anruf an den Client, wechselt der Status zu <b>ringing</b>. Nun kann das Gespräch via set-Command <b>fetch</b> angenommen werden. Das als sip_audiofile angegebene File wird abgespielt. Anschließend wechselt der Status wieder zu <b>listenwfp</b>.<br>
  1764. </li>
  1765. </ul>
  1766. <br>
  1767. <a name="SIPattr"></a>
  1768. <b>Attributes</b>
  1769. <ul>
  1770. <li><a name="#sip_user">sip_user</a><br>
  1771. User Name des SIP-Clients. Default ist 620 (Fritzbox erstes SIP Telefon)
  1772. </li>
  1773. <li><a name="#sip_registrar">sip_registrar</a><br>
  1774. Hostname oder IP-Addresse des SIP-Servers mit dem sich das Modul verbinden soll. (Default fritz.box)
  1775. </li>
  1776. <li><a name="#sip_from">sip_from</a><br>
  1777. SIP-Client-Info. Syntax : sip:sip_user@sip_registrar Default ist sip:620@fritz.box
  1778. </li>
  1779. <li><a name="#sip_ip">sip_ip</a><br>
  1780. Die IP-Addresse von FHEM im Heimnetz. Solange das Attribut nicht gesetzt ist versucht das Modul diese beim Start zu ermitteln.
  1781. </li>
  1782. <li><a name="#sip_port">sip_port</a><br>
  1783. Optinale Portnummer die vom Modul benutzt wird.<br>
  1784. Wenn dem Attribut kein Wert zugewiesen wurde verwendet das Modul eine zuf&auml;llige Portnummer zwichen 44000 und 45000
  1785. </li>
  1786. <li><b>Audiofiles</b>
  1787. Audiofiles k&ouml;nnen einfach mit dem externen Programm sox erzeugt werden :<br>
  1788. sox &lt;file&gt;.wav -t raw -r 8000 -c 1 -e a-law &lt;file&gt;.al<br>
  1789. Unterst&uuml;tzt werden nur die beiden RAW Audio Formate a-law und u-law !<br>
  1790. Statt eines echten Audiofiles kann auch eine Text2Speech Nachricht eingetragen werden.<br>
  1791. Bsp : attr mySIP sip_audiofile_call !Hier ist dein FHEM Server
  1792. </li>
  1793. <li><a href="#sip_audiofile_wfp">sip_audiofile_wfp</a><br>
  1794. Audiofile das nach dem Command <b>fetch</b> abgespielt wird.
  1795. </li>
  1796. <li><a href="#sip_audiofile_call">sip_audiofile_call</a></li>
  1797. Audiofile das dem Angerufenen bei set call vorgespielt wird.
  1798. <li><a href="#sip_audiofile_dtmf">sip_audiofile_dtmf</a></li>
  1799. Audiofile das dem Anrufer bei listen_for_dtmf abgespielt wird.
  1800. <li><a href="#sip_audiofile_ok">sip_audiofile_ok</a></li>
  1801. Audiofile das bei erkannter DTMF Sequenz abgespielt wird.
  1802. <li><a href="#sip_listen">sip_listen</a> (none , dtmf, wfp)</li>
  1803. <li><a name="#sip_ringtime">sip_ringtime</a><br>
  1804. Klingelzeit für eingehende Anrufe bei listen_for_dtmf
  1805. </li>
  1806. <li><a name="#sip_dtmf_size">sip_dtmf_size</a><br>
  1807. 1 bis 4 , default 2 Legt die L&auml;ge des erwartenden DTMF Events fest.
  1808. </li>
  1809. <li><a name="#sip_dtmf_loop">sip_dtmf_loop</a><br>
  1810. once oder loop , default once ...
  1811. </li>
  1812. <li><a name="#sip_waittime">sip_waittime</a><br>
  1813. Maximale Wartezeit im Status listen_for_wfp bis das Gespr&auml;ch automatisch angenommen wird.
  1814. </li>
  1815. <li>T2S_Device<br>
  1816. Name des Text2Speech Devices (Wird nur ben&ouml;tigt wenn Sprachnachrichten statt Audiofiles verwendet werden)
  1817. </li>
  1818. <li>T2S_Timeout<br>
  1819. Wartezeit in Sekunden wie lange maximal auf Text2Speech gewartet wird.
  1820. </li>
  1821. <li>audo_converter<br>sox oder ffmpeg, default sox<br>
  1822. Ist f&uml;r Text2Speech unbedingt erforderlich um die mp3 Dateien in Raw Audio umzuwandeln.<br>
  1823. Installation z.B. mit sudo apt-get install sox und noch die mp3 Unterst&uuml;tzung mit sudo apt-get install libsox-fmt-mp3
  1824. </li>
  1825. <li><a name="#sip_force_interval">sip_force_interval</a><br>
  1826. default 300
  1827. </li>
  1828. <li><a name="#sip_force_max">sip_force_max</a><br>
  1829. default 99
  1830. </li>
  1831. </ul>
  1832. <br>
  1833. </ul>
  1834. =end html_DE
  1835. =cut