NAME
MPEG::MP3Play - Perl extension for playing back MPEG music
SYNOPSIS
use MPEG::MP3Play;
my $mp3 = new MPEG::MP3Play;
$mp3->open ("test.mp3");
$mp3->play;
$mp3->message_handler;
DESCRIPTION
This Perl module enables you to playback MPEG music.
This README and the documention cover version 0.08 of the MPEG::MP3Play module.
PREREQUISITES
Xaudio SDK
MPEG::MP3Play is build against the 3.0 version of the Xaudio SDK and uses the async interface of the Xaudio library.
I don't know if older versions will work properly. The SDK is not part of this distribution, so get and install it first (http://www.xaudio.com/).
Perl
I built and tested this module using Perl 5.005_03. It should work also with Perl 5.004_04 and above, but I did not test this. If someone builds MPEG::MP3Play successfully with other versions of Perl, plesase drop me a note.
Optionally used Perl modules
samples/play.pl uses Term::ReadKey if it's installed.
samples/handler.pl requires Term::ReadKey.
samples/gtk*.pl require Gtk.
DOWNLOADING
You can download MPEG::MP3Play from any CPAN mirror. You will find it in the following directories:
http://www.perl.com/CPAN/modules/by-module/MPEG/
http://www.perl.com/CPAN/modules/by-authors/id/J/JR/JRED/
You'll also find recent information and download links on my homepage:
http://www.netcologne.de/~nc-joernre/
INSTALLATION
First, generate the Makefile:
perl Makefile.PL
You will be prompted for the location of the Xaudio SDK. The directory must contain the include and lib subdirectories, where the Xaudio header and library files are installed.
make
make test
./runsample play.pl
./runsample handler.pl
./runsample gtk.pl
./runsample gtkhandler.pl
./runsample synopsis.pl
make install
SAMPLE SCRIPTS
There are some small test scripts in the samples directory. You can run these scripts before 'make install' with the runsample script (or directly with 'perl', after running 'make install'). For runsample usage: see above.
All scripts expect a mp3 file 'test.mp3' in the actual directory.
- play.pl
-
Textmodus playback. Displays the timecode. Simple volume control with '+' and '-' keys.
- handler.pl
-
Does generally the same as play.pl, but uses the builtin message handler. You'll see, that this solution is much more elegant. It requires Term::ReadKey.
This script makes use of the debugging facility and is best documented so far.
- gtk.pl
-
This script demonstrates the usage of MPEG::MP3Play with the Gtk module. It produces a simple window with a progress bar while playing back the test.mp3 file.
- gtkhandler.pl
-
This script does the same as gtk.pl but uses the builtin message handler concept instead of implementing message handling by itself. Advantage of using the builtin message handler: no global variables are necessary anymore.
- synopsis.pl
-
This one proves that the usage shown in the SYNOPSIS really works ;)
BASIC CONCEPT
The concept of the Xaudio async API is based on forking an extra process (or thread) for the MPEG decoding and playing. The parent process controls this process by sending and recieving messages. This message passing is asynchronous.
This module interface provides methods for sending common messages to the MPEG process, eg. play, pause, stop. Also it implements a message handler to process the messages sent back. Eg. every message sent to the subprocess will be acknowledged by sending back an XA_MSG_NOTIFY_ACK message (or XA_MSG_NOTIFY_NACK on error). Error handling must be set up by handling this messages.
CONSTRUCTOR / DEBUGGING
- new
-
$mp3 = new MPEG::MP3Play ( [ debug => 'err' | 'all' ] );
This is the constructor of this class. It optionally takes the argument 'debug' to set a debugging level. If debugging is set to 'err', XA_MSG_NOTIFY_NACK messages will be carp'ed. Additionally XA_MSG_NOTIFY_ACK messages will be carp'ed if debugging is set to 'all'.
The debugging is implemented by the methods msg_notify_ack and msg_notify_nack and works only if you use the builtin message handler. You can overload them to set up a private error handling (see chapter USING THE BUILTIN MESSAGE HANDLER for details)
- debug
-
$mp3->debug ( 'err' | 'all' | 'none' | '' );
With this method you can set the debugging level at any time. If you pass an empty string or 'none' debugging will be disabled.
CONTROL METHODS
The following methods control the audio playback. Internally they send messages to the Xaudio subsystem. This message passing is asynchronous. The result value of these methods indicates only if the message was sent, but not if it was successfully processed. Instead the Xaudio subsystem sends back acknowledge messages. See the chapter MESSAGE HANDLING for details and refer to the Xaudio documentation.
- open
-
$sent = $mp3->open ($filename);
Opens the MPEG file $filename. No playback is started at this time.
- close
-
$sent = $mp3->close;
Closes an opened file.
- exit
-
$sent = $mp3->exit;
The Xaudio thread or process will be canceled. Use this with care. If you attempt to read or send messages after using this, you'll get a broken pipe error.
Generally you need not to use $mp3->exit. The DESTROY method of MPEG::MP3play cleans up everything well.
- play
-
$sent = $mp3->play;
Starts playing back an opened file. Must be called after $mp3->open.
- stop
-
$sent = $mp3->stop;
Stops playing back a playing file. The player rewinds to the beginning.
- pause
-
$sent = $mp3->pause;
Pauses. $mp3->play will go further at the actual position.
- seek
-
$sent = $mp3->seek ($offset, $range);
Sets the play position to a specific value. $offset is the position relative to $range. If $range is 100 and $offset is 50, it will be positioned in the middle of the song.
- volume
-
$sent = $mp3->volume ($pcm_level, $master_level, $balance);
Sets volume parameters. Works only if playing is active. $pcm_level is the level of the actual MPEG audio stream. $master_level is the master level of the sound subsystem. Both values must be set between 0 (silence) and 100 (ear breaking loud).
A $balance of 50 is the middle, smaller is more left, higher is more right.
You can supply undef for any parameter above and the corresponding value will not change.
- set_player_mode
-
$sent = $mp3->set_player_mode ( $flag, ... )
This method sets flags that modify the player's behavior. It expects a list of XA_PLAYER_MODE_* constants. Currently supported constants are:
XA_PLAYER_MODE_OUTPUT_AUTO_CLOSE_ON_STOP XA_PLAYER_MODE_OUTPUT_AUTO_CLOSE_ON_PAUSE XA_PLAYER_MODE_OUTPUT_AUTO_CLOSE_ON_EOF
Refer to the Xaudio documentation for details about this flags.
You can import this constants to your namespace using the ':state' tag (see CONSTANTS section below).
SIMPLE MESSAGE HANDLING
There are two methods to retrieve messages from the Xaudio subsystem. You can use them to implement your own message handler. Alternatively you can use the builtin message handler, described in the next chapter.
- get_message
-
$msg_href = $mp3->get_message;
If there is a message in the players message queue, it will be returned as a hash reference immediately. This method will not block if there is no message. It will return undef instead.
- get_message_wait
-
$msg_href = $mp3->get_message_wait ( [$timeout] );
This method will wait max. $timeout microseconds, if there is no message in the queue. If $timeout is omitted it will block until the next message appears. The message will be returned as a hash reference.
The message hash
The returned messages are references to hashes. Please refer to the Xaudio SDK documentation for details. The message hashes are build 1:1 out of the structs (in fact a union) documented there, using _ as a seperator for nested structs.
(Simply use Data::Dumper to learn more about the message hashes, e.g. that the name of the internal message handler is stored as $msg_href->{_method_name} ;)
- set_notification_mask
-
$sent = $mp3->set_notification_mask ($flag, ...);
By default all messages generated by the Xaudio subsystem are sent to you. This method sends a message to block or unblock certain types of notification messages. It expects a list of XA_NOTIFY_MASK_* constants corresponding to the messages you want to recieve. You can import this constants to your namespace using the ':mask' tag (see CONSTANTS section below).
Valid notification mask flags are:
XA_NOTIFY_MASK_ERROR XA_NOTIFY_MASK_DEBUG XA_NOTIFY_MASK_PROGRESS XA_NOTIFY_MASK_ACK XA_NOTIFY_MASK_NACK XA_NOTIFY_MASK_PLAYER_STATE XA_NOTIFY_MASK_INPUT_STATE XA_NOTIFY_MASK_INPUT_CAPS XA_NOTIFY_MASK_INPUT_NAME XA_NOTIFY_MASK_INPUT_DURATION XA_NOTIFY_MASK_INPUT_POSITION_RANGE XA_NOTIFY_MASK_INPUT_POSITION XA_NOTIFY_MASK_INPUT_TIMECODE_GRANULARITY XA_NOTIFY_MASK_INPUT_TIMECODE XA_NOTIFY_MASK_INPUT_STREAM_INFO XA_NOTIFY_MASK_OUTPUT_STATE XA_NOTIFY_MASK_OUTPUT_NAME XA_NOTIFY_MASK_OUTPUT_VOLUME XA_NOTIFY_MASK_OUTPUT_BALANCE XA_NOTIFY_MASK_OUTPUT_PCM_LEVEL XA_NOTIFY_MASK_OUTPUT_MASTER_LEVEL XA_NOTIFY_MASK_OUTPUT_PORTS XA_NOTIFY_MASK_OUTPUT_CAPS XA_NOTIFY_MASK_CODEC_EQUALIZER XA_NOTIFY_MASK_FEEDBACK_EVENT
Note:
If debugging is set to 'err' you cannot unset the XA_NOTIFY_MASK_NACK flag. If debugging ist set to 'all' also unsetting XA_NOTIFY_MASK_NACK is impossible.
- get_command_read_pipe
-
$read_fd = $mp3->get_command_read_pipe;
This method returns the file descriptor of the internal message pipe as an integer. You can use this to monitor the message pipe for incoming messages, e.g. through Gdk in a Gtk application. See samples/gtk*.pl for an example about using this feature.
USING THE BUILTIN MESSAGE HANDLER
You can implement your own message handler based upon the methods described above. In many cases its easier to use the builtin message handler.
- message_handler
-
$mp3->message_handler ( [$timeout] );
This method implements a message handler for all messages the Xaudio subsystem sends. It infinitely calls $mp3->get_message_wait and checks if a method according to the recieved message exists. If the method exists it will be invoked with the object instance and the recieved message as parameters. If no method exists, the message will be ignored.
The infinite message loop exits, if a message method returns false. So, all your message methods must return true, otherwise the message_handler will exit very soon ;)
The names of the message methods are derived from message names (a complete list of messages is part of the Xaudio SDK documentation). The prefix XA_ will be removed, the rest of the name will be converted to lower case.
Example: the message handler method for
XA_MSG_INPUT_POSITION
is
$mp3->msg_input_position ($msg_href)
The message handler is called with two parameters: the object instance $mp3 and the $msg_href returned by the get_message_wait method.
Hint
It's implicitly said above, but I want to mention it explicitly: you must define your message handlers in the MPEG::MP3Play package, because they are methods of the MPEG::MP3Play class. So say 'package MPEG::MP3Play' before writing your handlers.
Naturally you can subclass the MPEG::MP3Play module and implement your message handlers this way. It's up to you.
Doing some work
If the parameter $timeout is set when calling $mp3->method_handler, $mp3->get_message_wait is called with this timeout value. Additionally the method $mp3->work ist invoked after waiting or processing messages, so you can implement some logic here to control the module. The work method should not spend much time, because it blocks the rest of the control process (not the MPEG audio stream, its processed in its own thread, respectively process).
If the work method returns false, the method handler exits.
- work
-
$mp3->work;
See explantation in the paragraph above.
- process_messages_nowait
-
$mp3->process_messages_nowait;
This method processes all messages in the queue using the invocation mechanism described above. It returns immediately when there are no messages to process. You can use this as an input handler for the Gtk::Gdk->input_add call, see samples/gtkhandler.pl for an example of this.
User data for the message handlers
Often it is necessary that the message handlers can access some user data, e.g. to manipulate a Gtk widget. There are two methods to set and get user data. The user data will be stored in the MPEG::MP3Play object instance, so it can easily accessed where the instance handle is available.
- set_user_data
-
$mp3->set_user_data ( $data );
This sets the user data of the $mp3 handle to $data. It is a good idea to set $data to a hash reference, so you can easily store a handful parameters.
Example:
$mp3->set_user_data ( { pbar_widget => $pbar, win_widget => $window, gdk_input_tag => $input_tag } );
- get_user_data
-
$data = $mp3->get_user_data;
This returns the data previously set with $mp3->set_user_data or undef, if no user data was set before.
DEFAULT MESSAGE HANDLERS
The module provides simple message handlers for some default behavior. You can overload them, if want to implement your own functionality.
- msg_notify_player_state
-
If the current file reaches EOF this handler returns false, so the message handler will exit.
- msg_notify_ack
-
If debugging is set to 'all' this handler will print the acknowledged message using carp.
- msg_notify_nack
-
If debugging is set to 'err' or 'all' this handler will print the not acknowledged message plus an error string using carp.
CONSTANTS
There are many, many constants defined in the Xaudio header files. E.g. the message codes are defined there as constants. MPEG::MP3Play knows all defined constants, but does not export them to the callers namespace by default.
MPEG::MP3Play uses the standard Exporter mechanisms to export symbols to your namespace. There are defined some tags to group the symbols (see Exporter manpage on how to use them):
- msg
-
This exports all symbols you need to do message handling on your own, particularly all message codes are exported here. Refer to the source code for a complete listing.
- state
-
XA_PLAYER_STATE_*, XA_INPUT_STATE_* and XA_OUTPUT_STATE_*. Use this to check the actual player state in a XA_MSG_NOTIFY_PLAYER_STATE message handler.
- mask
-
This are all notify mask constants. The're needed to specify a notification mask. (see set_notification_mask)
- error
-
All symbols for Xaudio error handling, incl. success code. I never needed them so far.
- misc
-
Some symbols cannot be assigned to the tags above. They're collected here (look into the source for a complete list).
Note:
If you use the builtin message handler mechanism, you need not to import message symbols to your namespace. Alle message handlers are methods of the MPEG::MP3Play class, so they can access all symbols directly.
No import to your namespace at all is needed unless you want to use $mp3->set_notification_mask or $mp3->set_player_mode!
TODO
- Win32 support
- support of the full Xaudio API, with input/output
modules, etc.
- documentation: more details about the messages
hashes
- runsample.bat for Win32
Ideas, code and any help are very appreciated.
BUGS
- samples/gtk*.pl throw some Gdk messages on exit.
(not really a MPEG::MP3Play bug, I fear it documents
that I'm a beginner in coding Gtk+ applications ;)
Who is able to fix this and is so kind to send me the
patch? ;)
- the runsample script currently works only under
Unix, it will fail under Win32
REPORTING BUGS
First check if you're using the most recent version of this module, maybe the bug you're about to report is already fixed.
If you find a bug please send me a report. I will fix this as soon as possible. You'll make my life easier if you provide the following information along with your bugreport:
- your OS and Perl version (please send me the output
of 'perl -V')
- exact version number of the Xaudio development kit
you're using (including libc version, if matters)
- for bug reports regarding the GTK+ functionality
I need the version number of your GTK+ library and
the version number of your Perl Gtk module.
If you have a solution to fix the bug you're welcome to send me a unified context diff of your changes, so I can apply them to the trunk. You'll get a credit in the Changes file.
If you have problems with your soundsystem (you hear nothing, or the sound is chopped up) please try to compile the sample programs that are part of the Xaudio development kit. Do they work properly? If not, this is most likely a problem of your sound configuration and not a MPEG::MP3Play issue. Please check the Xaudio documentation in this case, before contacting me. Thanks.
MPEG::MP3PLay APPLICATIONS
Also I'm very interested to know, if someone write applications based on this module. So don't hesitate to send me an email, if you like (or not like ;) this module.
TESTED ENVIRONMENTS
This section will list the environments where this module is known to function well:
- Perl 5.005_03 and Perl 5.004_04, Linux 2.0.33 and
Linux 2.2.10, Xaudio SDK 3.01 glibc6,
gtk+ 1.2.3, Perl Gtk 0.5121
AUTHOR
Joern Reder <joern@netcologne.de>
COPYRIGHT
Copyright (C) 1999 by Joern Reder, All Rights Reserved.
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
The Xaudio SDK is copyright by MpegTV,LLC. Please refer to the LICENSE text published on http://www.xaudio.com/.
SEE ALSO
perl(1), MPEG::MP3Info.