dabreegster has asked for the wisdom of the Perl Monks concerning the following question:
I'm trying to write a relatively simple music-playing server with queue features, similar to Moosic or MPD. Jigstar Music Daemon, or JMD, simply listens for an ALRM signal and executes the commands in a file. It's different because it can play a song, pause it, play another, then resume the first when the second is finished. It can do this in a pretty much infinite manner. Operations will only occur to the most recent version of MPG321. (the program I'm using to actually play the songs.)
I know MPG321 has a remote interface and that there's a POE module for controlling it, but it'd take a good deal more work because it can only play one song at once. I'm not experienced enough yet to construct a program that can do a real music queue yet. So I'm sticking with my current design. Here's the code of JMD. Be warned, it's not pretty and it doesn't run under strict.
To control it, echo a command to /tmp/jmd and send the ALRM signal to JMD. The commands should do the following: play ARGS: Pass args to a new MPG321 instance. If the current instance is running, pause it. Next: Advance the songs. Pause: Force the current song to pause. Resume: Force the current song to resume. Toggle: If paused, resume, and vice versa. Stop: Stop the current instance. Debug: Print the list of PIDs and their status. Usually pausing a song, playing another, then resuming the first won't work under Linux using OSS. The dsp device is locked. So I run esd to mix the silence of the paused songs and the music of the running song. The problem is simple: Pausing, resuming, stopping, and advancing to the next track won't work. Every function that sends a signal to the current MPG321 instance doesn't do what it should. There are no errors. I know the methods I am using are messy, but I also now that they work. An older version of JMD that didn't use fork() to start mpg321 did work. I cannot find the difference between the two. Any help, suggestions, or code is much appreciated. I can also be found on #perl on irc.freenode.net generally, under the alias 'dabreegster'. Thanks.#!/usr/bin/perl ######################## # Jigstar Music Daemon # ######################## #> #> = Temporary comment. #> Check for lock file to see if another instance of JMD is running. die "Error: Lock file exists!" if -e "/var/lock/jmd"; open LOCK, ">/var/lock/jmd"; print LOCK $$; close LOCK; #> Check to see if ESD is running. If not, start it. #> Remember, esdctl returns 1 if ESD isn't running. system("esdctl serverinfo >> /dev/null") and system("esd -nobeeps &") +; #> Exit cleanly when told to do so. $SIG{INT} = sub { #> Do I need to force my children to die so they won't become zombie +s? unlink "/var/lock/jmd", "/tmp/jmd"; system("killall esd"); exit; }; $SIG{QUIT} = $SIG{INT}; #> Use CHLD to simulate the 'done' thing. #> Declare subroutines. sub Play ($); sub Next (); sub Pause (); sub Resume (); sub Stop (); sub Debug (); #> When woken up by JMC, read the input and execute the commands. $SIG{ALRM} = sub { return unless -s "/tmp/jmd"; open INPUT, "/tmp/jmd"; chomp($Cmd = <INPUT>); close INPUT; open INPUT, ">/tmp/jmd"; print INPUT undef; close INPUT; $Cmd =~ s/^play // and Play $Cmd if $Cmd =~ m/^play /; Next if $Cmd eq "next"; Status == 1 ? Pause : Resume if $Cmd eq "toggle"; Pause if $Cmd eq "pause"; Resume if $Cmd eq "resume"; Stop if $Cmd eq "stop"; Debug if $Cmd eq "status"; $SIG{QUIT}->() if $Cmd eq "quit"; }; our @PIDs; sub Play ($) { my $Args = shift; Pause; #> Have MPG321 get all files from /root/mp3. Make it configurable lat +er. #> Change STDERR receiver. if (my $PID = fork()) { push @PIDs, $PID; } else { chdir "/root/mp3/"; exec("mpg321 -v $Args 2> /dev/tty12 &"); } } sub Next () { #> If it's stopped, resume it temporarily to change tracks. if (Status() == 2) { Resume; kill "INT", $PIDs[-1] if @PIDs; } kill "INT", $PIDs[-1] if @PIDs; } sub Pause () { kill "STOP", $PIDs[-1] if @PIDs; } sub Resume () { kill "CONT", $PIDs[-1] if @PIDs; } sub Stop () { kill 9, $PIDs[-1] if @PIDs; pop @PIDs; } sub Debug () { my $Counter = 0; for my $PID (@PIDs) { #> Print the ID, the PID, and the status. Don't need to check if not +hing is #> there, because there has to be. print "$Counter: $PID = " . Status($PID) . "\n"; $Counter++; } } #> Return status of a PID. 0 = Isn't running, 1 = Playing, & 2 = Pause +d. sub Status ($) { my $PID = shift || $PIDs[-1]; my $Line = +(split(/\n/, `ps $PID`))[1]; if ($Line !~ m/$PID/) { return 0; } elsif ($Line =~ m/T</) { return 2; } else { return 1; } } sleep while 1;
|
---|
Replies are listed 'Best First'. | |
---|---|
Re: Managing and sending signals to control MPG321
by valdez (Monsignor) on Apr 04, 2005 at 21:36 UTC | |
by dabreegster (Beadle) on Apr 04, 2005 at 22:35 UTC |
Back to
Seekers of Perl Wisdom