1 package Audio
::Play
::MPlayer
;
5 #use base qw(Class::Accessor::Fast);
6 use base
qw(Object::Accessor);
10 Audio::Play::MPlayer - a frontend to play audio files using MPlayer
14 use Audio::Play::MPlayer;
16 # same as Audio::Play::MPG123
17 $player = Audio::Play::MPlayer->new;
22 $player->load( "ex-mp30.mp3" );
23 print $player->title, "\n";
24 $player->poll( 1 ) until $player->state == 0;
28 This module acts as a frontend to an external MPlayer process started
29 with the C<-slave> command-line option. The idea and interface (and
30 in part the code) has been taken from L<Audio::Play::MPG123>.
32 Please see L<Audio::Play::MPG123> for the documentation. Take into account
48 have not been implemented, and that:
53 work differently: C<jump> takes offsets in seconds, and C<tpf> always
54 returns C<1> to make it possible to write:
56 $player->jump( 60 / $player->tpf );
60 use IPC
::Open3
qw(open3);
63 our $VERSION = '0.03';
66 # url type layer mode mode_extension copyrighted error_protected
68 #__PACKAGE__->mk_accessors( qw(frame title artist album year comment genre samplerate channels bitrate extension) );
69 #Object::Accessor->new( qw(frame title artist album year comment genre samplerate channels bitrate extension) );
71 #my $bool = $obj->mk_accessors( qw(frame title artist album year comment genre samplerate channels bitrate extension) );
74 my( $class, %args ) = @_;
75 my $self = bless \
%args, $class;
77 $self->start_mplayer( $args{mplayerargs
} );
80 $self->mk_accessors( qw(frame title artist album year comment genre samplerate channels bitrate extension) );
91 my( $self, $args ) = @_;
94 my $pid = open3
( $wr, $rd, $rd,
95 'mplayer', '-slave', '-idle', @
{$args || []} );
97 die "Can't start mplayer" unless $pid;
102 $self->{r
}->blocking( 0 );
103 $self->{frame
} = [ undef, undef, undef, undef ];
104 $self->{buffer
} = '';
110 return unless $self->{pid
};
111 $self->command( 'quit' );
112 my $pid = delete $self->{pid
};
113 close delete $self->{r
};
114 close delete $self->{w
};
119 my( $self, $wait ) = @_;
123 my $len = sysread $self->{r
}, $self->{buffer
}, 2048,
124 length( $self->{buffer
} );
125 return $1 if $self->{buffer
} =~ s/^([^\n\r]*)[\r\n]+//;
127 vec( my $rbits = '', fileno( $self->{r
} ), 1 ) = 1;
128 select $rbits, undef, undef, 60;
136 ( meta_title
=> [ 'get_meta_title', 'title', ],
137 meta_artist
=> [ 'get_meta_artist', 'artist', ],
138 meta_album
=> [ 'get_meta_album', 'album', ],
139 meta_year
=> [ 'get_meta_year', 'year', ],
140 meta_comment
=> [ 'get_meta_comment', 'comment', ],
141 meta_genre
=> [ 'get_meta_genre', 'genre', ],
144 # AUDIO: 44100 Hz, 2 ch, s16le, 128.0 kbit/9.07% (ratio: 16000->176400)
145 # A: 16.5 (16.4) of 252.3 (04:12.3) 3.6%
148 my( $self, $re, $wait ) = @_;
150 while( my $line = $self->line( $wait ) ) {
151 if( $line =~ /^A:\s+([\d\.]+)\s+\([\d\:\.]+\)\s+of\s+([\d\.]+)/ ) {
152 $self->{frame
}->[2] = $1;
153 $self->{frame
}->[3] = $2 - $1;
155 $self->{state} = 0 if $self->{frame
}->[3] <= 0;
156 } elsif( $line =~ /=====\s+PAUSE\s+=====/ ) {
158 } elsif( $line =~ /^ANS_(\w+)='([^']+)'$/ ) {
160 my( $k, $v ) = ( lc( $1 ), $2 );
163 $self->{$info{$k}->[1]} = $v;
165 } elsif( $line =~ /^AUDIO:\s+(\d+)/ ) {
166 $self->{samplerate
} = $1;
167 if( $line =~ /(\d+)\s+ch/i ) {
168 $self->{channels
} = $1;
170 if( $line =~ /(\d+)\.\d+\s+kbit/i ) {
171 $self->{bitrate
} = $1;
173 } elsif( $line =~ /^Playing\s/ ) {
174 $self->{$_->[1]} = undef foreach values %info;
175 $self->command( $_->[0] ) foreach values %info;
176 } elsif( $line =~ /^\s+(title|artist|album|year|comment|genre):\s(.*?)\s*$/i ) {
178 $self->{lc($1)} = $2;
180 # print STDERR $line, "\n";
182 return $line if $line =~ $re;
189 my( $self, $wait ) = @_;
191 $self->parse( qr/./, $wait ); # wait for anything
192 $self->parse( qr/^\0/, 0 ); # consume pending output
196 my( $self, $command ) = @_;
198 print { $self->{w
} } $command, "\n";
202 my( $self, $file ) = @_;
205 $self->command( qq{loadfile
"$file"} );
206 $self->{state} = 2; # feeling lucky
212 return $self->{state};
215 # FIXME works more-or-less
219 return if $self->{state} == 0;
220 $self->pause if $self->{state} == 2;
221 $self->command( 'pausing_keep seek 0.0 2' );
229 return if $self->{state} == 0;
230 $self->command( "pause" );
231 if( $self->{state} == 2 ) {
232 $self->parse( qr/=====\s+PAUSE\s+=====/, 1 );
233 # try to parse metatdata command answers
235 } elsif( $self->{state} == 1 ) {
240 sub paused
{ $_[0]->{state} == 2 ?
0 : 1 }
242 # FIXME not like Audio::Play::MPG123
244 my( $self, $seconds ) = @_;
246 if( $seconds && $seconds =~ /^[+\-]/ ) {
247 $self->command( "seek $seconds 0" );
249 $self->command( "seek $seconds 2" );
253 # Sets the player speed to current speed + delta
255 my( $self, $delta ) = @_;
257 return if $self->{state} == 0;
258 return if not defined $delta or $delta == 0;
260 $self->command( sprintf( "speed %.2f", $delta ) );
264 # mock Audio::Play::MPG123
269 Mattia Barbon <mbarbon@cpan.org>, using ideas from
270 L<Audio::Play::MPG123> by Marc Lehmann <schmorp@schmorp.de>.
274 This program is free software; you can redistribute it and/or
275 modify it under the same terms as Perl itself.
279 The latest sources can be found on GitHub at
280 L<http://github.com/mbarbon/audio-play-mplayer/tree>
284 Marc Lehmann <schmorp@schmorp.de> for L<Audio::Play::MPG123>.
286 The MP3 file used in tests has been taken from
287 L<http://www.shellworld.net/~davidsky/exam-mp3.htm> (test ID3 tag not
This page took 0.477874 seconds and 4 git commands to generate.