From e26a57c82b5b6a393d6bb4c198e685517ccef830 Mon Sep 17 00:00:00 2001 From: "adrian.sampson" Date: Wed, 4 Feb 2009 05:54:37 +0000 Subject: [PATCH] cleanup and docs --HG-- extra : convert_revision : svn%3A41726ec3-264d-0410-9c23-a9f1637257cc/trunk%4095 --- beets/player/__init__.py | 0 beets/player/bpd.py | 31 +++++++++++----------- beets/player/gstplayer.py | 56 ++++++++++++++++++++++++++++++++++----- 3 files changed, 64 insertions(+), 23 deletions(-) create mode 100644 beets/player/__init__.py diff --git a/beets/player/__init__.py b/beets/player/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/beets/player/bpd.py b/beets/player/bpd.py index e8554a1b9..3a69c743e 100755 --- a/beets/player/bpd.py +++ b/beets/player/bpd.py @@ -12,7 +12,6 @@ from beets import Library import sys - DEFAULT_PORT = 6600 PROTOCOL_VERSION = '0.12.2' BUFSIZE = 1024 @@ -41,12 +40,10 @@ ERROR_PLAYER_SYNC = 55 ERROR_EXIST = 56 - def debug(msg): print >>sys.stderr, msg - class Server(object): """A MPD-compatible music player server. @@ -96,15 +93,6 @@ class Server(object): """ return SuccessResponse() -class BGServer(Server): - """A `Server` using GStreamer to play audio and beets to store its - library. - """ - - def __init__(self, host, port=DEFAULT_PORT, libpath='library.blb'): - super(BGServer, self).__init__(host, port) - self.library = Library(libpath) - class Connection(object): """A connection between a client and the server. Handles input and output from and to the client. @@ -181,8 +169,6 @@ class Connection(object): """ cls(client, server).run() - - class Command(object): """A command issued by the client for processing by the server. """ @@ -250,8 +236,6 @@ class CommandList(list): return out - - class Response(object): """A result of executing a single `Command`. A `Response` is iterable and consists of zero or more lines of response data @@ -298,6 +282,21 @@ class SuccessResponse(Response): return RESP_OK +class BGServer(Server): + """A `Server` using GStreamer to play audio and beets to store its + library. + """ + + def __init__(self, host, port=DEFAULT_PORT, libpath='library.blb'): + import gstplayer + super(BGServer, self).__init__(host, port) + self.library = Library(libpath) + self.player = gstplayer.GstPlayer() + + def run(self): + super(BGServer, self).run() + self.player.run() + if __name__ == '__main__': BGServer('0.0.0.0', 6600, 'library.blb').run() \ No newline at end of file diff --git a/beets/player/gstplayer.py b/beets/player/gstplayer.py index 1effe9d59..bd14c4184 100755 --- a/beets/player/gstplayer.py +++ b/beets/player/gstplayer.py @@ -1,5 +1,9 @@ #!/usr/bin/env python +"""A wrapper for the GStreamer Python bindings that exposes a simple +music player. +""" + import gst import sys import time @@ -8,8 +12,27 @@ import thread import os class GstPlayer(object): + """A music player abstracting GStreamer's Playbin element. + + Create a player object, then call run() to start a thread with a + runloop. Then call play_file to play music. Use player.playing + to check whether music is currently playing. + + A basic play queue is also implemented (just a Python list, + player.queue, whose last element is next to play). To use it, + just call enqueue() and then play(). When a track finishes and + another is available on the queue, it is played automatically. + """ + def __init__(self): - # set up the Gstreamer player + """Initialize a player. + + Once the player has been created, call run() to begin the main + runloop in a separate thread. + """ + + # Set up the Gstreamer player. From the pygst tutorial: + # http://pygstdocs.berlios.de/pygst-tutorial/playbin.html self.player = gst.element_factory_make("playbin", "player") fakesink = gst.element_factory_make("fakesink", "fakesink") self.player.set_property("video-sink", fakesink) @@ -17,14 +40,18 @@ class GstPlayer(object): bus.add_signal_watch() bus.connect("message", self._handle_message) - # set up our own stuff + # Set up our own stuff. self.playing = False self.queue = [] def _get_state(self): + """Returns the current state flag of the playbin.""" + # gst's get_state function returns a 3-tuple; we just want the + # status flag in position 1. return self.player.get_state()[1] def _handle_message(self, bus, message): + """Callback for status updates from GStreamer.""" if message.type == gst.MESSAGE_EOS: # file finished playing if self.queue: @@ -40,20 +67,28 @@ class GstPlayer(object): self.playing = False def play_file(self, path): + """Immediately begin playing the audio file at the given + path. + """ self.player.set_state(gst.STATE_NULL) self.player.set_property("uri", "file://" + path) self.player.set_state(gst.STATE_PLAYING) self.playing = True def play(self): + """If paused, resume playback. Otherwise, start playing the + queue. + """ if self._get_state() == gst.STATE_PAUSED: self.player.set_state(gst.STATE_PLAYING) self.playing = True else: - # presumably, nothing is playing - self.play_file(self.queue.pop()) + # Nothing is playing. Start the queue. + if self.queue: + self.play_file(self.queue.pop()) def pause(self): + """Pause playback.""" self.player.set_state(gst.STATE_PAUSED) self.playing = False @@ -61,6 +96,12 @@ class GstPlayer(object): self.queue[0:0] = [path] # push to front def run(self): + """Start a new thread for the player. + + Call this function before trying to play any music with + play_file() or play(). + """ + # If we don't use the MainLoop, messages are never sent. gobject.threads_init() def start(): loop = gobject.MainLoop() @@ -68,16 +109,17 @@ class GstPlayer(object): thread.start_new_thread(start, ()) def block(self): - """Block until we stop playing.""" + """Block until playing finishes (the queue empties).""" while self.playing: time.sleep(1) + if __name__ == '__main__': - path = sys.argv[1] + # A very simple command-line player. Just give it names of audio + # files on the command line; these are all queued and played. p = GstPlayer() for path in sys.argv[1:]: p.enqueue(os.path.abspath(os.path.expanduser(path))) p.run() p.play() p.block() -