| 1 |
#!/usr/bin/perl |
|---|
| 2 |
|
|---|
| 3 |
# sphinx-netserver.pl |
|---|
| 4 |
# Copyright (c) 2005 Josh McAllister |
|---|
| 5 |
# |
|---|
| 6 |
# This program is free software; you can redistribute it and/or modify |
|---|
| 7 |
# it under the same terms as Perl itself. |
|---|
| 8 |
# |
|---|
| 9 |
# Written by Josh McAllister <josh208@gmail.com> |
|---|
| 10 |
|
|---|
| 11 |
use IO::Socket; |
|---|
| 12 |
use Symbol; |
|---|
| 13 |
use POSIX; |
|---|
| 14 |
use Proc::Daemon; |
|---|
| 15 |
use Config::Tiny; |
|---|
| 16 |
use FindBin; |
|---|
| 17 |
use Speech::Recognizer::SPX qw(:uttproc :fbs); |
|---|
| 18 |
|
|---|
| 19 |
# not used by anything $SPHINX_DIR='/usr/share/sphinx2'; |
|---|
| 20 |
my $config = Config::Tiny->read( $FindBin::Bin . '/etc/zoip.conf' ); |
|---|
| 21 |
my $SPHINX_MODELS = $FindBin::Bin . "/share/sphinx2"; |
|---|
| 22 |
|
|---|
| 23 |
# ensure that the language model and hmm directories exist before we proceed |
|---|
| 24 |
die "Missing language model $SPHINX_MODELS/model/lm/zork" unless ( -d "$SPHINX_MODELS/model/lm/zork" ); |
|---|
| 25 |
die "Missing hmm model $SPHINX_MODELS/model/hmm/communicator" unless ( -d "$SPHINX_MODELS/model/hmm/communicator" ); |
|---|
| 26 |
|
|---|
| 27 |
# Daemonize |
|---|
| 28 |
Proc::Daemon::Init if ( $config->{sphinx}->{daemonize} == 1 ); |
|---|
| 29 |
|
|---|
| 30 |
# establish SERVER socket, bind and listen. |
|---|
| 31 |
$server = IO::Socket::INET->new(LocalPort => $config->{sphinx}->{socket} || 1069, |
|---|
| 32 |
Type => SOCK_STREAM, |
|---|
| 33 |
Proto => 'tcp', |
|---|
| 34 |
Reuse => 1, |
|---|
| 35 |
Listen => 10 ) |
|---|
| 36 |
or die "making socket: $@\n"; |
|---|
| 37 |
|
|---|
| 38 |
# global variables |
|---|
| 39 |
$PREFORK = $config->{sphinx}->{children_prefork} || 2; # number of children to maintain |
|---|
| 40 |
$MAX_CLIENTS_PER_CHILD = $config->{sphinx}->{max_clients_per_child} || 50; # number of clients each child should process |
|---|
| 41 |
%children = (); # keys are current child process IDs |
|---|
| 42 |
$children = 0; # current number of children |
|---|
| 43 |
|
|---|
| 44 |
sub REAPER { # takes care of dead children |
|---|
| 45 |
$SIG{CHLD} = \&REAPER; |
|---|
| 46 |
my $pid = wait; |
|---|
| 47 |
$children --; |
|---|
| 48 |
delete $children{$pid}; |
|---|
| 49 |
} |
|---|
| 50 |
|
|---|
| 51 |
sub HUNTSMAN { # signal handler for SIGINT |
|---|
| 52 |
local($SIG{CHLD}) = 'IGNORE'; # we're going to kill our children |
|---|
| 53 |
kill 'INT' => keys %children; |
|---|
| 54 |
exit; # clean up with dignity |
|---|
| 55 |
} |
|---|
| 56 |
|
|---|
| 57 |
# Fork off our children. |
|---|
| 58 |
for (1 .. $PREFORK) { |
|---|
| 59 |
make_new_child(); |
|---|
| 60 |
} |
|---|
| 61 |
|
|---|
| 62 |
# Install signal handlers. |
|---|
| 63 |
$SIG{CHLD} = \&REAPER; |
|---|
| 64 |
$SIG{INT} = \&HUNTSMAN; |
|---|
| 65 |
|
|---|
| 66 |
# And maintain the population. |
|---|
| 67 |
while (1) { |
|---|
| 68 |
sleep; # wait for a signal (i.e., child's death) |
|---|
| 69 |
for ($i = $children; $i < $PREFORK; $i++) { |
|---|
| 70 |
make_new_child(); # top up the child pool |
|---|
| 71 |
} |
|---|
| 72 |
} |
|---|
| 73 |
|
|---|
| 74 |
sub make_new_child { |
|---|
| 75 |
my $pid; |
|---|
| 76 |
my $sigset; |
|---|
| 77 |
|
|---|
| 78 |
# block signal for fork |
|---|
| 79 |
$sigset = POSIX::SigSet->new(SIGINT); |
|---|
| 80 |
sigprocmask(SIG_BLOCK, $sigset) |
|---|
| 81 |
or die "Can't block SIGINT for fork: $!\n"; |
|---|
| 82 |
|
|---|
| 83 |
die "fork: $!" unless defined ($pid = fork); |
|---|
| 84 |
|
|---|
| 85 |
if ($pid) { |
|---|
| 86 |
# Parent records the child's birth and returns. |
|---|
| 87 |
sigprocmask(SIG_UNBLOCK, $sigset) |
|---|
| 88 |
or die "Can't unblock SIGINT for fork: $!\n"; |
|---|
| 89 |
$children{$pid} = 1; |
|---|
| 90 |
$children++; |
|---|
| 91 |
return; |
|---|
| 92 |
} else { #Child |
|---|
| 93 |
# Child can *not* return from this subroutine. |
|---|
| 94 |
$SIG{INT} = 'DEFAULT'; # make SIGINT kill us as it did before |
|---|
| 95 |
|
|---|
| 96 |
# unblock signals |
|---|
| 97 |
sigprocmask(SIG_UNBLOCK, $sigset) |
|---|
| 98 |
or die "Can't unblock SIGINT for fork: $!\n"; |
|---|
| 99 |
|
|---|
| 100 |
# Initialize sphinx |
|---|
| 101 |
fbs_init({-live => 'FALSE', |
|---|
| 102 |
-samp => 8000, |
|---|
| 103 |
-adcin => 'TRUE', |
|---|
| 104 |
-ctloffset => 0, |
|---|
| 105 |
-ctlcount => 100000000, |
|---|
| 106 |
-cepdir => "$SPHINX_MODELS/model/lm/zork", |
|---|
| 107 |
-datadir => "$SPHINX_MODELS/model/lm/zork", |
|---|
| 108 |
-agcmax => 'FALSE', |
|---|
| 109 |
-langwt => 6.5, |
|---|
| 110 |
-fwdflatlw => 8.5, |
|---|
| 111 |
-rescorelw => 9.5, |
|---|
| 112 |
-ugwt => 0.5, |
|---|
| 113 |
-fillpen => 1e-10, |
|---|
| 114 |
-silpen => 1e-10, #0.005, |
|---|
| 115 |
-inspen => 0.65, |
|---|
| 116 |
-top => 1, |
|---|
| 117 |
-topsenfrm => 3, |
|---|
| 118 |
-topsenthresh => -70000, |
|---|
| 119 |
-beam => 2e-06, |
|---|
| 120 |
-npbeam => 2e-06, |
|---|
| 121 |
-lpbeam => 2e-05, |
|---|
| 122 |
-lponlybeam => 0.0005, |
|---|
| 123 |
-nwbeam => 0.0005, |
|---|
| 124 |
-fwdflat => 'FALSE', |
|---|
| 125 |
-fwdflatbeam => 1e-08, |
|---|
| 126 |
-fwdflatnwbeam=> 0.0003, |
|---|
| 127 |
-bestpath => 'TRUE', |
|---|
| 128 |
-kbdumpdir => "$SPHINX_MODELS/model/lm/zork", |
|---|
| 129 |
-lmfn => "$SPHINX_MODELS/model/lm/zork/zork.lm", |
|---|
| 130 |
-dictfn => "$SPHINX_MODELS/model/lm/zork/zork.dic", |
|---|
| 131 |
-phnfn => "$SPHINX_MODELS/model/hmm/communicator/phone", |
|---|
| 132 |
-mapfn => "$SPHINX_MODELS/model/hmm/communicator/map", |
|---|
| 133 |
-hmmdir => "$SPHINX_MODELS/model/hmm/communicator", |
|---|
| 134 |
-hmmdirlist => "$SPHINX_MODELS/model/hmm/communicator", |
|---|
| 135 |
-ndictfn => "$SPHINX_MODELS/model/hmm/communicator/noisedict", |
|---|
| 136 |
'-8bsen' => 'TRUE', |
|---|
| 137 |
-sendumpfn => "$SPHINX_MODELS/model/hmm/communicator/sendump", |
|---|
| 138 |
-cbdir => "$SPHINX_MODELS/model/hmm/communicator"}); |
|---|
| 139 |
|
|---|
| 140 |
# handle connections until we've reached $MAX_CLIENTS_PER_CHILD |
|---|
| 141 |
for ($i=0; $i < $MAX_CLIENTS_PER_CHILD; $i++) { |
|---|
| 142 |
my $buf = undef; |
|---|
| 143 |
$client = $server->accept() or last; |
|---|
| 144 |
uttproc_begin_utt(); |
|---|
| 145 |
my $count = 0; |
|---|
| 146 |
my $datasize = readline $client; |
|---|
| 147 |
chomp $datasize; |
|---|
| 148 |
my $b = read ($client, my($buf), $datasize); |
|---|
| 149 |
#print "SERVER DEBUG: Expecting $datasize bytes, got $b bytes.\n"; |
|---|
| 150 |
uttproc_rawdata($buf, 1) or die "uttproc_rawdata failed"; |
|---|
| 151 |
uttproc_end_utt(); |
|---|
| 152 |
my ($fr, $hyp) = uttproc_result(1); |
|---|
| 153 |
#print "frames $fr\n"; |
|---|
| 154 |
print STDERR "SERVER RESULT: $hyp\n"; |
|---|
| 155 |
print $client "$hyp"; |
|---|
| 156 |
close $client; |
|---|
| 157 |
} |
|---|
| 158 |
# tidy up gracefully and finish |
|---|
| 159 |
|
|---|
| 160 |
# this exit is VERY important, otherwise the child will become |
|---|
| 161 |
# a producer of more and more children, forking yourself into |
|---|
| 162 |
# process death. |
|---|
| 163 |
fbs_end(); |
|---|
| 164 |
print STDERR "======= \n"; |
|---|
| 165 |
print STDERR "======= CHILD ENDED\n"; |
|---|
| 166 |
print STDERR "======= \n"; |
|---|
| 167 |
exit; |
|---|
| 168 |
} |
|---|
| 169 |
} |
|---|