2 ############################################################################
3 # soepkiptngd_mobile (Soepkip The Next Generation daemon, Mobile version)
5 # (c) copyright 2001 Eric Lammerts <eric@lammerts.org>
7 ############################################################################
8 # This program is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License, version 2, as
10 # published by the Free Software Foundation.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # A copy of the GNU General Public License is available on the World Wide Web
18 # at `http://www.gnu.org/copyleft/gpl.html'. You can also obtain it by
19 # writing to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 # Boston, MA 02111-1307, USA.
21 ############################################################################
23 # fork, and start soepkiptngd
24 # fork, and start funkey handler
25 # wait until soepkip is playing stuff, or timeout (timeout is needed when no preload is available)
35 # find program directory
38 my $l = readlink or die "readlink $_: $!\n";
39 if($l =~ m
|^/|) { $_ = $l; } else { s|[^/]*$|/$l|; }
42 my $progdir = abs_path
($1);
44 require "$progdir/soepkiptng.lib";
48 read_configfile
(\
%conf, $opt_c);
50 $mixerchannel = 'pcm';
54 return join(" ", split(//, $_[0]));
58 # (re)open database connection if necessary
60 $dbh = DBI
->connect("DBI:mysql:$conf{db_name}:$conf{db_host}",
61 $conf{db_user
}, $conf{db_pass
}) or do {
63 warn "Can't connect to database $conf{db_name}" .
64 "\@$conf{db_host} as user $conf{db_user}\n";
71 sub playlist_clear
() {
73 $dbh->do("DELETE FROM queue");
74 warn "playlist cleared.\n";
77 sub open_db_getnow
() {
79 my $now = get_nowplaying
($dbh) or do {
83 warn "now->{id}=$now->{id}\n";
87 sub playlist_addall_artist
() {
88 my $now = open_db_getnow
() or return;
90 my $songsref = $dbh->selectcol_arrayref(
91 "SELECT id FROM song WHERE present AND filename LIKE '/%' AND ".
92 "artist_id=$now->{arid} AND id != $now->{id} AND ".
93 "unix_timestamp(now()) - unix_timestamp(last_played) > ".
94 "$conf{min_random_time} ORDER BY RAND()");
95 warn "adding songs: " . join(",", @
{$songsref}) . ".\n";
96 return if @
{$songsref} == 0;
97 add_song
($dbh, "queue", '', @
{$songsref});
100 sub playlist_addall_album
($) {
101 my ($alltracks) = @_;
103 my $now = open_db_getnow
() or return;
104 $now->{track
} = -1 if $alltracks;
106 my $songsref = $dbh->selectcol_arrayref(
107 "SELECT song.id FROM song,album WHERE present AND filename LIKE '/%' AND ".
108 "song.album_id=album.id AND album.name <> '' AND ".
109 "album_id=$now->{alid} AND song.id != $now->{id} AND ".
110 "track > $now->{track} AND ".
111 "unix_timestamp(now()) - unix_timestamp(last_played) > ".
112 "$conf{min_random_time} ORDER BY track");
113 warn "adding songs: " . join(",", @
{$songsref}) . ".\n";
114 return if @
{$songsref} == 0;
115 add_song
($dbh, "queue", '', @
{$songsref});
120 shuffle_table
($dbh, "queue");
124 # return higest of (left, right) volume
126 my ($l, $r) = Audio
::Mixer
::get_cval
($mixerchannel);
127 return $l > $r?
$l : $r;
131 my ($incr, $abs) = @_;
141 $volume = getvol
() + $incr;
142 warn "volume=$volume\n";
145 if($incr == 0) { $muted = !$muted; }
146 if($abs) { $volume = $incr; $muted = 0; }
148 if($volume > 100) { $volume = 100; }
149 if($volume < 0) { $volume = 0; }
151 warn "setting volume, volume=$volume, muted=$muted\n";
152 say("volume " . numtext
($volume)) if $debug;
153 Audio
::Mixer
::set_cval
($mixerchannel, ($muted?
0 : $volume));
157 my $iaddr = inet_aton
($killhost) or return;
158 $paddr = sockaddr_in
($killport, $iaddr);
160 say("kill song $keypadvalue") if $debug;
161 if($keypadvalue && open_db
()) {
162 $dbh->do("LOCK TABLES queue WRITE, song READ");
163 my $res = $dbh->selectall_arrayref(
164 "SELECT song_id,song.track FROM queue " .
165 "LEFT JOIN song ON queue.song_id=song.id " .
166 "ORDER BY song_order");
169 last if $_->[1] == $keypadvalue;
170 push @goners, $_->[0];
172 warn sprintf "deleting songs up to track %d: %s\n", $keypadvalue, join(",", @goners);
173 del_song
($dbh, "queue", @goners);
174 $dbh->do("UNLOCK TABLES");
178 socket SOCK
, PF_INET
, SOCK_STREAM
, getprotobyname('tcp')
182 warn "killed song.\n";
190 open ST
, $conf{statusfile
} or return;
191 chop((undef, $filename) = <ST
>);
194 unlink $filename and killsong
();
199 $keypadvalue += $_[0];
200 push @keypadvalues, $_[0];
201 warn "keypadvalue=$keypadvalue\n";
207 warn "digit_reset\n";
213 foreach(@keypadvalues) {
214 say("dot command $_") if $debug;
221 playlist_addall_album
(1);
224 playlist_addall_album
(0);
227 playlist_addall_artist
();
231 if($debug == 3) { $debug = 0; }
232 say("deebug $debug");
249 say("reboot") if $debug;
256 if($killdelete >= 3) {
257 say("kill and delete") if $debug;
262 sub prepare_word
($) {
265 my $wavfile = "/tmp/soepkiptngd_mobile_say_$t.wav";
266 warn "say wavfile=$wavfile\n";
268 my $tmpfile = "/tmp/soepkiptngd_mobile_say.wav";
270 symlink $wavfile, $tmpfile;
274 open F
, "| text2wave -scale 5 -F 44100 -o $tmpfile";
278 warn "wavfile size=" . (-s
$wavfile) . " bytes.\n";
283 my ($t, $dontsplit) = @_;
288 @words = split /\s+/, $t;
291 # pause _before_ doing text2speech (to speed it up)
292 warn "kill -USR2 $cdrplaypid\n";
293 kill 'USR2', $cdrplaypid; # pause: make it close /dev/dsp
297 push @wavs, prepare_word
($_);
299 open PL
, "|cdrplay -w";
302 if(($pid = fork) == 0) {
303 open STDOUT
, ">&PL" or die;
310 warn "kill -HUP $cdrplaypid\n";
311 kill 'HUP', $cdrplaypid; # resume
316 my $now = get_nowplaying
($dbh) or do {
321 my $t = "$now->{artist} ... $now->{title}";
329 say("request song " . numtext
($keypadvalue))
331 add_song
($dbh, "queue", '', $keypadvalue);
332 warn "adding song: $keypadvalue.\n";
336 sub request_album
() {
337 my $alid = $keypadvalue;
340 my $songsref = $dbh->selectcol_arrayref(
341 "SELECT song.id FROM song,album WHERE present AND filename LIKE '/%' AND ".
342 "song.album_id=album.id AND album.id=$alid ".
345 warn "adding songs: " . join(",", @
{$songsref}) . ".\n";
346 return if @
{$songsref} == 0;
347 say("request album " . numtext
($alid) .
348 " found " . numtext
(scalar @
{$songsref}))
350 add_song
($dbh, "queue", '', @
{$songsref});
351 warn "adding song: @{$songsref}.\n";
354 sub request_artist
() {
355 my $arid = $keypadvalue;
358 my $songsref = $dbh->selectcol_arrayref(
359 "SELECT song.id FROM song,artist WHERE present AND filename LIKE '/%' AND ".
360 "song.artist_id=artist.id AND artist.id=$arid ".
363 warn "adding songs: " . join(",", @
{$songsref}) . ".\n";
364 say("request artist " . numtext
($arid) .
365 " found " . numtext
(scalar @
{$songsref}))
367 return if @
{$songsref} == 0;
368 add_song
($dbh, "queue", '', @
{$songsref});
369 warn "adding song: @{$songsref}.\n";
373 warn "funkeyd cdrplaypid=$cdrplaypid k=$killhost:$killport\n";
377 print STDERR
"settings keycodes:";
379 foreach(keys %conf) {
380 next unless /^funkey_(\d+)$/;
381 $keynum < 128 or die "too many funkeys defined!\n";
382 $loadkeys_input .= sprintf " keycode %d = U+%04x\n", $1, 0xfe00 + $keynum;
383 print STDERR
" $1=>$keynum";
384 $scancode{$keynum} = $1;
385 $funkey_handle{$keynum} = $conf{$_};
388 warn "---\n$loadkeys_input---\n";
390 if(open(F
, "|-") == 0) {
391 $ENV{'PATH'} = $mypath;
393 exec 'loadkeys', '-';
394 die "loadkeys: $!\n";
396 print F
$loadkeys_input;
397 warn "\nloadkeys wait\n";
400 warn "funkey fork\n";
403 $ENV{'PATH'} = $mypath;
404 open LOGERR
, ">>/tmp/soepkiptngd_mobile.out";
405 $SIG{__WARN__
} = sub {
409 printf LOGERR
"%s %s",
410 scalar localtime, $msg;
413 Audio
::Mixer
::init_mixer
();
414 open F
, "/dev/funkey" or die "/dev/funkey: $!\n";
417 $key = unpack "C", $key;
419 # skip autorepeated keys
420 next if $key == $prevkey;
423 # don't act on releasing a key
426 if(time - $lastkeytime > 10) {
428 warn "timeout -> digit_reset()\n";
433 warn "scancode $scancode{$key} keynum $key action $funkey_handle{$key}!\n";
434 eval $funkey_handle{$key};
439 sub wait_for_soepkiptng
() {
443 while((time - $starttime) < 15) {
444 if(open ST
, $conf{statusfile
}) {
445 chop((undef, undef, undef, $cdrplaypid, $killhost, $killport) = <ST
>);
447 last if $cdrplaypid && $killhost && $killport;
456 $SIG{__WARN__
} = sub {
462 $mypath = "/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/usr/local/sbin:$progdir:$progdir/bin";
463 warn "path=$mypath\n";
466 setvol
($conf{volume_init
}, 1) if $conf{volume_init
};
472 $ENV{'PATH'} = $mypath;
473 open LOGERR
, ">>/tmp/soepkiptngd_mobile.out";
474 $SIG{__WARN__
} = sub {
476 printf LOGERR
"%s %s",
477 scalar localtime, $_[0];
480 warn "hdparm -u1 -m16 -X66 -d1 /dev/hda\n";
481 system "hdparm -u1 -m16 -X66 -d1 /dev/hda";
482 warn "ifconfig lo\n";
483 system "ifconfig lo 127.0.0.1";
484 warn "hostname -F /etc/hostname\n";
485 system "hostname -F /etc/hostname";
487 warn "unlink $conf{statusfile}\n";
488 unlink $conf{statusfile
};
490 warn "starting soepkiptngd\n";
491 exec 'sched', 'soepkiptngd', '-d';
493 exec 'soepkiptngd', '-d';
494 warn "soepkiptngd: $!\n";
495 exec "$progdir/soepkiptngd", '-d';
496 die "$progdir/soepkiptngd: $!\n";
499 warn "wait_for_soepkiptng\n";
503 if(open ST
, $conf{statusfile
}) {
504 chop((undef, undef, undef, $cdrplaypid, $killhost, $killport) = <ST
>);
508 warn "killhost=$killhost:$killport\n";
519 warn "/sbin/init: $!\n";
522 warn "/bin/sh: $!\n";
524 # nothing else we can do