2 ############################################################################
3 # soepkiptngd_mobile (Soepkip The Next Generation daemon, Mobile version)
5 # (c) copyright 2001 Eric Lammerts <eric@lammerts.org>
8 ############################################################################
9 # This program is free software; you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License, version 2, as
11 # published by the Free Software Foundation.
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # A copy of the GNU General Public License is available on the World Wide Web
19 # at `http://www.gnu.org/copyleft/gpl.html'. You can also obtain it by
20 # writing to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 # Boston, MA 02111-1307, USA.
22 ############################################################################
24 # fork, and start soepkiptngd
25 # fork, and start funkey handler
26 # wait until soepkip is playing stuff, or timeout (timeout is needed when no preload is available)
36 # find program directory
39 my $l = readlink or die "readlink $_: $!\n";
40 if($l =~ m
|^/|) { $_ = $l; } else { s|[^/]*$|/$l|; }
43 my $progdir = abs_path
($1);
45 require "$progdir/soepkiptng.lib";
49 read_configfile
(\
%conf, $opt_c);
51 $mixerchannel = 'pcm';
55 return join(" ", split(//, $_[0]));
59 # (re)open database connection if necessary
61 $dbh = DBI
->connect("DBI:mysql:$conf{db_name}:$conf{db_host}",
62 $conf{db_user
}, $conf{db_pass
}) or do {
64 warn "Can't connect to database $conf{db_name}" .
65 "\@$conf{db_host} as user $conf{db_user}\n";
72 sub playlist_clear
() {
74 $dbh->do("DELETE FROM queue");
75 warn "playlist cleared.\n";
78 sub open_db_getnow
() {
80 my $now = get_nowplaying
($dbh) or do {
84 warn "now->{id}=$now->{id}\n";
88 sub playlist_addall_artist
() {
89 my $now = open_db_getnow
() or return;
91 my $songsref = $dbh->selectcol_arrayref(
92 "SELECT id FROM song WHERE present AND filename LIKE '/%' AND ".
93 "artist_id=$now->{arid} AND id != $now->{id} AND ".
94 "unix_timestamp(now()) - unix_timestamp(last_played) > ".
95 "$conf{min_random_time} ORDER BY RAND()");
96 warn "adding songs: " . join(",", @
{$songsref}) . ".\n";
97 return if @
{$songsref} == 0;
98 add_song
($dbh, "queue", '', @
{$songsref});
101 sub playlist_addall_album
($) {
102 my ($alltracks) = @_;
104 my $now = open_db_getnow
() or return;
105 $now->{track
} = -1 if $alltracks;
107 my $songsref = $dbh->selectcol_arrayref(
108 "SELECT song.id FROM song,album WHERE present AND filename LIKE '/%' AND ".
109 "song.album_id=album.id AND album.name <> '' AND ".
110 "album_id=$now->{alid} AND song.id != $now->{id} AND ".
111 "track > $now->{track} AND ".
112 "unix_timestamp(now()) - unix_timestamp(last_played) > ".
113 "$conf{min_random_time} ORDER BY track");
114 warn "adding songs: " . join(",", @
{$songsref}) . ".\n";
115 return if @
{$songsref} == 0;
116 add_song
($dbh, "queue", '', @
{$songsref});
121 shuffle_table
($dbh, "queue");
125 # return higest of (left, right) volume
127 my ($l, $r) = Audio
::Mixer
::get_cval
($mixerchannel);
128 return $l > $r?
$l : $r;
132 my ($incr, $abs) = @_;
142 $volume = getvol
() + $incr;
143 warn "volume=$volume\n";
146 if($incr == 0) { $muted = !$muted; }
147 if($abs) { $volume = $incr; $muted = 0; }
149 if($volume > 100) { $volume = 100; }
150 if($volume < 0) { $volume = 0; }
152 warn "setting volume, volume=$volume, muted=$muted\n";
153 say("volume " . numtext
($volume)) if $debug;
154 Audio
::Mixer
::set_cval
($mixerchannel, ($muted?
0 : $volume));
158 my $iaddr = inet_aton
($killhost) or return;
159 $paddr = sockaddr_in
($killport, $iaddr);
161 say("kill song $keypadvalue") if $debug;
162 if($keypadvalue && open_db
()) {
163 $dbh->do("LOCK TABLES queue WRITE, song READ");
164 my $res = $dbh->selectall_arrayref(
165 "SELECT song_id,song.track FROM queue " .
166 "LEFT JOIN song ON queue.song_id=song.id " .
167 "ORDER BY song_order");
170 last if $_->[1] == $keypadvalue;
171 push @goners, $_->[0];
173 warn sprintf "deleting songs up to track %d: %s\n", $keypadvalue, join(",", @goners);
174 del_song
($dbh, "queue", @goners);
175 $dbh->do("UNLOCK TABLES");
179 socket SOCK
, PF_INET
, SOCK_STREAM
, getprotobyname('tcp')
183 warn "killed song.\n";
191 open ST
, $conf{statusfile
} or return;
192 chop((undef, $filename) = <ST
>);
195 unlink $filename and killsong
();
200 $keypadvalue += $_[0];
201 push @keypadvalues, $_[0];
202 warn "keypadvalue=$keypadvalue\n";
208 warn "digit_reset\n";
214 foreach(@keypadvalues) {
215 say("dot command $_") if $debug;
222 playlist_addall_album
(1);
225 playlist_addall_album
(0);
228 playlist_addall_artist
();
232 if($debug == 3) { $debug = 0; }
233 say("deebug $debug");
250 say("reboot") if $debug;
257 if($killdelete >= 3) {
258 say("kill and delete") if $debug;
263 sub prepare_word
($) {
266 my $wavfile = "/tmp/soepkiptngd_mobile_say_$t.wav";
267 warn "say wavfile=$wavfile\n";
269 my $tmpfile = "/tmp/soepkiptngd_mobile_say.wav";
271 symlink $wavfile, $tmpfile;
275 open F
, "| text2wave -scale 5 -F 44100 -o $tmpfile";
279 warn "wavfile size=" . (-s
$wavfile) . " bytes.\n";
284 my ($t, $dontsplit) = @_;
289 @words = split /\s+/, $t;
292 # pause _before_ doing text2speech (to speed it up)
293 warn "kill -USR2 $cdrplaypid\n";
294 kill 'USR2', $cdrplaypid; # pause: make it close /dev/dsp
298 push @wavs, prepare_word
($_);
300 open PL
, "|cdrplay -w";
303 if(($pid = fork) == 0) {
304 open STDOUT
, ">&PL" or die;
311 warn "kill -HUP $cdrplaypid\n";
312 kill 'HUP', $cdrplaypid; # resume
317 my $now = get_nowplaying
($dbh) or do {
322 my $t = "$now->{artist} ... $now->{title}";
330 say("request song " . numtext
($keypadvalue))
332 add_song
($dbh, "queue", '', $keypadvalue);
333 warn "adding song: $keypadvalue.\n";
337 sub request_album
() {
338 my $alid = $keypadvalue;
341 my $songsref = $dbh->selectcol_arrayref(
342 "SELECT song.id FROM song,album WHERE present AND filename LIKE '/%' AND ".
343 "song.album_id=album.id AND album.id=$alid ".
346 warn "adding songs: " . join(",", @
{$songsref}) . ".\n";
347 return if @
{$songsref} == 0;
348 say("request album " . numtext
($alid) .
349 " found " . numtext
(scalar @
{$songsref}))
351 add_song
($dbh, "queue", '', @
{$songsref});
352 warn "adding song: @{$songsref}.\n";
355 sub request_artist
() {
356 my $arid = $keypadvalue;
359 my $songsref = $dbh->selectcol_arrayref(
360 "SELECT song.id FROM song,artist WHERE present AND filename LIKE '/%' AND ".
361 "song.artist_id=artist.id AND artist.id=$arid ".
364 warn "adding songs: " . join(",", @
{$songsref}) . ".\n";
365 say("request artist " . numtext
($arid) .
366 " found " . numtext
(scalar @
{$songsref}))
368 return if @
{$songsref} == 0;
369 add_song
($dbh, "queue", '', @
{$songsref});
370 warn "adding song: @{$songsref}.\n";
374 warn "funkeyd cdrplaypid=$cdrplaypid k=$killhost:$killport\n";
378 print STDERR
"settings keycodes:";
380 foreach(keys %conf) {
381 next unless /^funkey_(\d+)$/;
382 $keynum < 128 or die "too many funkeys defined!\n";
383 $loadkeys_input .= sprintf " keycode %d = U+%04x\n", $1, 0xfe00 + $keynum;
384 print STDERR
" $1=>$keynum";
385 $scancode{$keynum} = $1;
386 $funkey_handle{$keynum} = $conf{$_};
389 warn "---\n$loadkeys_input---\n";
391 if(open(F
, "|-") == 0) {
392 $ENV{'PATH'} = $mypath;
394 exec 'loadkeys', '-';
395 die "loadkeys: $!\n";
397 print F
$loadkeys_input;
398 warn "\nloadkeys wait\n";
401 warn "funkey fork\n";
404 $ENV{'PATH'} = $mypath;
405 open LOGERR
, ">>/tmp/soepkiptngd_mobile.out";
406 $SIG{__WARN__
} = sub {
410 printf LOGERR
"%s %s",
411 scalar localtime, $msg;
414 Audio
::Mixer
::init_mixer
();
415 open F
, "/dev/funkey" or die "/dev/funkey: $!\n";
418 $key = unpack "C", $key;
420 # skip autorepeated keys
421 next if $key == $prevkey;
424 # don't act on releasing a key
427 if(time - $lastkeytime > 10) {
429 warn "timeout -> digit_reset()\n";
434 warn "scancode $scancode{$key} keynum $key action $funkey_handle{$key}!\n";
435 eval $funkey_handle{$key};
440 sub wait_for_soepkiptng
() {
444 while((time - $starttime) < 15) {
445 if(open ST
, $conf{statusfile
}) {
446 chop((undef, undef, undef, $cdrplaypid, $killhost, $killport) = <ST
>);
448 last if $cdrplaypid && $killhost && $killport;
457 $SIG{__WARN__
} = sub {
463 $mypath = "/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/usr/local/sbin:$progdir:$progdir/bin";
464 warn "path=$mypath\n";
467 setvol
($conf{volume_init
}, 1) if $conf{volume_init
};
473 $ENV{'PATH'} = $mypath;
474 open LOGERR
, ">>/tmp/soepkiptngd_mobile.out";
475 $SIG{__WARN__
} = sub {
477 printf LOGERR
"%s %s",
478 scalar localtime, $_[0];
481 warn "hdparm -u1 -m16 -X66 -d1 /dev/hda\n";
482 system "hdparm -u1 -m16 -X66 -d1 /dev/hda";
483 warn "ifconfig lo\n";
484 system "ifconfig lo 127.0.0.1";
485 warn "hostname -F /etc/hostname\n";
486 system "hostname -F /etc/hostname";
488 warn "unlink $conf{statusfile}\n";
489 unlink $conf{statusfile
};
491 warn "starting soepkiptngd\n";
492 exec 'sched', 'soepkiptngd', '-d';
494 exec 'soepkiptngd', '-d';
495 warn "soepkiptngd: $!\n";
496 exec "$progdir/soepkiptngd", '-d';
497 die "$progdir/soepkiptngd: $!\n";
500 warn "wait_for_soepkiptng\n";
504 if(open ST
, $conf{statusfile
}) {
505 chop((undef, undef, undef, $cdrplaypid, $killhost, $killport) = <ST
>);
509 warn "killhost=$killhost:$killport\n";
520 warn "/sbin/init: $!\n";
523 warn "/bin/sh: $!\n";
525 # nothing else we can do