Hi all,

I have to control/manage/automatize a player (music) and I managed to do in
the following way.

I posting here to get feedback and also I liked the solution, so it can be
useful for others. ;-)

Firstly, I chose the mplayer as the player because of multi-platform and
multi-filetypes support. Also, it supports control commands in the stdin. I
have done the same technique using mpg123 as well.

The idea:

Run a class (subclass of threading.Thread) that its main loop stay polling
other process (mplyer or mpg123) and sends commands to them, also getting
data as current music, time elapsed and total time.

Keep in mind that it is my first time playing/coding with threads :-)

Ok! Show me the code!

http://pastebin.com/9nhf6FK0
The same below (who knows how long last a web service) :-)

# file: player.py

import threading
from subprocess import Popen, PIPE
from datetime import datetime



class MPG123Player(threading.Thread):
    daemon = True # added to make Ctrl-C and Ctrl-D work when running
python -i player.py

    def __init__(self, music=''):
        self.music = music
        threading.Thread.__init__(self)
        self._kill_me = False
        self.player = self.init_player()

    def finish_it(self):
        self._kill_me = True

    def init_player(self):
        return Popen(['mpg123', '--remote', self.music], shell=False,
stdout=PIPE, stdin=PIPE)

    def run(self):
        '''Thread method that is called when a Thread is started,
        this is the "main loop" of it'''
        try:
            self.player_loop()
        finally:
            self.quit()

    def play(self, music=''):
        music = music or self.music
        if music:
            cmd = 'LOAD ' + music
            self.player_cmd(cmd)

    def stop(self):
        self.player_cmd('STOP')

    def player_cmd(self, cmd):
        '''Protocol to talk to the mpg123 '''
        self.player.stdin.write(cmd + '\n')

    def quit(self):
        self.player.terminate()

    def player_loop(self):
        player = self.player

        self.play()

        while not self._kill_me:
            status = player.stdout.readline()
            '''here we have to keep reading the stdout, because if we don't
            read from it this buffer get full and the mpg123 stops working.

            I give from it because of this issue, mplayer.py has a better
approach
            '''
            #print status
            if status.startswith('@F'):
                cmd_name, cur_frame,  frames_left, cur_seconds,
seconds_left = status.split()
                if cmd_name == '@F' and cur_seconds == '0.00':
                    self.total_seconds = float(seconds_left)
                cur_seconds = float(cur_seconds)
                self.cur_seconds = cur_seconds


class Mplayer(threading.Thread, BasePlayer):
    daemon = True # added to make Ctrl-C and Ctrl-D work when running
python -i player.py

    def __init__(self, music=''):
        threading.Thread.__init__(self)

    def init_player(self):
        # it is using mplayer.py - https://github.com/baudm/mplayer.py
        return mplayer.Player(stderr=subprocess.PIPE)
        # but the basic idea is run the mplayer with this options, but
        # mplayer.py has some convenient api
        #
        #return Popen(['mplayer', '-slave', '-idle', #'-msglevel',
'global=4',
        #            '-quiet', 'nodefault-bindings', '-noconfig', 'all',
        #            self.music], shell=False, stdout=PIPE, stdin=PIPE,
        #            stderr=subprocess.STDOUT)

    def run(self):
        try:
            self.player_loop()
        finally:
            self.quit()

    def play(self, music=''):
        music = music or self.music
        if music:
            cmd = self.player.loadfile(music)
    def stop(self):
        self.player.stop()

    def quit(self):
        self.player.quit()
        #self.player.terminate()

    def player_loop(self):
        player = self.player

        while not self._kill_me:
            self.total_seconds = player.length or 0.0
            self.cur_seconds = player.time_pos or 0.0

            if (self.total_seconds - self.cur_seconds) <= 0.05:
                # if it's about to finish the music dispatch the logic to
get
                # the next music
                print '[%s] ended:' % datetime.now(), player.filename


player = Mplayer('/path/to/a/file/199.mp3')
#player = MPG123Player('199.mp3')

player.start()


# you can play with the player using python console
# python -i player.py
# >>> player.play('file')
# >>> player.stop()
# I put this file in my application/myapp/modules/player.py
# and in my controllers I can from player import player
# def index()
#     return '%s of %s' % (player.cur_seconds, player.total_seconds)

[],

-- 
Luciano Pacheco
blog.lucmult.com.br

Reply via email to