class PanucciPlayer(ForwardingObservableService): """ A proxy object which adds a layer of abstraction between all the different backends. It picks the right backend for the job and forwards signals from them. """ signals = [ "playing", "paused", "stopped", "eof" ] def __init__(self, config): self.__log = logging.getLogger('panucci.player.PanucciPlayer') ForwardingObservableService.__init__(self, self.signals, self.__log) self.config = config if self.config.get("options", "backend") == "gstreamer": from panucci.backends.gstreamer import Player elif self.config.get("options", "backend") == "gstreamer1": from panucci.backends.gstreamer1 import Player self.__player = Player() self.__initialized = False self._start_position = 0 # Forward the following signals self.forward(self.__player, [ "playing", "paused", "stopped", "eof" ], PanucciPlayer) #self.__player.register( "playing", self.on_playing ) self.__player.register( "paused", self.on_paused ) self.__player.register( "stopped", self.on_stopped ) self.__player.register( "eof", self.on_stopped ) self.__player.register( "error", self.on_player_error ) def __getattr__(self, attr): """ If the attribute isn't found in this object, get it from the player object. This makes proxying function calls simple and transparent. """ if self.__player is not None: return getattr(self.__player, attr) else: self.__log.critical("No player available") raise AttributeError def do_seek(self, from_beginning=None, from_current=None, percent=None): pos, dur = self.get_position_duration() pos_sec = max(0, pos / 10**9) dur_sec = max(0, dur / 10**9) if self.playing and self.current_uri: interface.PlaybackStopped(self._start_position, pos_sec, dur_sec, self.current_uri) # Hand over the seek command to the backend return self.__player.do_seek(from_beginning, from_current, percent) def on_playing(self, seek_to): """ Used to seek to the correct position once the file has started playing. This has to be done once the player is ready because certain player backends can't seek in any state except playing. """ if seek_to > 0: self._seek(seek_to) pos, dur = self.get_position_duration() pos_sec = pos / 10**9 dur_sec = dur / 10**9 interface.PlaybackStarted(pos_sec, self.current_uri) self._start_position = pos_sec def on_paused(self, *args): self.on_stopped_paused() def on_stopped(self, *args): self.on_stopped_paused() def on_stopped_paused(self): pos, dur = self.get_position_duration() pos_sec = max(0, pos / 10**9) dur_sec = max(0, dur / 10**9) if self.current_uri: interface.PlaybackStopped(self._start_position, pos_sec, dur_sec, self.current_uri) def on_stop_requested(self): self.stop() def on_reset_playlist(self): self.stop(True) self.__player.reset_position_duration() def on_player_error(self, msg): self.__log.error("Error: %s", msg)
class PanucciPlayer(ForwardingObservableService): """ A proxy object which adds a layer of abstraction between all the different backends. It picks the right backend for the job and forwards signals from them. """ signals = ["playing", "paused", "stopped", "eof"] def __init__(self, config): self.__log = logging.getLogger('panucci.player.PanucciPlayer') ForwardingObservableService.__init__(self, self.signals, self.__log) self.config = config if self.config.get("options", "backend") == "gstreamer": from panucci.backends.gstreamer import Player elif self.config.get("options", "backend") == "gstreamer1": from panucci.backends.gstreamer1 import Player self.__player = Player() self.__initialized = False self._start_position = 0 # Forward the following signals self.forward(self.__player, ["playing", "paused", "stopped", "eof"], PanucciPlayer) #self.__player.register( "playing", self.on_playing ) self.__player.register("paused", self.on_paused) self.__player.register("stopped", self.on_stopped) self.__player.register("eof", self.on_stopped) self.__player.register("error", self.on_player_error) def __getattr__(self, attr): """ If the attribute isn't found in this object, get it from the player object. This makes proxying function calls simple and transparent. """ if self.__player is not None: return getattr(self.__player, attr) else: self.__log.critical("No player available") raise AttributeError def do_seek(self, from_beginning=None, from_current=None, percent=None): pos, dur = self.get_position_duration() pos_sec = max(0, pos / 10**9) dur_sec = max(0, dur / 10**9) if self.playing and self.current_uri: interface.PlaybackStopped(self._start_position, pos_sec, dur_sec, self.current_uri) # Hand over the seek command to the backend return self.__player.do_seek(from_beginning, from_current, percent) def on_playing(self, seek_to): """ Used to seek to the correct position once the file has started playing. This has to be done once the player is ready because certain player backends can't seek in any state except playing. """ if seek_to > 0: self._seek(seek_to) pos, dur = self.get_position_duration() pos_sec = pos / 10**9 dur_sec = dur / 10**9 interface.PlaybackStarted(pos_sec, self.current_uri) self._start_position = pos_sec def on_paused(self, *args): self.on_stopped_paused() def on_stopped(self, *args): self.on_stopped_paused() def on_stopped_paused(self): pos, dur = self.get_position_duration() pos_sec = max(0, pos / 10**9) dur_sec = max(0, dur / 10**9) if self.current_uri: interface.PlaybackStopped(self._start_position, pos_sec, dur_sec, self.current_uri) def on_stop_requested(self): self.stop() def on_reset_playlist(self): self.stop(True) self.__player.reset_position_duration() def on_player_error(self, msg): self.__log.error("Error: %s", msg)
class PanucciPlayer(ForwardingObservableService): """ A proxy object which adds a layer of abstraction between all the different backends. It picks the right backend for the job and forwards signals from them. """ signals = [ "playing", "paused", "stopped", "eof" ] def __init__(self, playlist): self.__log = logging.getLogger('panucci.player.PanucciPlayer') ForwardingObservableService.__init__(self, self.signals, self.__log) self.config = playlist.config if self.config.get("options", "backend") == "gstreamer": from panucci.backends.gstreamer import Player self.__player = Player() self.__initialized = False self._start_position = 0 self._is_playing = False # Forward the following signals self.forward( self.__player, [ "playing", "paused", "stopped", "eof" ], PanucciPlayer ) self.__player.register( "playing", self.on_playing ) self.__player.register( "paused", self.on_stopped ) self.__player.register( "stopped", self.on_stopped ) self.__player.register( "eof", self.on_stopped ) self.__player.register( "error", self.on_player_error ) self.playlist = playlist self.playlist.register( 'new-track-loaded', self.on_new_track ) self.playlist.register( 'seek-requested', self.do_seek ) self.playlist.register( 'stop-requested', self.on_stop_requested ) self.playlist.register( 'reset-playlist', self.on_reset_playlist ) # Register the d-bus interface only once we're ready interface.register_player(self) def __getattr__(self, attr): """ If the attribute isn't found in this object, get it from the player object. This makes proxying function calls simple and transparent. """ if self.__player is not None: return getattr(self.__player, attr) else: self.__log.critical("No player available") raise AttributeError def add_bookmark_at_current_position( self, label=None ): """ Adds a bookmark at the current position Returns: (bookmark lable string, position in nanoseconds) """ default_label, position = self.get_formatted_position() label = default_label if label is None else label self.playlist.save_bookmark( label, position ) self.__log.info('Added bookmark: %s - %d', label, position) return label, position def get_formatted_position(self, pos=None): """ Gets the current position and converts it to a human-readable str. Returns: (bookmark lable string, position in nanoseconds) """ if pos is None: (pos, dur) = self.get_position_duration() text = util.convert_ns(pos) return (text, pos) def on_new_track(self): """ New track callback; stops the player and starts the new track. """ if self.playlist.current_filepath is not None: filepath = self.playlist.current_filepath if filepath.startswith('/'): filepath = 'file://' + filepath self.load_media(filepath) # This is just here to prevent the player from starting to play # when it is first opened. The first time this function is called it # doesn't run self.play(), but otherwise it will. if self.__initialized: self.play() self.__initialized = True def do_seek(self, from_beginning=None, from_current=None, percent=None): pos, dur = self.get_position_duration() pos_sec = max(0, pos / 10**9) dur_sec = max(0, dur / 10**9) if self._is_playing and self.current_file: interface.PlaybackStopped(self._start_position, pos_sec, dur_sec, self.current_file) self._is_playing = False # Hand over the seek command to the backend return self.__player.do_seek(from_beginning, from_current, percent) def on_playing(self): """ Used to seek to the correct position once the file has started playing. This has to be done once the player is ready because certain player backends can't seek in any state except playing. """ seek = self.playlist.play() if seek > 0: self._seek(seek) pos, dur = self.get_position_duration() pos_sec = pos / 10**9 dur_sec = dur / 10**9 interface.PlaybackStarted(pos_sec, self.current_file) self._start_position = pos_sec self._is_playing = True def on_stopped(self, *args): pos, dur = self.get_position_duration() pos_sec = max(0, pos / 10**9) dur_sec = max(0, dur / 10**9) if self.current_file is not None: interface.PlaybackStopped(self._start_position, pos_sec, dur_sec, self.current_file) self._is_playing = False @property def current_file(self): return self.playlist.current_filepath def on_stop_requested(self): self.playlist.stop( self.get_position_duration()[0] ) self.stop() self._is_playing = False def on_reset_playlist(self): self.on_stop_requested() self.__player.reset_position_duration() def on_player_error(self, msg): self.__log.error("Error: %s", msg)
class PanucciPlayer(ForwardingObservableService): """ A proxy object which adds a layer of abstraction between all the different backends. It picks the right backend for the job and forwards signals from them. """ signals = ["playing", "paused", "stopped", "eof"] def __init__(self, playlist): self.__log = logging.getLogger('panucci.player.PanucciPlayer') ForwardingObservableService.__init__(self, self.signals, self.__log) self.config = playlist.config if self.config.get("options", "backend") == "gstreamer": from panucci.backends.gstreamer import Player self.__player = Player() self.__initialized = False self._start_position = 0 self._is_playing = False # Forward the following signals self.forward(self.__player, ["playing", "paused", "stopped", "eof"], PanucciPlayer) self.__player.register("playing", self.on_playing) self.__player.register("paused", self.on_stopped) self.__player.register("stopped", self.on_stopped) self.__player.register("eof", self.on_stopped) self.__player.register("error", self.on_player_error) self.playlist = playlist self.playlist.register('new-track-loaded', self.on_new_track) self.playlist.register('seek-requested', self.do_seek) self.playlist.register('stop-requested', self.on_stop_requested) self.playlist.register('reset-playlist', self.on_reset_playlist) # Register the d-bus interface only once we're ready interface.register_player(self) def __getattr__(self, attr): """ If the attribute isn't found in this object, get it from the player object. This makes proxying function calls simple and transparent. """ if self.__player is not None: return getattr(self.__player, attr) else: self.__log.critical("No player available") raise AttributeError def add_bookmark_at_current_position(self, label=None): """ Adds a bookmark at the current position Returns: (bookmark lable string, position in nanoseconds) """ default_label, position = self.get_formatted_position() label = default_label if label is None else label self.playlist.save_bookmark(label, position) self.__log.info('Added bookmark: %s - %d', label, position) return label, position def get_formatted_position(self, pos=None): """ Gets the current position and converts it to a human-readable str. Returns: (bookmark lable string, position in nanoseconds) """ if pos is None: (pos, dur) = self.get_position_duration() text = util.convert_ns(pos) return (text, pos) def on_new_track(self): """ New track callback; stops the player and starts the new track. """ if self.playlist.current_filepath is not None: filepath = self.playlist.current_filepath if filepath.startswith('/'): filepath = 'file://' + filepath self.load_media(filepath) # This is just here to prevent the player from starting to play # when it is first opened. The first time this function is called it # doesn't run self.play(), but otherwise it will. if self.__initialized: self.play() self.__initialized = True def do_seek(self, from_beginning=None, from_current=None, percent=None): pos, dur = self.get_position_duration() pos_sec = max(0, pos / 10**9) dur_sec = max(0, dur / 10**9) if self._is_playing and self.current_file: interface.PlaybackStopped(self._start_position, pos_sec, dur_sec, self.current_file) self._is_playing = False # Hand over the seek command to the backend return self.__player.do_seek(from_beginning, from_current, percent) def on_playing(self): """ Used to seek to the correct position once the file has started playing. This has to be done once the player is ready because certain player backends can't seek in any state except playing. """ seek = self.playlist.play() if seek > 0: self._seek(seek) pos, dur = self.get_position_duration() pos_sec = pos / 10**9 dur_sec = dur / 10**9 interface.PlaybackStarted(pos_sec, self.current_file) self._start_position = pos_sec self._is_playing = True def on_stopped(self, *args): pos, dur = self.get_position_duration() pos_sec = max(0, pos / 10**9) dur_sec = max(0, dur / 10**9) if self.current_file is not None: interface.PlaybackStopped(self._start_position, pos_sec, dur_sec, self.current_file) self._is_playing = False @property def current_file(self): return self.playlist.current_filepath def on_stop_requested(self): self.playlist.stop(self.get_position_duration()[0]) self.stop() self._is_playing = False def on_reset_playlist(self): self.on_stop_requested() self.__player.reset_position_duration() def on_player_error(self, msg): self.__log.error("Error: %s", msg)