The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

POE::Wheel::Audio::Mad - POE Wheel implementing in-session non-blocking mpeg stream playing

SYNOPSIS

  use POE;
  use POE::Wheel::Audio::Mad;

  POE::Session->create(
  	inline_states => {
  		_start  => \&am_start,
  		message => \&am_message
  	}
  );
  
  sub am_start {
  	my ($kernel, $heap) = @_[KERNEL, HEAP];
  	
	## you may also specify decoder options,  listed below..
  	$heap->{wheel} = new POE::Wheel::Audio::Mad ( message_event => 'message' );
  	
  	$kernel->yield( 'decoder_open', { 
  		filename => '/path/to/some/stream.mp3', 
  		play     => 1 
  	});
  }
  
  sub am_message {
  	my ($kernel, $message) = @_[KERNEL, ARG0];
  	
  	if ($message->{id} eq 'INPUT_EOF_WARNING') {

  		print "finished..\n";

  		undef $heap->{wheel};
  		
  	} elsif ($message->{id} eq 'DECODER_FRAME_DATA') {

  		if (defined($message->{data}->{played})) {

	  		print "\rplayed: $message->{data}->{played}";

	  	}
  	}
  }
  
  $poe_kernel->run();
  exit();
  	

DESCRIPTION

POE::Wheel::Audio::Mad is an attempt to bring a naitive perl mpeg
decoder into a perl session.  This module was written to work as
a POE Wheel due to it's nature -- it simply playes mpeg streams --
you have to do the job of controlling the player and handling 
updates.  This really isn't your traditional wheel.

OPTIONS

These options may be specified as part of the call to the 
new() constructor,  and affect decoder behaviour.  
message_event
*REQUIRED*  Specifies which event in your session will be 
receiving event messages from the decoder.  See section
MESSAGES below for more information on what this will
mean.
output_close_on_pause
  If defined to a true value,  this will cause the decoder to
  physically close the output device when stream decoding is
  in the paused state.  This frees up the device for use by
  other applications.  Default:  false.
	
output_close_on_stop
If defined to a true value,  this will cause the decoder to 
physically close the output device when stream decoding is 
in the stopped state.  Default: true.
output_device
Specifies the complete path to the dsp device to open for
playing decoded audio.  Default: '/dev/dsp'
output_samplerate
Specifies the sampling rate to open the dsp device at.  If a
stream is not at this sampling rate Audio::Mad::Resample will
be used to up/down-sample the stream to match.  Any standard
sampling rate can be used.
mixer_device
Specifies the complete path to the mixer device to open for
manipulating sound levels.  Default: '/dev/mixer'
mixer_balance
Specifies the balance to set the mixer to once opened.  Any
value between 0 (full left) and 100 (full right) may be
used.  Default: 50 (center)
mixer_volume
Specifies the master volume to set the mixer to once opened.
Any value between 0 (mute) and 100 (full volume) may be
used.  Default: 50
mixer_pcm
Specifies the pcm volume to set the mixer to once opened.
Any value between 0 (mute) and 100 (full volume) may be
used.  Default: 60
decoder_progress_range
Specifies the denominator to use when returning the stream
progress index.  The duration in seconds is divided by this
number to determine playing unit size,  as each "unit" is
passed a progress message is generated indicating how many
units have been played.
decoder_play_on_open
If defined to a true value,  this will cause the decoder to
immediatly begin playing a stream once an 'open' command
has been issued for it.

STATES

POE::Wheel::Audio::Mad brings with it a large amount of
states that get defined in your session.  Most of these
states are used for controlling the decoder behaviour
or for querying information,  and they are listed below.
All of these states take a single hashref as their
argument,  the keys and expected values (if any) are 
listed as well.
decoder_shutdown
When called,  this state will halt all current decoding activities,
clean up it's internal state, release resources,  and send a 
message indicating the shutdown was successful.
decoder_open
Opens a stream,  scans it for validity and information,  then prepares
the decoder to begin playing.  Possible keys are:
stream
string containing the full pathname to the stream to be opened.
required.
play
boolean indicating wether the decoder should begin playing the
stream as soon as it's opened.  default:  [decoder_play_on_open]
decoder_play
Starts or resumes playing of the currently opened stream.
decoder_pause
Pauses playing on the current stream.  Decoding is halted,  the
input file remains open,  and the current file position is
preserved.
decoder_stop
Stops playing on the current stream.  Decoding is halted,  the
input file remains open,  but the current file position is 
set to the beginning of the stream.
decoder_seek
Seeks to a new position in the stream,  and resumes playing
at the new position.  The keys used are:
position
integer specifying the relative position to seek to.
required.
range
integer indiciating the denominator to use when determining
relative file offsets.  default:  the current value of the
decoder option 'decoder_progress_range', see OPTIONS.
For example:

to seek 25% past the beginning (if the stream is 500 seconds 
long,  this would start playing at 125 seconds):

$kernel->yield('decoder_seek', { position => 25, range => 100 });

to seek to a specific second,  use the desired second as
the position,  and the number of seconds in the stream
as the range:

$kernel->yield('decoder_seek', { position => 125, range => 500 });
decoder_set
Updates decoder options (above) and manipulates mixer values.
The following keys are all required to be present: 
type
string indicating which subsystem you wish to manipulate.
currently this is either 'option' for changing decoder
options,  or 'pcm' for manipulating the mixer.
key
string indicating the key,  or the name of the option
that you wish to set.  If you are changing decoder
options,  this is just the name of the option as listed
above.  If you are manipulating the mixer,  possible
values are:  'volume', 'pcm', or 'balance'.
value
value you wish to be assigned to the specified 
subsystem and key.
For example:

to alter a decoder option,  such as deactivating decoder_play_on_open:

$kernel->yield('decoder_set', { type => 'option', key => 'decoder_play_on_open', value => 0 });

to change the mixer volume,  such as setting the pcm volume to 75:

$kernel->yield('decoder_set', { type => 'mixer', key => 'pcm', value => 75 });
decoder_info
Causes the decoder to output information about one of it's subsystems.
You must specify a single key:
type
The name of a subsystem you would like to coherce into reporting
state information.  You may select one of:  'decoder',  'input',
or 'dsp'.  See section MESSAGES for help in parsing state
information.

MESSAGES

This wheel will send messages back to your session via the state
you specified in the option 'message_event'.  This state will 
be passed decoder messages,  one at a time,  in hashref format.

This hashref always has only two keys:  id,  and data.  'id' is
the identifier for the message.  Every message id used by the
decoder is listed below.  data is the payload corresponding to
this type of event.  It could possibly be of any type or value,
or possibly blank,  but it will always be defined.
DECODER_SHUTDOWN_SUCCESS
Emitted when a shutdown has been specifically asked for,  usually
by yielding to 'decoder_shutdown'.  After all files have been
closed,  the output device shutdown,  and resources freed this
state will be emitted to let users know the wheel is ready to
be destroyed.
DECODER_PLAY_FAILED
Emitted when the decoder is asked to play,  but no input file is
open.  
DECODER_PAUSE_FAILED
Emitted when the decoder is asked to pause,  but the decoder is
not currently playing.
DECODER_STOP_FAILED
Emitted when the decoder is asked to stop,  but the decoder is
not currently playing,  or currently has an input file open.
DECODER_STATUS_DATA
Emitted when the decoder changes state.  The data packet is
a hashref containing information about the new state.  
state
Currently the only key defined in the data packet,  it a 
textual description of the current decoder state. Possible 
values are:  'CLOSED', 'STOPPED', 'PLAYING', 'PAUSED'.
DECODER_FRAME_DATA
Emitted periodically while the decoder is processing a stream.
The data packet is a hashref which could contain one of the
following keys:
played
an integer indicating the number of seconds that have been 
played in the stream.  this gets printed every 500ms for
better accuracy,  as such,  the value may not change each
time it is printed.
progress
an integer indicating relative position within the stream.
the option 'decoder_progress_range' is used as a denominator
and applied to the length (in bytes) of the stream.
DECODER_FRAME_ERROR
Emitted when the decoder crosses an unrecoverable error 
while processing frames in the stream.  the data packet
contains a string with a short message about the error.
INPUT_OPEN_FAILED
Emitted when the decoder has been asked to open a file,
but couldn't find the file or locate a valid mepg stream
within the file.  the data packet contains a string with
a short message about the error.
INPUT_CLOSE_SUCCESS
Emitted when the decoder has successfully shutdown an 
input stream,  and is ready to open a new input 
stream.  the data packet contains a string with the
name of the file that was closed.
INPUT_STATUS_DATA
Emitted when the decoders input subsystem has changed 
state.  The data packet is a hashref,  and could contain
any of the following keys:
state
a string containing a description of the input systems new
state.  possible values are:  'OPEN' or 'CLOSED'.
filename
a string containing the name of the file the input system
has just changed state on.  If state was 'OPEN',  this file
was just opened,  if 'CLOSED',  this file was just closed.
INPUT_INFO_DATA
Emitted when new information about an input stream has just
become available.  Usually immediately after the stream has 
been opened.  the data packet is a hasref,  and could contain
any of the following:
s_frames
The number of frames calculated to be in this stream.
s_vbr
Boolean indicating wether the stream is variable or
constant bitrate.  false=CBR, true=VBR.
s_size
The number of bytes calculated to be in the stream.
s_duration
The duration of the stream in HH:MM:SS.DDD format.
s_bitrate
The calculated bitrate of this stream,  as an integer.
s_avgrate
The mean bitrate of this stream,  as an integer.
s_samplerate
The sampling rate of this stream.
s_mode
The stereo mode of this stream.
s_layer
The layer of this stream.
s_flags
The frame flags for this stream.
s_frame_duration
The duration of each individual frame in this stream.
xing_frames
The number of frames in this stream,  according to the Xing header.
xing_bytes
The number of bytes in this stream,  according to the Xing header.
INPUT_EOF_WARNING
Emitted when the decoder has come across an end-of-file contidition
on the input stream file.  the data packet is a string,  and contains
the name of the input stream file.
INPUT_CLOSE_WARNING
Emitted when the decoder has failed to call a close(2) on the input
stream filehandle.  
DSP_OPEN_SUCCESS
Emitted when the decoder has acquired the output device.  the data
packet is a string containing the path name of the device that has
been opened.
DSP_OPEN_FAILED
Emitted when the decoder has failed to acquire an output device.  It
either failed to open the device,  or set it's paramaters.  the data
packet is a string describing the error.
DSP_STATUS_DATA
Emitted when the output device has changed state.  the data packet
is a hashref containing information about the new state.
state
Currently the only defined key in the data packet,  it contains a 
textual description of the output subsystems state.  Possible
values are:  'CLOSED', 'OPEN'.

SEE ALSO

perl(1)

POE::Component::Audio::Mad::Dispatch(3) POE::Component::Audio::Mad::Handle(3)

Audio::Mad(3) Audio::OSS(3)

AUTHOR

Mark McConnell, <mischke@cpan.org>

COPYRIGHT AND LICENSE

Copyright 2003 by Mark McConnell

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself with the exception that you must also feel bad if you don't email me with your opinions of this module.