#!/usr/bin/perl # Play the data on STDIN as an MP3 # # TODO # ---- # Acl the queue # Accept and handle playlists, ogg files, etc. # Deal with newer ID3v2 tags properly. # Make this structured code. It's a mess. # # Jered Floyd takes very little credit for this code use Getopt::Std; # Get the MP3Info module from this directory, because I suck. unshift(@INC, "/usr/local/bin"); #require MP3::Info; #import MP3::Info; use MPEG::MP3Info; &use_winamp_genres(); # Attach infoagents outland system("/bin/athena/attach -n infoagents outland 2>&1 > /dev/null"); # Select the correct output device and set the volume system("/mit/outland/bin/audio_setdevice -out headphones -volume 100 2>&1 /dev/null"); # The command line we get from lpd is (no spaces between options and args): # -C lpr -C class # -A LPRng internal identifier # -H originating host # -J lpr -J jobname (default: list of files) # -L lpr -U username # -P logname # -Q queuename (lpr -Q) # -a printcap af (accounting file name) # -d printcap sd entry (spool dir) # -e print job data file name (currently being processed) # -h print job originiating host (same as -H) # -j job number in spool queue # -k print job control file name # -l printcap pl (page length) # -n user name (same as -L) # -s printcap sf (status file) # -w printcap pw (page width) # -x printcap px (page x dimension) # -y printcap py (page y dimension) # accounting file name # All the filter_options from lpd getopt('ACFHJLPQRZacdefhijklnprswxy', \%opts); # Status messages at start of playback open(ZEPHYR, '|/usr/bin/zwrite -d -n eichin -s "SIPB LPR MP3 spooler"'); print(ZEPHYR "User $opts{'n'} on host $opts{'H'} is playing:\n"); # So, the file we're currently processing is "-d/-e". # Do some magic to make sure it's an MP3, and get the important bits # to zephyr out. $magic0=''; open(DATAFILE, "$opts{'d'}/$opts{'e'}"); sysread(DATAFILE, $magic, 2); close(DATAFILE); # MPEG header is beshort &0xffe0 ($magic0, $magic1) = unpack("C2", $magic); if ((($magic0 & 0xff) == 0xff) && (($magic1 & 0xe0) == 0xe0)) { # MPEG audio file &play_mpeg_audio(\%opts); } else { printf(ZEPHYR "I don't think this is an MPEG audio file... %02x %02x\n", $magic0, $magic1); print ZEPHYR "I'm going to try playing it anyway, because I'm not smart enough to do\nanything else yet.\n"; &play_mpeg_audio(\%opts); } # Play an MPEG audio file sub play_mpeg_audio { # Retrieve those command line opts. my %opts = %{shift(@_)}; my %MPEGModes = ( 0 => "stereo", 1 => "joint-stereo", 2 => "dual-channel", 3 => "single-channel"); # If it's an MP3 file, try to extract useful data my $tag = get_mp3tag("$opts{'d'}/$opts{'e'}"); if (!$tag) { print ZEPHYR "No ID3 tag found\n"; print ZEPHYR "Filename: $opts{'J'}\n\n"; } else { printf(ZEPHYR "Title : %-30.30s Artist: %-30.30s\n", $tag->{TITLE}, $tag->{ARTIST}); printf(ZEPHYR "Album : %-30.30s Year : %-4.4s\n", $tag->{ALBUM}, $tag->{YEAR}); printf(ZEPHYR "Comment: %-30.30s Genre : %-30.30s\n\n", $tag->{COMMENT}, $tag->{GENRE}); } my $info = get_mp3info("$opts{'d'}/$opts{'e'}"); if (!$info) { print ZEPHYR "No MPEG header found\n"; } else { print ZEPHYR "MPEG $info->{VERSION} layer $info->{LAYER}, "; if ($info->{VBR}) { print ZEPHYR "VBR "; } print ZEPHYR "$info->{BITRATE} kbit/s, $info->{FREQUENCY} kHz "; print ZEPHYR $MPEGModes{$info->{STEREO}}; print ZEPHYR "\n\n"; printf ZEPHYR "Track length: %02d:%02ds\n", $info->{MM}, $info->{SS}; } close(ZEPHYR); # Play the file # mpg123 is a crock. If you don't give it -q, it needs to be on a pty # or it SEGVs. Really. system("/mit/infoagents/bin/mpg123 -q - 2>&1 /tmp/mpg123.out"); # Done. Status: open(ZEPHYR, '|/usr/athena/bin/zwrite -d -n -c sipb-auto -i sipbmp3 -s "SIPB LPR MP3 spooler"'); # Check if there were any errors open(MP3STATUS, "/tmp/mpg123.out"); if () { print ZEPHYR "Playback completed with the following errors:\n"; print ZEPHYR $_; while () { print ZEPHYR $_; } } else { print ZEPHYR "Playback completed successfully.\n"; } close(MP3STATUS); unlink(MP3STATUS); close(ZEPHYR); }