dabreegster has asked for the wisdom of the Perl Monks concerning the following question:

I'm trying to write an MP3 daemon. After realizing Audio::Play::MPG123 must've been buggy somewhere, I decided to write my own interface to MPG321. And so here is Audio::Play::MPG321:
#!/usr/bin/perl package Audio::Play::MPG321; use strict; use warnings; use IPC::Open2; use IO::Select; $| = 1; sub new { my $class = shift; my ($read, $write); my $pid = open2($read, $write, "mpg321", "--aggressive", "--skip-printing-frames=39", "-R", "start"); my $handle = IO::Select->new($read); my $self = { pid => $pid, read => $read, write => $write, handle => $handle, song => undef, sofar => "0:00", remains => "0:00", state => 2 }; bless($self, $class); return $self; } sub poll { my $self = shift; while ($self->{handle}->can_read(0.5)) { my $in; sysread($self->{read}, $in, 1024); $self->parse($in); } } sub parse { my $self = shift; my $in = shift; if ($in =~ m/^\@P /) { $in =~ s/^\@P //; $self->{state} = $in; } elsif ($in =~ m/^\@F /) { $in =~ s/^\@F //; my ($sofar, $remains) = split(/ /, $in); $self->{sofar} = sprintf("%d:%02d", int($sofar / 60), $sofar % 60); $self->{remains} = sprintf("%d:%02d", int($remains / 60), $remains % + 60); } } sub play { my $self = shift; my $song = shift; print { $self->{write} } "load $song\n"; } sub state { my $self = shift; return $self->{state}; } sub toggle { my $self = shift; print { $self->{write} } "pause\n"; } sub pause { my $self = shift; print { $self->{write} } "pause\n" if $self->state() == 2; } sub resume { my $self = shift; print { $self->{write} } "pause\n" if $self->state() == 1; } sub seek { my $self = shift; my $position = shift; $position *= 39; print { $self->{write} } "jump $position\n"; } sub stop { my $self = shift; print { $self->{write} } "quit\n"; } 1; __END__
Note that I took the mpg321 source code and modified it in several ways to produce different output in -R (remote) mode. I did this simply for simplicity. Basically mpg321 will give the following types of output, which are read by poll() and parsed by parse(). @F x x # x are digits that show the number of seconds passed and the number remaining @P x # Where x is 0 (stopped), 1 (paused), or 2 (playing) The module works pretty well. The only problem I have is the single most frustrating bug I have ever encountered. If I pause it, the {state} of the player will change to 1. In resume(), I test for the return value of state(), which is simply an accessor for {state}, to be 1 (meaning the song is paused.) Oddly enough though, when the song is paused, resume has no effect! Why? I inserted a print statement before the test, and apparently $self->{state} magically returns to 2! I inserted print tests everywhere and found out nothing. The only places that {state} seemed to be set are in new(), which is only caused once, and in parse() when it encounters '@P x', but I made sure it's not being set incorrectly there with print statements. I have absolutely no clue what is going wrong. Any advice or code is appreciated. As always, I can be found on #perl, irc.freenode.net, alias dabreegster. Here's a client for A::P::M, if needed:
#!/usr/bin/perl $| = 1; use Audio::Play::MPG321; $player = new Audio::Play::MPG321; $SIG{CHLD} = 'IGNORE'; $SIG{INT} = sub { $player->stop(); exit 1; }; do { while (1) { $player->poll(); select(undef, undef, undef, 0.5); } } unless fork(); while (1) { print "\n> "; chomp(my $in = <STDIN>); my ($method, @args) = split(/\s+/, $in); $player->$method(@args); print $player->state(), "\n"; }

Considered by ewijaya; "There are too many similarity with this node written by the same author."
Unconsidered by davido: Keep votes blocked reaping. Also, node wasn't an exact duplicate.

Replies are listed 'Best First'.
Re: A very stubborn variable
by Roy Johnson (Monsignor) on May 27, 2005 at 03:40 UTC
    Could you watch the variable in the debugger? Or localize and tie it so that you could carp when it gets changed? See Re: detecting changes in a localised variable for more on that.

    Caution: Contents may have been coded under pressure.
Re: A very stubborn variable
by thcsoft (Monk) on May 27, 2005 at 03:57 UTC
    it would be fairer against the package's author if you inherited your package from it and overrode the respective methods.

    language is a virus from outer space.
      I'll watch the variable. And I'm not rewriting Audio::Play::MPG123, I'm writing Audio::Play::MPG321. Notice the numbers. Very little is the same among the two modules.
        I've got a bit of dyslexic tendancies, so I'll admit the difference between 123 and 321 in your original post was quite lost on me.

        If you are planning to submit to CPAN, a less confusing name might be something to carefully consider.

        -Scott