1# 2# $Id: Vgetty.pm,v 1.4 2002/02/20 17:34:35 gert Exp $ 3# 4# Copyright (c) 1998 Jan "Yenya" Kasprzak <kas@fi.muni.cz>. All rights 5# reserved. This package is free software; you can redistribute it and/or 6# modify it under the same terms as Perl itself. 7# 8 9package Modem::Vgetty; 10 11use FileHandle; 12use POSIX; 13use strict; 14 15use Carp; 16 17use vars qw($testing $log_file $VERSION); 18 19$VERSION='0.03'; 20$testing = 0; 21$log_file = '/var/log/voicelog'; 22 23my @event_names = qw(BONG_TONE BUSY_TONE CALL_WAITING DIAL_TONE 24 DATA_CALLING_TONE DATA_OR_FAX_DETECTED FAX_CALLING_TONE 25 HANDSET_ON_HOOK LOOP_BREAK LOOP_POLARITY_CHANGE NO_ANSWER 26 NO_CARRIER 27 NO_DIAL_TONE NO_VOICE_ENERGY RING_DETECTED RINGBACK_DETECTED 28 RECEIVED_DTMF SILENCE_DETECTED SIT_TONE TDD_DETECTED 29 VOICE_DETECTED UNKNOWN_EVENT); 30 31 32 33sub new { 34 my ($class, $infd, $outfd, $pid) = @_; 35 my $self = bless {}, $class; 36 37 $infd ||= $ENV{'VOICE_INPUT'}; 38 $outfd ||= $ENV{'VOICE_OUTPUT'}; 39 $pid ||= $ENV{'VOICE_PID'}; 40 41 42 $self->{'IN'} = FileHandle->new_from_fd( $infd, "r" ) 43 || return; 44 $self->{'OUT'} = FileHandle->new_from_fd( $outfd, "w" ) 45 || return; 46 $self->{'IN'}->autoflush; 47 $self->{'OUT'}->autoflush; 48 49 $self->{'PIPE_BUF_LEN'} = POSIX::_POSIX_PIPE_BUF ; 50 51 $self->{'PID'} = $pid; 52 $self->{'LOG'} = FileHandle->new(); 53 54 if ($testing > 0) { 55 $self->{'LOG'}->open(">>$log_file") || return undef; 56 $self->{'LOG'}->autoflush; 57 $self->{'LOG'}->print("-----------\n### Pid $$ opening log\n----------\n"); 58 } 59 $self->{'EVENTS'} = { map { $_ => {} } @event_names }; 60 61 $self->init(); 62 63 return $self; 64 65} 66 67 68# The basic two functions (a low-level interface); 69sub receive { 70 my $self = shift; 71 my $input; 72 while(1) { 73 $input = $self->{IN}->getline; 74 chomp $input; 75 $self->{LOG}->print("received: $input\n") if $testing > 0; 76 last unless defined $self->{EVENTS}->{$input}; 77 # Handle the event: 78 my $dtmf = ''; 79 if ($input eq 'RECEIVED_DTMF') { 80 $dtmf = $self->{IN}->getline; 81 chomp $dtmf; 82 $self->{LOG}->print("DTMF $dtmf\n") if $testing > 0; 83 } 84 for (keys %{$self->{EVENTS}->{$input}}) { 85 $self->{LOG}->print("Running handler $_ for event $input\n") if $testing > 0; 86 &{$self->{EVENTS}->{$input}->{$_}}($self, $input, $dtmf); 87 $self->{LOG}->print("Handler $_ for event $input finished.\n") if $testing > 0; 88 } 89 } 90 $input; 91} 92 93sub send { 94 my $self = shift; 95 my $output = shift; 96 $self->{OUT}->print("$output\n"); 97 kill PIPE => $self->{PID}; 98 $self->{LOG}->print("sent: $output\n") if $testing > 0; 99} 100 101sub expect { 102 my $self = shift; 103 $self->{LOG}->print("expecting: ", (join '|', @_), "\n") 104 if $testing > 0; 105 my $received = $self->receive || return undef; 106 for my $expected (@_) { 107 return $received if $received eq $expected; 108 } 109 return undef; 110} 111 112sub waitfor { 113 my $self = shift; 114 my $string = shift; 115 while (($self->expect($string) || "") ne $string) { } 116} 117 118sub chat { 119 my $self = shift; 120 my @chatscript = @_; 121 my $received = 0; 122 for my $cmd (@chatscript) { 123 $received = 1 ^ $received; 124 next if $cmd eq ''; 125 if ($received == 1) { 126 return undef unless $self->expect($cmd); 127 128 } else { 129 $self->send($cmd); 130 } 131 } 132 return 1; 133} 134 135# Initial chat 136sub init { 137 my $self = shift; 138 $self->chat ('HELLO SHELL', 'HELLO VOICE PROGRAM', 'READY'); 139# $self->chat ('HELLO SHELL', 'HELLO VOICE PROGRAM'); 140 141 return $self; 142} 143 144# Setting the voice device 145sub device { 146 my $self = shift; 147 my $dev = shift; 148 $self->{LOG}->print("attempting to set device $dev") if $testing; 149 $self->chat ('', "DEVICE $dev", 'READY') || return undef; 150 $self->{DEVICE}=$dev; 151 $self->{LOG}->print("sucessfully set device $dev") if $testing; 152} 153 154sub shutdown { 155 my $self = shift; 156 $self->chat ('', 'GOODBYE', 'GOODBYE SHELL'); 157 $self->{IN}->close; 158 $self->{OUT}->close; 159 $self->{LOG}->close if $testing > 0; 160} 161 162sub DESTROY { 163 my $self = shift; 164 $self->shutdown; 165} 166 167sub enable_events { 168 my $self = shift; 169 $self->chat ('', 'ENABLE EVENTS', 'READY'); 170} 171 172sub disable_events { 173 my $self = shift; 174 $self->chat ('', 'DISABLE EVENTS', 'READY'); 175} 176 177sub beep { 178 my $self = shift; 179 my $freq = shift; 180 my $len = shift; 181 $self->chat ('', "BEEP $freq $len", 'BEEPING'); 182} 183 184sub dial { 185 my $self = shift; 186 my $num = shift; 187 $self->chat ('', "DIAL $num", 'DIALING'); 188} 189 190sub getty { 191 my $self = shift; 192 $self->chat ('', 'GET TTY') || return undef; 193 my $id = $self->receive; 194 $self->expect ('READY') || return undef; 195 return $id; 196} 197 198sub modem_type { 199# To be implemented in vgetty first. 200 return undef; 201} 202 203sub autostop { 204 my $self = shift; 205 my $arg = shift; 206 $self->chat ('', "AUTOSTOP $arg", 'READY'); 207} 208 209sub play { 210 my $self = shift; 211 my $file = shift; 212 $self->chat ('', "PLAY $file", 'PLAYING'); 213} 214 215sub record { 216 my $self = shift; 217 my $file = shift; 218 $self->chat ('', "RECORD $file", 'RECORDING'); 219} 220 221sub wait { 222 my $self = shift; 223 my $sec = shift; 224 $self->chat ('', "WAIT $sec", 'WAITING'); 225} 226 227sub stop { 228 my $self = shift; 229 $self->send ('STOP'); # Nechceme READY. 230} 231 232sub add_handler { 233 my $self = shift; 234 my $event = shift; 235 my $name = shift; 236 my $func = shift; 237 if (!defined($self->{EVENTS}->{$event})) { 238 $self->{LOG}->print("add_handler: unknown event $event\n") 239 if $testing > 0; 240 return undef; 241 } 242 $self->{EVENTS}->{$event}->{$name} = $func; 243} 244 245sub del_handler { 246 my $self = shift; 247 my $event = shift; 248 my $name = shift; 249 if (!defined($self->{EVENTS}->{$event})) { 250 $self->{LOG}->print("del_handler: unknown event $event\n") 251 if $testing > 0; 252 return undef; 253 } 254 if (!defined($self->{EVENTS}->{$event}->{$name})) { 255 $self->{LOG}->print("del_handler: trying to delete nonexistent handler $name\n") 256 if $testing > 0; 257 } else { 258 delete $self->{EVENTS}->{$event}->{$name}; 259 } 260} 261 262sub play_and_wait { 263 my $self = shift; 264 my $file = shift; 265 $self->play($file); 266 $self->waitfor('READY'); 267} 268 269##################################################################### 270# The readnum routine, its private variables and the event handler. # 271##################################################################### 272 273my $_readnum_number = ''; # The number itself. Filled in by the event handler. 274my $_readnum_timeout = 10; # The value of the timeout. Fileld in by readnum. 275my $_readnum_in_timeout = 1; # 'READY' from timeout or from the '#' key? 276 277# Event handler. Just adds key to the $_readnum_number. 278sub _readnum_event { 279 my $self = shift; 280 my $input = shift; # Unused. Should be 'RECEIVED_DTMF'. 281 my $dtmf = shift; 282 283 if ($dtmf eq '#') { # Stop the reading now. 284 $_readnum_in_timeout = 0; 285 $self->stop; 286 $self->{LOG}->print("_readnum_event(): Got #; stopping\n"); 287 return; 288 } 289 $_readnum_number .= $dtmf; 290 $self->stop; 291 $self->expect('READY'); 292 # Restart the wait again. 293 $_readnum_in_timeout = 1; 294 $self->wait($_readnum_timeout); 295} 296 297sub readnum { 298 my $self = shift; 299 my $message = shift; 300 my $timeout = shift; 301 my $times = shift; 302 $_readnum_number = ''; 303 $_readnum_in_timeout = 1; 304 $_readnum_timeout = $timeout if $timeout != 0; 305 $times = 3 if $times == 0; 306 307 # Install the handler. 308 $self->add_handler('RECEIVED_DTMF', 'readnum', \&_readnum_event); 309 while($_readnum_in_timeout != 0 && $_readnum_number eq '' 310 && $times-- > 0) { 311 $self->play_and_wait($message); 312 last if $_readnum_in_timeout == 0; 313 while ($_readnum_in_timeout != 0) { 314 $self->wait($_readnum_timeout); 315 $self->expect('READY'); 316 } 317 } 318 return undef if $times < 0; 319 $self->del_handler('RECEIVED_DTMF', 'readnum'); 320 $self->stop; 321 $self->expect('READY'); 322 $_readnum_number; 323} 324 3251; 326 327__END__ 328 329=head1 NAME 330 331Modem::Vgetty - interface to vgetty(8) 332 333=head1 SYNOPSIS 334 335 use Modem::Vgetty; 336 $v = new Modem::Vgetty; 337 338 $string = $v->receive; 339 $v->send($string); 340 $string = $v->expect($str1, $str2, ...); 341 $v->waitfor($string); 342 $rv = $v->chat($expect1, $send1, $expect2, $send2, ...); 343 344 $ttyname = $v->getty; 345 $rv = $v->device($dev_type); 346 $rv = $v->autostop($bool); 347 $rv = $v->modem_type; # !!! see the docs below. 348 349 $rv = $v->beep($freq, $len); 350 $rv = $v->dial($number); 351 $rv = $v->play($filename); 352 $rv = $v->record($filename); 353 $rv = $v->wait($seconds); 354 $rv = $v->play_and_wait($filename); 355 $v->stop; 356 357 $v->add_handler($event, $handler_name, $handler); 358 $v->del_handler($event, $handler_name); 359 $v->enable_events; 360 $v->disable_events; 361 362 $number = $v->readnum($message, $tmout, $repeat); 363 364 $v->shutdown; 365 366=head1 DESCRIPTION 367 368C<Modem::Vgetty> is an encapsulation object for writing applications 369for voice modems using the B<vgetty(8)> or B<vm(8)> package. The answering 370machines and sofisticated voice applications can be written using this 371module. 372 373=head1 OVERVIEW 374 375I<Voice modem> is a special kind of modem, which (besides the normal 376data and/or fax mode) can communicate also in voice mode. It means 377it can record sounds it hears from the phone line to the file, 378Play-back recorded files, it can beep to the line, and it can detect 379various standard sounds coming from the line (busy tone, silence, 380dual tone modulation frequency (DTMF) keypad tones, etc). 381An example of the voice modem can be the ZyXEL U1496, US Robotics 382Sportster (not Courier), etc. 383 384To use this software with the voice modem you need to have the 385B<vgetty(8)> package installed. B<Vgetty> is distributed as a part of 386B<mgetty> package. In fact, B<vgetty> is a B<mgetty(8)> with the voice 387extensions. Vgetty has some support for scripting - when it receives 388an incoming call, it runs a voice shell (it is program specified in 389the B<voice.conf> file) as its child process, establishes the read 390and write pipes to it, and tells it the number of the appropriate 391descriptors in the environment variables. Voice shell can now 392communicate with B<vgetty>. It can tell B<vgetty> "Play this file", 393or "Record anything you hear to that file", or "Notify me when 394user hangs up", etc. Sophisticated voice systems and answering 395machines can be build on top of B<vgetty>. 396 397B<mgetty> (including the B<vgetty>) is available at 398the following URL: 399 400 ftp://alpha.greenie.net/pub/mgetty/ 401 402Originally there was a (Bourne) shell interface to B<vgetty> only. 403The B<Modem::Vgetty> module allows user to write the voice shell in Perl. 404The typical use is to write a script and point the B<vgetty> to it 405(in B<voice.conf> file). The script will be run when somebody calls in. 406Another use is running voice shell from the B<vm(8)> program, which 407can for example dial somewhere and say something. 408 409=head1 QUICK START 410 411 #!/usr/bin/perl 412 use Modem::Vgetty; 413 my $v = new Modem::Vgetty; 414 $v->add_handler('BUSY_TONE', 'endh', sub { $v->stop; exit(0); }); 415 local $SIG{ALRM} = sub { $v->stop; }; 416 $v->enable_events; 417 $v->record('/tmp/hello.rmd'); 418 alarm(20); 419 $v->waitfor('READY'); 420 $v->shutdown; 421 422The above example installs the simple `exit now'-style handler for the 423B<BUSY_TONE> event (which is sent by B<vgetty> when user hangs up) 424and then records the B<hello.rmd> file. Put this text into a file 425and then point B<vgetty> to it in the B<voice.conf>. After you dial into 426your voice modem, you can record a 20-seconds of some message. 427Verify that B</tmp/hello.rmd> exists. Now delete the line contaning 428the word "record" and two subsequent lines and insert to the file 429the following line instead of them: 430 431 $v->play_and_wait('/tmp/hello.rmd'); 432 433Now call the voice modem and listen to the sounds you have just recorded. 434 435 436=head1 METHODS 437 438=head2 Begin and end of communication 439 440The B<Modem::Vgetty> object will initialize the communication pipes to 441the B<vgetty> at the creation time - in the constructor. The closing 442of the communication is done via the B<shutdown> method: 443 444 $v->shutdown; 445 446The module will call this method itself from the destructor, if you do 447not call it explicitly. 448 449=head2 Low-level communication 450 451Users probably don't want to use these methods directly. Use the higher-level 452functions instead. 453 454=over 4 455 456=item receive 457 458This method returns a string received from the B<vgetty>. It parses 459the string for the event types and runs appropriate event handlers. 460If event handler is run it waits for another string. 461 462=item send($string) 463 464This method sends the string B<$string> to the B<vgetty> process. 465 466=item expect($string1, $string2, ...) 467 468Receives a string from B<vgetty> (using the B<receive> method described 469above) and returns it iff it is equal to one of the strings in the argument 470list. When something different is received, this method returns B<undef>. 471 472=item waitfor($string) 473 474Waits until the string B<$sring> is received from B<vgetty> (using the 475B<receive> method described above). 476=item chat($expect1, $sent1, $expect2, $sent2, ...) 477 478A chat-script with B<vgetty>. Arguments are interpreted as the received-sent 479string pairs. A received string equals to the empty string means that no 480B<receive> method will be called at that place. This can be used for 481constructing chat scripts beginning with the sent string instead of the 482received one. 483 484=back 485 486=head2 Vgetty control methods 487 488There are miscellaneous methods for controllig B<vgetty> and querying its 489status. 490 491 492=over 4 493 494=item getty 495 496Returns the name of the modem special file (e.g. B</dev/ttyC4>). 497 498=item device($name) 499 500Sets the port of the voice modem input and output is done to. 501Possible values are qw(NO_DEVICE DIALUP_LINE EXTERNAL_MICROPHONE 502INTERNAL_SPEAKER LOCAL_HANDSET). 503 504=item autostop($bool) 505 506With autostop on, the voicelib will automatically abort a 507play in progress and return READY. This is useful for faster 508reaction times for voice menus. Possible arguments are qw(ON OFF). 509B<Note:> The interface should probably be changed to accept the 510Perl boolean arguments (undef, something else). Returns defined 511value on success, undef on failure. 512 513=item modem_type 514 515B<vgetty> currently has no way of telling voice shell 516the type of the current modem. This method is a proposed interface 517for determining this type. Currently returns B<undef>. The appropriate 518low-level interface has to be implemented in B<vgetty> first. 519 520=back 521 522=head2 Voice commands 523 524=over 4 525 526=item beep($freq, $len) 527 528Sends a beep through the chosen device using given frequency (HZ) and length 529(in miliseconds). 530Returns a defined value on success or undef on failure. 531The state of the vgetty changes to "BEEPING" and B<vgetty> 532returns "READY" after a beep is finshed. Example: 533 534 $v->beep(50,10); 535 # Possibly do something else 536 $v->waitfor('READY'); 537 538=item dial($number) 539 540Modem tries to dial a given number. The B<vgetty> changes its state 541to "DIALING" and returns "READY" after the dialing is finished. 542 543=item play($filename) 544 545The B<vgetty> tries to play the given file as a raw modem data. 546See the "Voice data" section for details on creating the raw modem data 547file. It changes the state to "PLAYING" and returns "READY" after 548playing the whole file. 549 550=item record($filename) 551 552The B<vgetty> records the voice it can hear on the line to the given file. 553It uses the raw modem data format (which can be re-played using the 554B<play> subroutine). B<vgetty> changes its state to "RECORDING" and 555you need to manually stop the recording using the B<stop> method 556after some time (or, you can set B<autostop> and wait for any event 557- silence, busy tone, etc). 558 559=item wait($seconds) 560 561The modem waits for a given number of seconds. Changes its state to 562"WAITING" and returns "READY" after the wait is finished. Example: 563 564 $v->wait(5); 565 $v->waitfor('READY'); 566 567=item stop 568 569The B<vgetty> stops anything it is currently doing and returns to the 570command state. You must use B<stop> when you want to call another 571B<beep>, B<dial>, B<play>, B<record> or B<wait> before the previous 572one is finished. The B<vgetty> returns "READY" after the B<stop> 573is called. So it is possible to interrupt a main routine waiting 574for "READY" from the event handler: 575 576 my $dtmf; 577 $v->add_handler('RECEIVED_DTMF', 'readnum', 578 sub { my $self=shift; $self->stop; $dtmf = $_[2]; }); 579 $v->enable_events; 580 $v->wait(10); 581 $v->waitfor('READY'); 582 583In the previous example the B<waitfor> method can be finished either by 584the 10-second timeout expired, or by the 'READY' generated by the 585B<stop> in the event handler. See also the B<Events> section. 586 587=item play_and_wait($file) 588 589It is an abbreviation for the following: 590 591 $v->play($file); 592 $v->waitfor('READY'); 593 594It is repeated so much time in the voice applications so I have decided 595to make a special routine for it. I may add the similar routines 596for B<dial>, B<record>, B<beep> and even B<wait> in the future releases. 597 598=back 599 600=head2 Event handler methods 601 602=over 4 603 604=item add_handler($event, $handler_name, $handler) 605 606Installs a call-back routine $handler for the event type $event. 607The call-back routine is called with three arguments. The first 608one is the Modem::Vgetty object itself, the second one is the 609event name and the third one is optional event argument. 610The B<$handler_name> argument can be anything. It is used when you 611want to delete this handler for identificating it. 612 613=item del_handler($event, $handler_name) 614 615This method deletes the handler $handler_name for the $event event. 616The result of unregistering the handler from the 617event handler of the same event is unspecified. It may or may not be 618called. 619 620=item enable_events 621 622Tells the B<vgetty> that the voice shell is willing to dispatch events. 623No events are sent by B<vgetty> until this method is called. 624 625=item disable_events 626 627Tells the B<vgetty> that the voice shell doesn't want to receive 628any events anymore. 629 630=back 631 632=head2 The B<readnum> method 633 634=over 4 635 636=item readnum($message, $tmout, $repeat) 637 638The applications often need to read the multi-digit 639number via the DTMF tones. This routine plays the B<$message> to the 640voice object and then waits for the 641sequence of the DTMF keys finished by the `#' key. If no key is pressed 642for B<$tmout> of seconds, it re-plays the message again. It returns 643failure if no key is pressed after the message is played B<$repeat>-th 644time. It returns a string (a sequence of DTMF tones 0-9,A-D and `*') 645without the final `#'. When some DTMF tones are received and no terminating 646`#' or other tone is received for B<$tmout> seconds, the routine returns 647the string it currently has without waiting for the final '#'. 648DTMF tones are accepted even at the time the B<$message> is played. 649When the DTMF tone is received, the playing of the B<$message> is 650(with some latency, of course) stopped. 651 652B<NOTE:> The interface of this routine can be changed in future releases, 653because I am not (yet) decided whether the current interface is the best one. 654See also the B<EXAMPLES> section where the source code of this routine 655(and its co-routine) is discussed. 656 657=back 658 659=head1 EVENTS 660 661=head2 Introduction 662 663Events are asynchronous messages sent by B<vgetty> to the voice shell. 664The B<Modem::Vgetty> module dispatches events itself in the B<receive> 665method. User can register any number of handlers for each event. 666When an event arrives, all handlers for that event are called (in no 667specified order). 668 669=head2 Event types 670 671At this time, the B<Modem::Vgetty> module recognizes the following 672event types (description is mostly re-typed from the B<vgetty> 673documentation): 674 675=over 4 676 677=item BONG_TONE 678 679The modem detected a bong tone on the line. 680 681=item BUSY_TONE 682 683The modem detected busy tone on the line (when dialing to the busy 684number or when caller finished the call). 685 686=item CALL_WAITING 687 688Defined in IS-101 (I think it is when the line receives another call-in 689when some call is already in progress. -Yenya). 690 691=item DIAL_TONE 692 693The modem detected dial tone on the line. 694 695=item DATA_CALLING_TONE 696 697The modem detected data calling tone on the line. 698 699=item DATA_OR_FAX_DETECTED 700 701The modem detected data or fax calling tones on the line. 702 703=item FAX_CALLING_TONE 704 705The modem detected fax calling tone on the line. 706 707=item HANDSET_ON_HOOK 708 709Locally connected handset went on hook. 710 711=item HANDSET_OFF_HOOK 712 713Locally connected handset went off hook. 714 715=item LOOP_BREAK 716 717Defined in IS-101. 718 719=item LOOP_POLARITY_CHANGE 720 721Defined in IS-101. 722 723=item NO_ANSWER 724 725After dialing the modem didn't detect answer for the time 726give in dial_timeout in voice.conf. 727 728=item NO_CARRIER 729 730The caller has hung up. This event is detected only by the ISDN4Linux 731driver. 732 733=item NO_DIAL_TONE 734 735The modem didn't detect dial tone (make sure your modem is 736connected properly to your telephone company's line, or check 737the ATX command if dial tone in your system differs from 738the standard). 739 740=item NO_VOICE_ENERGY 741 742It means that the modem detected voice energy at the 743beginning of the session, but after that there was a 744period of some time of silence (the actual time can be set using 745the B<rec_silence_len> and B<rec_silence_treshold> parameters 746in B<voice.conf>). 747 748=item RING_DETECTED 749 750The modem detected an incoming ring. 751 752=item RINGBACK_DETECTED 753 754The modem detected a ringback condition on the line. 755 756=item RECEIVE_DTMF 757 758The modem detected a dtmf code. The actual code value 759(one of 0-9, *, #, A-D) is given to the event handler as the 760third argument. 761 762=item SILENCE_DETECTED 763 764The modem detected that there was no voice energy at the 765beginning of the session and after some time of silence 766(the actual time can be set using 767the B<rec_silence_len> and B<rec_silence_treshold> parameters 768in B<voice.conf>). 769 770=item SIT_TONE 771 772Defined in IS-101. 773 774=item TDD_DETECTED 775 776Defined in IS-101. 777 778=item VOICE_DETECTED 779 780The modem detected a voice signal on the line. IS-101 does 781not define, how the modem makes this decision, so be careful. 782 783=item UNKNOWN_EVENT 784 785None of the above :) 786 787=back 788 789=head1 VOICE DATA 790 791Voice shell can send the voice data to the modem using the B<play> 792method and record them using the B<record> method. The ".rmd" extension 793(Raw Modem Data) is usually used for these files. The ".rmd" is not 794a single format - every modem has its own format (sampling frequency, 795data bit depth, etc). There is a B<pvftools> package for converting 796the sound files (it is a set of filters similar to the B<netpbm> for image 797files). The B<pvftormd(1)> filter can be used to create the RMD files 798for all known types of modems. 799 800=head1 EXAMPLES 801 802=head2 Answering machine 803 804A simple answering machine can look like this: 805 806 #!/usr/bin/perl 807 use Modem::Vgetty; 808 my $voicemaster = 'root@localhost'; 809 my $tmout = 30; 810 my $finish = 0; 811 my $v = new Modem::Vgetty; 812 $v->add_handler('BUSY_TONE', 'finish', 813 sub { $v->stop; $finish=1; }); 814 $v->add_handler('SILENCE_DETECTED', 'finish', 815 sub { $v->stop; $finish=1; }); 816 local $SIG{ALRM} = sub { $v->stop; }; 817 $v->enable_events; 818 $v->play_and_wait('/path/welcome.rmd'); 819 $v->beep(100,10); 820 $v->waitfor('READY'); 821 if ($finish == 0) { 822 my $num = 0; 823 $num++ while(-r "/path/$num.rmd"); 824 $v->record("/path/$num.rmd"); 825 alarm $tmout; 826 $v->waitfor('READY'); 827 } 828 system "echo 'Play with rmdtopvf /path/$num.rmd|pvftoau >/dev/audio'" . 829 " | mail -s 'New voice message' $voicemaster"; 830 exit 0; 831 832See the B<examples/answering_machine.pl> in the source distribution, 833which contains a more configurable version of the above text. 834It first sets the event handlers for the case of busy tone (the caller 835hangs up) or silence (the caller doesn't speak at all). The handler 836stops B<vgetty> from anything it is currently doing and sets the $finish 837variable to 1. Then the reception of the events is enabled and 838the welcome message is played. Then the answering machine beeps 839and starts to record the message. Note that we need to check the 840$finish variable before we start recording to determine if user 841hanged up the phone. Now we find the first filename <number>.rmd 842such that this file does not exist and we start to record the message 843to this file. We record until user hangs up the phone or until 844the timeout occurs. 845 846=head2 Readnum routine 847 848An interesting application of the low-level routines is the 849B<Voice::Modem::readnum> method. The calling sequence of this method 850has been discussed above. The source code for this routine and its 851co-routine will be discussed here, so that you can write your own 852variants of B<readnum> (which in fact does not have too general 853interface). See also the source code of B<Vgetty.pm> for the B<readnum> 854source. 855 856The B<readnum> routine needs to have its own event handler for the 857B<RECEIVED_DTMF> event and the way the handler can communicate with 858this routine. In our solution we use "static" variables: 859 860 my $_readnum_number = ''; 861 my $_readnum_timeout = 10; 862 my $_readnum_in_timeout = 1; 863 864The event handler will add the new character to the end of the 865B<$_readnum_number> variable. The B<$_readnum_timeout> is the number 866of seconds both B<readnum> and the event handler should wait for the 867next keypress, and the B<$_readnum_in_timeout> is a flag used by the 868event handler for notifying the main B<readnum> routine that it forced 869the B<vgetty> to emit the `READY' message because of the final `#' 870has been received. 871 872 sub _readnum_event { 873 my $self = shift; 874 my $input = shift; # Unused. Should be 'RECEIVED_DTMF'. 875 my $dtmf = shift; 876 877 if ($dtmf eq '#') { # Stop the reading now. 878 $_readnum_in_timeout = 0; 879 $self->stop; 880 $self->{LOG}->print("_readnum_event(): Got #; stopping\n"); 881 return; 882 } 883 $_readnum_number .= $dtmf; 884 $self->stop; 885 $self->expect('READY'); 886 # Restart the wait again. 887 $_readnum_in_timeout = 1; 888 $self->wait($_readnum_timeout); 889 } 890 891The event handler is installed for the `RECEIVED_DTMF' event only, so it 892doesn't need to check for the B<$input> value. The actual DTMF key is in 893the third parameter, B<$dtmf>. Note that the handler will be called 894when B<vgetty> is PLAYING or WAITING and the B<readnum> routine will 895be waiting for the `READY' message. This allows us to immediately 896interrupt waiting by the B<$self->stop> (which emits the `READY' message). 897So when the `#' DTMF tone is received, we send a B<stop> to B<vgetty>. 898If something else is received, we B<stop> the B<vgetty> too but we 899enter a new wait using B<$self->wait>. 900 901 sub readnum { 902 my $self = shift; 903 my $message = shift; 904 my $timeout = shift; 905 my $times = shift; 906 $_readnum_number = ''; 907 $_readnum_in_timeout = 1; 908 $_readnum_timeout = $timeout if $timeout != 0; 909 $times = 3 if $times == 0; 910 911 # Install the handler. 912 $self->add_handler('RECEIVED_DTMF', 'readnum', \&_readnum_event); 913 while($_readnum_in_timeout != 0 && $_readnum_number eq '' 914 && $times-- > 0) { 915 $self->play_and_wait($message); 916 last if $_readnum_in_timeout == 0; 917 while ($_readnum_in_timeout != 0) { 918 $self->wait($_readnum_timeout); 919 $self->expect('READY'); 920 } 921 } 922 return undef if $times < 0; 923 $self->del_handler('RECEIVED_DTMF', 'readnum'); 924 $self->stop; 925 $self->expect('READY'); 926 $_readnum_number; 927 } 928 929The B<readnum> routine just sets up the event handler, then plays 930the B<$message> and waits for the input (possibly several times). 931The main work is done in the event handler. At the end the handler 932is unregistered and the final value is returned. 933 934=head2 Callme script 935 936In the B<examples> subdirectory of the source distribution there is 937a B<callme.pl> script. This dials the given number and plays the 938given message. Use the following command to run it: 939 940 vm shell -S /usr/bin/perl callme.pl <number> <message>.rmd 941 942=head1 BUGS 943 944There may be some, but it will more likely be in the B<vgetty> itself. 945On the other hand, there can be typos in this manual (English is not my 946native language) or some parts of the interface that should be 947redesigned. Feel free to mail any comments on this module to me. 948 949=head1 TODO 950 951=over 4 952 953=item Modem type recognition 954 955The B<vgetty> should be able to tell the voice shell the name of the 956current modem type. 957 958=item The _wait() routines 959 960I need to implement the routines similar to B<play_and_wait> for other 961B<vgetty> states as well. 962 963=item Debugging information 964 965The module has currently some support for writing a debug logs 966(use the $Modem::Vgetty::testing = 1 and watch the /var/log/voicelog 967file). This needs to be re-done using (I think) Sys::Syslog. 968I need to implement some kind of log-levels, etc. 969 970=item Mgetty/Vgetty 1.1.17 971 972Need to figure out what is new in 1.1.17 (I use 1.1.14 now). I think 973new B<vgetty> can play more than one file in the single `PLAY' command, 974it (I think) have some support for sending voice data from/to the voice 975shell via the pipe, etc. 976 977=back 978 979=head1 AUTHOR 980 981The B<Modem::Vgetty> package was written by Jan "Yenya" Kasprzak 982<kas@fi.muni.cz>. Feel free to mail me any suggestions etc. 983on this module. Module itself is available from CPAN, but be sure 984to check the following address, where the development versions can 985be found: 986 987 http://www.fi.muni.cz/~kas/vgetty/ 988 989=head1 COPYRIGHT 990 991Copyright (c) 1998 Jan "Yenya" Kasprzak <kas@fi.muni.cz>. All rights 992reserved. This package is free software; you can redistribute it and/or 993modify it under the same terms as Perl itself. 994 995=cut 996 997