From f61743b3b3f90950f792106dd59263b5ba438656 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 27 Sep 2010 21:29:28 -0500 Subject: [PATCH 1/1] Adding support for other stream handlers in hopes to support Maemo 4.1 --- src/player.py | 6 +- src/stream.py | 145 ------------------------------------------- src/stream_gst.py | 146 ++++++++++++++++++++++++++++++++++++++++++++ src/stream_osso.py | 172 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 323 insertions(+), 146 deletions(-) delete mode 100644 src/stream.py create mode 100644 src/stream_gst.py create mode 100644 src/stream_osso.py diff --git a/src/player.py b/src/player.py index 1b1494e..b1871cd 100644 --- a/src/player.py +++ b/src/player.py @@ -3,7 +3,11 @@ import logging import gobject import util.misc as misc_utils -import stream +try: + import stream as _stream + stream = _stream # Silence PyFlakes +except ImportError: + import stream_gst as stream import stream_index import call_monitor diff --git a/src/stream.py b/src/stream.py deleted file mode 100644 index d584b65..0000000 --- a/src/stream.py +++ /dev/null @@ -1,145 +0,0 @@ -import logging - -import gobject -import gst - -import util.misc as misc_utils - - -_moduleLogger = logging.getLogger(__name__) - - -class GSTStream(gobject.GObject): - - STATE_PLAY = "play" - STATE_PAUSE = "pause" - STATE_STOP = "stop" - - __gsignals__ = { - 'state-change' : ( - gobject.SIGNAL_RUN_LAST, - gobject.TYPE_NONE, - (gobject.TYPE_STRING, ), - ), - 'eof' : ( - gobject.SIGNAL_RUN_LAST, - gobject.TYPE_NONE, - (gobject.TYPE_STRING, ), - ), - 'error' : ( - gobject.SIGNAL_RUN_LAST, - gobject.TYPE_NONE, - (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT), - ), - } - - - def __init__(self): - gobject.GObject.__init__(self) - #Fields - self._state = self.STATE_STOP - self._uri = "" - self._elapsed = 0 - self._duration = 0 - - #Set up GStreamer - self._player = gst.element_factory_make("playbin2", "player") - bus = self._player.get_bus() - bus.add_signal_watch() - bus.connect("message", self._on_message) - - #Constants - self._timeFormat = gst.Format(gst.FORMAT_TIME) - self._seekFlag = gst.SEEK_FLAG_FLUSH - - @property - def playing(self): - return self.state == self.STATE_PLAY - - @property - def has_file(self): - return 0 < len(self._uri) - - @property - def state(self): - state = self._player.get_state()[1] - return self._translate_state(state) - - def set_file(self, uri): - if self._uri != file: - self._invalidate_cache() - if self.state != self.STATE_STOP: - self.stop() - - self._uri = uri - self._player.set_property("uri", uri) - - def play(self): - if self.state == self.STATE_PLAY: - _moduleLogger.info("Already play") - return - _moduleLogger.info("Play") - self._player.set_state(gst.STATE_PLAYING) - self.emit("state-change", self.STATE_PLAY) - - def pause(self): - if self.state == self.STATE_PAUSE: - _moduleLogger.info("Already pause") - return - _moduleLogger.info("Pause") - self._player.set_state(gst.STATE_PAUSED) - self.emit("state-change", self.STATE_PAUSE) - - def stop(self): - if self.state == self.STATE_STOP: - _moduleLogger.info("Already stop") - return - self._player.set_state(gst.STATE_NULL) - _moduleLogger.info("Stopped") - self.emit("state-change", self.STATE_STOP) - - @property - def elapsed(self): - try: - self._elapsed = self._player.query_position(self._timeFormat, None)[0] - except: - pass - return self._elapsed - - @property - def duration(self): - try: - self._duration = self._player.query_duration(self._timeFormat, None)[0] - except: - _moduleLogger.exception("Query failed") - return self._duration - - def seek_time(self, ns): - self._elapsed = ns - self._player.seek_simple(self._timeFormat, self._seekFlag, ns) - - def _invalidate_cache(self): - self._elapsed = 0 - self._duration = 0 - - def _translate_state(self, gstState): - return { - gst.STATE_NULL: self.STATE_STOP, - gst.STATE_PAUSED: self.STATE_PAUSE, - gst.STATE_PLAYING: self.STATE_PLAY, - }.get(gstState, self.STATE_STOP) - - @misc_utils.log_exception(_moduleLogger) - def _on_message(self, bus, message): - t = message.type - if t == gst.MESSAGE_EOS: - self._player.set_state(gst.STATE_NULL) - self.emit("eof", self._uri) - elif t == gst.MESSAGE_ERROR: - self._player.set_state(gst.STATE_NULL) - err, debug = message.parse_error() - _moduleLogger.error("Error: %s, (%s)" % (err, debug)) - self.emit("error", err, debug) - - -gobject.type_register(GSTStream) diff --git a/src/stream_gst.py b/src/stream_gst.py new file mode 100644 index 0000000..0b6d959 --- /dev/null +++ b/src/stream_gst.py @@ -0,0 +1,146 @@ +import logging + +import gobject +import gst + +import util.misc as misc_utils + + +_moduleLogger = logging.getLogger(__name__) + + +class GSTStream(gobject.GObject): + + # @bug Advertising state changes a bit early, should watch for GStreamer state change + + STATE_PLAY = "play" + STATE_PAUSE = "pause" + STATE_STOP = "stop" + + __gsignals__ = { + 'state-change' : ( + gobject.SIGNAL_RUN_LAST, + gobject.TYPE_NONE, + (gobject.TYPE_STRING, ), + ), + 'eof' : ( + gobject.SIGNAL_RUN_LAST, + gobject.TYPE_NONE, + (gobject.TYPE_STRING, ), + ), + 'error' : ( + gobject.SIGNAL_RUN_LAST, + gobject.TYPE_NONE, + (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT), + ), + } + + + def __init__(self): + gobject.GObject.__init__(self) + #Fields + self._uri = "" + self._elapsed = 0 + self._duration = 0 + + #Set up GStreamer + self._player = gst.element_factory_make("playbin2", "player") + bus = self._player.get_bus() + bus.add_signal_watch() + bus.connect("message", self._on_message) + + #Constants + self._timeFormat = gst.Format(gst.FORMAT_TIME) + self._seekFlag = gst.SEEK_FLAG_FLUSH + + @property + def playing(self): + return self.state == self.STATE_PLAY + + @property + def has_file(self): + return 0 < len(self._uri) + + @property + def state(self): + state = self._player.get_state()[1] + return self._translate_state(state) + + def set_file(self, uri): + if self._uri != uri: + self._invalidate_cache() + if self.state != self.STATE_STOP: + self.stop() + + self._uri = uri + self._player.set_property("uri", uri) + + def play(self): + if self.state == self.STATE_PLAY: + _moduleLogger.info("Already play") + return + _moduleLogger.info("Play") + self._player.set_state(gst.STATE_PLAYING) + self.emit("state-change", self.STATE_PLAY) + + def pause(self): + if self.state == self.STATE_PAUSE: + _moduleLogger.info("Already pause") + return + _moduleLogger.info("Pause") + self._player.set_state(gst.STATE_PAUSED) + self.emit("state-change", self.STATE_PAUSE) + + def stop(self): + if self.state == self.STATE_STOP: + _moduleLogger.info("Already stop") + return + self._player.set_state(gst.STATE_NULL) + _moduleLogger.info("Stopped") + self.emit("state-change", self.STATE_STOP) + + @property + def elapsed(self): + try: + self._elapsed = self._player.query_position(self._timeFormat, None)[0] + except: + pass + return self._elapsed + + @property + def duration(self): + try: + self._duration = self._player.query_duration(self._timeFormat, None)[0] + except: + _moduleLogger.exception("Query failed") + return self._duration + + def seek_time(self, ns): + self._elapsed = ns + self._player.seek_simple(self._timeFormat, self._seekFlag, ns) + + def _invalidate_cache(self): + self._elapsed = 0 + self._duration = 0 + + def _translate_state(self, gstState): + return { + gst.STATE_NULL: self.STATE_STOP, + gst.STATE_PAUSED: self.STATE_PAUSE, + gst.STATE_PLAYING: self.STATE_PLAY, + }.get(gstState, self.STATE_STOP) + + @misc_utils.log_exception(_moduleLogger) + def _on_message(self, bus, message): + t = message.type + if t == gst.MESSAGE_EOS: + self._player.set_state(gst.STATE_NULL) + self.emit("eof", self._uri) + elif t == gst.MESSAGE_ERROR: + self._player.set_state(gst.STATE_NULL) + err, debug = message.parse_error() + _moduleLogger.error("Error: %s, (%s)" % (err, debug)) + self.emit("error", err, debug) + + +gobject.type_register(GSTStream) diff --git a/src/stream_osso.py b/src/stream_osso.py new file mode 100644 index 0000000..92e0ede --- /dev/null +++ b/src/stream_osso.py @@ -0,0 +1,172 @@ +import logging + +import gobject +import dbus + +import util.misc as misc_utils + + +_moduleLogger = logging.getLogger(__name__) + + +class SimplePlayer(gobject.GObject): + + STATE_PLAY = "play" + STATE_PAUSE = "pause" + STATE_STOP = "stop" + + __gsignals__ = { + 'state-change' : ( + gobject.SIGNAL_RUN_LAST, + gobject.TYPE_NONE, + (gobject.TYPE_STRING, ), + ), + 'eof' : ( + gobject.SIGNAL_RUN_LAST, + gobject.TYPE_NONE, + (gobject.TYPE_STRING, ), + ), + 'error' : ( + gobject.SIGNAL_RUN_LAST, + gobject.TYPE_NONE, + (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT), + ), + } + + _SERVICE_NAME = "com.nokia.osso_media_server" + _OBJECT_PATH = "/com/nokia/osso_media_server" + _AUDIO_INTERFACE_NAME = "com.nokia.osso_media_server.music" + + def __init__(self): + gobject.GObject.__init__(self) + #Fields + self._state = self.STATE_STOP + self._uri = "" + self._elapsed = 0 + self._duration = 0 + + #Event callbacks + self.on_playing_done = on_playing_done + + session_bus = dbus.SessionBus() + + # Get the osso-media-player proxy object + oms_object = session_bus.get_object( + self._SERVICE_NAME, + self._OBJECT_PATH, + introspect=False, + follow_name_owner_changes=True, + ) + # Use the audio interface + oms_audio_interface = dbus.Interface( + oms_object, + self._AUDIO_INTERFACE_NAME, + ) + self._audioProxy = oms_audio_interface + + self._audioProxy.connect_to_signal("state_changed", self._on_state_changed) + self._audioProxy.connect_to_signal("end_of_stream", self._on_end_of_stream) + + error_signals = [ + "no_media_selected", + "file_not_found", + "type_not_found", + "unsupported_type", + "gstreamer", + "dsp", + "device_unavailable", + "corrupted_file", + "out_of_memory", + "audio_codec_not_supported", + ] + for error in error_signals: + self._audioProxy.connect_to_signal(error, self._on_error) + + @property + def playing(self): + return self.state == self.STATE_PLAY + + @property + def has_file(self): + return 0 < len(self._uri) + + @property + def state(self): + return self._state + + def set_file(self, uri): + if self._uri != uri: + self._invalidate_cache() + if self.state != self.STATE_STOP: + self.stop() + + self._uri = uri + self._audioProxy.set_media_location(self._uri) + + def play(self): + if self.state == self.STATE_PLAY: + _moduleLogger.info("Already play") + return + _moduleLogger.info("Play") + self._audioProxy.play() + self._state = self.STATE_PLAY + self.emit("state-change", self.STATE_PLAY) + + def pause(self): + if self.state == self.STATE_PAUSE: + _moduleLogger.info("Already pause") + return + _moduleLogger.info("Pause") + self._audioProxy.pause() + self._state = self.STATE_PAUSE + self.emit("state-change", self.STATE_PLAY) + + def stop(self): + if self.state == self.STATE_STOP: + _moduleLogger.info("Already stop") + return + self._audioProxy.stop() + _moduleLogger.info("Stopped") + self._state = self.STATE_STOP + self.emit("state-change", self.STATE_STOP) + + @property + def elapsed(self): + pos_info = self._audioProxy.get_position() + if isinstance(pos_info, tuple): + self._elapsed, self._duration = pos_info + return self._elapsed + + @property + def duration(self): + pos_info = self._audioProxy.get_position() + if isinstance(pos_info, tuple): + self._elapsed, self._duration = pos_info + return self._duration + + def seek_time(self, ns): + _moduleLogger.debug("Seeking to: %s", ns) + self._audioProxy.seek( dbus.Int32(1), dbus.Int32(ns) ) + + def _invalidate_cache(self): + self._elapsed = 0 + self._duration = 0 + + @misc_utils.log_exception(_moduleLogger) + def _on_error(self, *args): + err, debug = "", repr(args) + _moduleLogger.error("Error: %s, (%s)" % (err, debug)) + self.emit("error", err, debug) + + @misc_utils.log_exception(_moduleLogger) + def _on_end_of_stream(self, *args): + self._state = self.STATE_STOP + self.emit("eof", self._uri) + + @misc_utils.log_exception(_moduleLogger) + def _on_state_changed(self, state): + # @todo Switch to updating/emitting state based on this + _moduleLogger.info("State: %s", state) + + +gobject.type_register(GSTStream) -- 1.7.9.5