Synchronous/Asynchrnous Audio play with pymedia

Ron Provost ronpro at cox.net
Sun Sep 18 19:22:59 EDT 2005


Hello,

I'm developing a piece of software to assist illiteraate adults to learn to 
read.  I'm trying to figure out how, if possible, to make audio playback 
asynchrnous but still controllable.  I'm using python 2.4 with pymedia on 
XP.  I started out with the example in the tutorials section of the pymedia 
website.  The pymedia docs imply to me that playback using Output's play() 
method should already be asynchronous and controllable.  I judge this 
because of the presence of the pause() and unpause() methods.  However, when 
I run the example I find that play() in fact is not returning until an 
entire frame has been played through the sound card.  This isn't entirely a 
problem since the frames are small, but I would prefer to give the entire 
sound file to the class and let it go on playing while I continue with other 
processing.  If, at some point during playback, I wish to pause, unpause or 
completely stop playback, I would like, again, to be able to make 
asynchronous calls to do so.  Doe anybody know if this is possible?  Am I 
using pymedia incorrectly?

I've attempted to construct a threaded class to handle my problem, but I'm a 
novice with threads and It's not working properly.  To use this class, first 
make an instance.  To assign an mp3 file for playback use myInst.select( 
myFileObj ).  To begin playback or to unpause use:  myInst.play( ).  to 
pause use:  myInst.pause( ).  to stop use:  myInst.stop( ).  Once stopped, 
myInst.play( ) should restart playback from the beginning.  The problem is 
that when I stop(), restarting with play() doesn't work.  Instead, the 
thread silently terminates.

Thanks for any help you can offer.  I've been trying to solve this on my own 
for days now and just know it shouldn't be this hard.




import time
import pymedia.audio.sound as sound
import pymedia.audio.acodec as acodec
import threading, Queue

class AudioPlayer( threading.Thread ):
   # States
   PLAY      =    1
   PAUSE     =    2
   STOP      =    3

   def __init__( self ):
      threading.Thread.__init__( self )

      self.setDaemon( 1 )
      self.requestQueue  = Queue.Queue( )
      self.start( )

   def select( self, filelikeObj ):
      self.requestQueue.put( filelikeObj )

   def play( self ):
      self.requestQueue.put( AudioPlayer.PLAY )

   def pause( self ):
      self.requestQueue.put( AudioPlayer.PAUSE )

   def stop( self ):
      self.requestQueue.put( AudioPlayer.STOP )

   def run( self ):
      state = AudioPlayer.STOP
      file  = None
      snd   = None

      while True:
         if (state == AudioPlayer.PLAY) and self.requestQueue.empty( ):
            if not snd:
               cparams= { 'id': acodec.getCodecID( 'mp3' ) }
               codec = acodec.Decoder( cparams )
               file.seek( 0 )
               bytes = file.read( 8192 )
               frame = codec.decode( bytes )
               snd = sound.Output( frame.sample_rate, frame.channels, 
sound.AFMT_S16_LE )
            else:
               bytes = file.read( 512 )
               if len(bytes) > 0:
                  frame = codec.decode( bytes )

            if frame:
               snd.play( frame.data )
            else:
               if snd:
                  snd.stop( )
               snd   = None
               state = AudioPlayer.STOP
         else:
            msg = self.requestQueue.get( )

            if msg in ( AudioPlayer.PAUSE, AudioPlayer.PLAY ):
               state = msg
            else:
               if snd:
                  snd.stop( )
               snd   = None
               state = AudioPlayer.STOP
               if msg != AudioPlayer.STOP:
                  file = msg

# Test application
if __name__ == '__main__':
   import time
   player = AudioPlayer( )
   snd = open( 'music.mp3', 'rb' )
   player.select( snd )
   player.play( )
   time.sleep( 3 )

   player.pause( )
   time.sleep( 3 )
   player.play( )
   time.sleep( 10 )
   player.stop( )
   time.sleep( 3 )
   player.play( )
 





More information about the Python-list mailing list