diff --git a/mediacore-mediaserver b/mediacore-mediaserver index 188a82e..2b047f6 100755 --- a/mediacore-mediaserver +++ b/mediacore-mediaserver @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/python3 import mediaserver.mediaserver mediaserver.mediaserver.Run() \ No newline at end of file diff --git a/mediaserver/PKG_CONFIG.py b/mediaserver/PKG_CONFIG.py deleted file mode 100755 index 188b90e..0000000 --- a/mediaserver/PKG_CONFIG.py +++ /dev/null @@ -1,51 +0,0 @@ -# shared package configuration settings for applications in KHMedia -##### Common ##### - -# folder to store user specific configuration -user_cfg_folder = "~/.khmedia" - -# khmedia config file -config_file = "khmedia_config.xml" - -# khmedia example config resource -example_config_resource = "khmedia_config.example.xml" - -# location of the khsystem_need_config file -khsystem_need_config = "~/.khsystem_config_needed" - -##### Player ##### - -#default folders to look for song files (last in line is the fallback folder that will be created if none are existing) -default_song_folders = ["/usr/share/khmedia/songs","/usr/local/share/khmedia/songs","~/Songs"] - -#default folders to look for background music files (last in line is the fallback folder that will be created if none are existing) -default_music_folders = ["/usr/share/khmedia/music","/usr/local/share/khmedia/music","~/Music"] - -# files that are considered playable music files -music_extensions = [".mp3",".wav",".ogg",".m4b",".m4a"] - -# default volume for song playback (Linear 0.0 <= value <= 1.0 ) -default_song_volume = 0.5 - -# default volume for music playback (Linear 0.0 <= value <= 1.0 ) -default_music_volume = 0.12 - -##### Recorder ##### - -#default folder to store recordings -# You can use the following replacements -# {XDG_DESKTOP_DIR} -# {XDG_DOWNLOAD_DIR} -# {XDG_TEMPLATES_DIR} -# {XDG_PUBLICSHARE_DIR} -# {XDG_DOCUMENTS_DIR} -# {XDG_MUSIC_DIR} -# {XDG_PICTURES_DIR} -# {XDG_VIDEOS_DIR} - -# lowercase text between brackets is replaced by the corresponding text in the -# currently loaded translation table -# e.g. {something} can be replaced by "Something" or "Iets" if that is defined in the -# translation tabled -default_recordings_folder = "{XDG_DESKTOP_DIR}/{dir_recordings}" - diff --git a/mediaserver/__init__.py b/mediaserver/__init__.py index aee403e..64cd19c 100755 --- a/mediaserver/__init__.py +++ b/mediaserver/__init__.py @@ -9,7 +9,7 @@ from gi.repository import Gst GObject.threads_init() Gst.init(None) -""" -from mediaserver.basicplayer import BasicPlayer -player = BasicPlayer() -""" \ No newline at end of file +from . resources import Resources + +# set Resources to use resources from this package +Resources.SetPackage(__name__) diff --git a/mediaserver/basicplayer.py b/mediaserver/basicplayer.py index cd48c77..a549284 100755 --- a/mediaserver/basicplayer.py +++ b/mediaserver/basicplayer.py @@ -7,9 +7,11 @@ import sys, os # perform gstreamer imports (python3 style) import gi gi.require_version('Gst','1.0') +gi.require_version('GstGL', '1.0') +gi.require_version('GstVideo', '1.0') from gi.repository import GObject -from gi.repository import Gst +from gi.repository import Gst, GstGL, GstVideo class BasicPlayer(GObject.GObject): @@ -51,9 +53,9 @@ class BasicPlayer(GObject.GObject): def __init__(self): GObject.GObject.__init__(self) # setup gstreamer - self.pipeline_state = Gst.State.NULL; + self.pipeline_state = Gst.State.NULL + self.window_handle = 0 self.prepare_gstreamer() - self.buffering = False def __del__(self): @@ -63,17 +65,16 @@ class BasicPlayer(GObject.GObject): if property.name == 'volume': return self.pipeline.get_property('volume') else: - raise AttributeError, 'unknown property %s' % property.name + raise AttributeError("unknown property '{0}'".format(property.name_)) def do_set_property(self, property, value): if property.name == 'volume': volume = clamp(value,0.0,1.0) self.pipeline.set_property('volume', volume) - #print "Set volume to {0}, got {1}".format(volume,self.pipeline.get_property('volume')) + #print("Set volume to {0}, got {1}".format(volume,self.pipeline.get_property('volume'))) self.emit('volume-changed',volume) else: - raise AttributeError, 'unknown property %s' % property.name - + raise AttributeError("unknown property '{0}'".format(property.name_)) def play(self): # start playback ;) if self.player_state in ["READY","PAUSED",]: @@ -83,20 +84,20 @@ class BasicPlayer(GObject.GObject): def load(self,file): self.source = "file://" + file - #print "Attempting to load: '{0}'".format(file) - self.pipeline.set_state(Gst.State.NULL); + #print( "Attempting to load: '{0}'".format(file)) + self.pipeline.set_state(Gst.State.NULL) self.pipeline.set_property("uri", self.source) - self.pipeline.set_state(Gst.State.PAUSED); + self.pipeline.set_state(Gst.State.PAUSED) self.player_state = "LOADING" self.tags.clear() def load_uri(self,uri): self.source = uri - #print "Attempting to load: '{0}'".format(file) - self.pipeline.set_state(Gst.State.NULL); + #print("Attempting to load: '{0}'".format(file)) + self.pipeline.set_state(Gst.State.NULL) self.pipeline.set_property("uri", self.source) - self.pipeline.set_state(Gst.State.PAUSED); + self.pipeline.set_state(Gst.State.PAUSED) self.player_state = "LOADING" self.tags.clear() @@ -104,8 +105,7 @@ class BasicPlayer(GObject.GObject): def stop(self): if self.player_state in ["PLAYING","PAUSED",]: self._running = False - self.pipeline.set_state(Gst.State.READY) - self.player_state = "READY" + self.unload() self.emit('playback-stopped') def pause(self,notify=True): @@ -116,42 +116,49 @@ class BasicPlayer(GObject.GObject): if notify: self.emit('playback-paused') - def _finished(self): + def finished(self): self._running = False - self.pipeline.set_state(Gst.State.READY) - self.seek(0) - self.player_state = "PAUSED" + self.unload() self.emit('playback-finished') + def unload(self): + self.stop_gstreamer() + self.prepare_gstreamer() + def prepare_gstreamer(self): # bin containing the recorder stuff self.pipeline = Gst.ElementFactory.make("playbin", None) - videosink = Gst.ElementFactory.make("glimagesink", None) - alsasink = Gst.ElementFactory.make("alsasink", None) + self.videosink = Gst.ElementFactory.make("glimagesink", None) + self.videosink.set_window_handle(self.window_handle) + self.alsasink = Gst.ElementFactory.make("alsasink", None) # set output device #devicename = self.config["Devices.Output"].getStr('name') #if common.check_alsadev(devicename): # alsasink.set_property('device', devicename) - self.pipeline.set_property("video-sink", videosink) - self.pipeline.set_property("audio-sink", alsasink) + self.pipeline.set_property("video-sink", self.videosink) + self.pipeline.set_property("audio-sink", self.alsasink) # connect the bus listener to the message function self.bus = self.pipeline.get_bus() self.bus.add_signal_watch() - self.bus.connect("message", self.on_message) + self.busconnection = self.bus.connect("message", self.on_message) - self.player_state = "NONE" + self.player_state = "NULL" + + def link_to_window(self,window_handle): + self.window_handle = window_handle + self.videosink.set_window_handle(window_handle) def stop_gstreamer(self): try: self.pipeline.get_bus().disconnect(self.busconnection) self.pipeline.get_bus().remove_signal_watch() self.pipeline.set_state(Gst.State.NULL) - except GObject.GError, e: + except GObject.GError as e: self.set_sensitive(True) def seek(self,seconds): @@ -162,21 +169,21 @@ class BasicPlayer(GObject.GObject): if result is not None and result[0]: return float(result[1]) / Gst.SECOND else: - return -1; + return -1 def position(self): result = self.pipeline.query_position(Gst.Format.TIME) if result is not None and result[0]: return float(result[1]) / Gst.SECOND else: - return -1; + return -1 def on_message(self, bus, message): t = message.type # detect end of stream, and if t == Gst.MessageType.EOS: - self._finished() + self.finished() elif t == Gst.MessageType.ERROR: self.pipeline.set_state(Gst.State.NULL) err, debug = message.parse_error() @@ -185,23 +192,23 @@ class BasicPlayer(GObject.GObject): self._running = False self.emit('playback-finished') self.emit('playback-error', self.player_state, err, debug) - self.player_state = "NONE" + self.player_state = "NULL" elif t == Gst.MessageType.TAG: - tags = message.parse_tag(); + tags = message.parse_tag() for i in range(0,tags.n_tags()): key = tags.nth_tag_name(i) val = tags.get_value_index(key,0) - self.tags[key] = val; + self.tags[key] = val elif t == Gst.MessageType.ASYNC_DONE: if message.src == self.pipeline: pass elif t == Gst.MessageType.STREAM_STATUS: (status,owner) = message.parse_stream_status() -# print "Stream status: {0} (by {1})\n".format(status,owner) +# print("Stream status: {0} (by {1})\n".format(status,owner)) pass elif t == Gst.MessageType.BUFFERING: pct = message.parse_buffering() - print "Buffering: {0}%".format(pct) + print("Buffering: {0}%".format(pct)) self.emit('playback-buffering',pct) if pct != 100: if self.pipeline_state == Gst.State.PLAYING: @@ -212,13 +219,13 @@ class BasicPlayer(GObject.GObject): self.pipeline.set_state(Gst.State.PLAYING) self.buffering = False elif t == Gst.MessageType.DURATION_CHANGED: -# print "Stream duration changed: {0}\n".format(float(self.pipeline.query_duration(Gst.Format.TIME)[1])/Gst.SECOND) +# print("Stream duration changed: {0}\n".format(float(self.pipeline.query_duration(Gst.Format.TIME)[1])/Gst.SECOND)) pass elif t == Gst.MessageType.STATE_CHANGED: if message.src == self.pipeline: (old,new,pending) = message.parse_state_changed() self.pipeline_state = new -# print "State changed from '{0}' to '{1}' pending '{2}'\n".format(old,new,pending) +# print("State changed from '{0}' to '{1}' pending '{2}'\n".format(old,new,pending)) if old == Gst.State.READY and new == Gst.State.PAUSED and self.player_state == "LOADING": self.pipeline.set_state(Gst.State.PAUSED) self.player_state = "READY" diff --git a/mediaserver/images/background-base.png b/mediaserver/images/background-base.png new file mode 100644 index 0000000..7ef6a9b Binary files /dev/null and b/mediaserver/images/background-base.png differ diff --git a/mediaserver/images/background-base.svg b/mediaserver/images/background-base.svg new file mode 100644 index 0000000..cccc1f1 --- /dev/null +++ b/mediaserver/images/background-base.svg @@ -0,0 +1,297 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mediaserver/images/background-image.png b/mediaserver/images/background-image.png new file mode 100644 index 0000000..cf32351 Binary files /dev/null and b/mediaserver/images/background-image.png differ diff --git a/mediaserver/images/background-image.svg b/mediaserver/images/background-image.svg new file mode 100644 index 0000000..14d2a5f --- /dev/null +++ b/mediaserver/images/background-image.svg @@ -0,0 +1,296 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mediaserver/mediaserver.py b/mediaserver/mediaserver.py index e24c760..9d07596 100755 --- a/mediaserver/mediaserver.py +++ b/mediaserver/mediaserver.py @@ -1,6 +1,6 @@ # License for this source file # -# Copyright (c) 2014 Miqra Engineering +# Copyright (c) 2021 Miqra Engineering # import sys, os @@ -9,12 +9,22 @@ import signal from optparse import OptionParser from collections import OrderedDict +from .resources import Resources + # perform gstreamer imports (python3 style) import gi -gi.require_version('Gst','1.0') +gi.require_version('Gst', '1.0') +gi.require_version('Gtk', '3.0') +gi.require_version('GstGL', '1.0') +gi.require_version('GstVideo', '1.0') +gi.require_version('GdkPixbuf', '2.0') from gi.repository import GObject -from gi.repository import Gst +from gi.repository import Gst, GstGL, GstVideo +from gi.repository import GdkPixbuf +from gi.repository import GLib, Gio, Gtk, Gdk +from gi.repository import GdkX11 + Gst.init(None) # perform dbus imports @@ -26,15 +36,19 @@ from dbus.mainloop.glib import DBusGMainLoop DBusGMainLoop(set_as_default=True) # imports from module -from monitoredplayer import MonitoredPlayer +from . monitoredplayer import MonitoredPlayer class MediaService(dbus.service.Object): def __init__(self): + bus_name = dbus.service.BusName('nl.miqra.MediaCore.Media', bus=dbus.SystemBus()) dbus.service.Object.__init__(self, bus_name, '/nl/miqra/MediaCore/Media') + self.window = Gtk.Window(title="MediaServer") + self.windowInit() + self.player = MonitoredPlayer() self.player.connect('playback-ready',self.onPlayerReady) # parameters: source_file tag_dict @@ -46,46 +60,110 @@ class MediaService(dbus.service.Object): self.player.connect('volume-changed',self.onPlayerVolumeChanged) # parameters: volume self.player.connect('playback-buffering',self.onPlayerBuffering) # parameters: volume - self.loadcount = 0; - self.loadmax = 1; + self.window.connect('show',self.onWindowShow) + + self.loadcount = 0 + self.loadmax = 1 self.quickplay = False self.quickplayduration = 0 self.quickplayloop = False + self.window.show() self.tick() # Keepalive timer to help react to Keyboard interrupts def tick(self): GObject.timeout_add(100, self.tick) + def windowInit(self): + self.window.set_name("mainwindow") + self.imagebox = Gtk.Box() + self.imagebox.set_name("imbox") + self.imagebox.set_hexpand(True) + self.imagebox.set_vexpand(True) + self.imagebox.set_halign(Gtk.Align.CENTER) + self.imagebox.set_valign(Gtk.Align.CENTER) + + css = b""" + #mainwindow + { + background-color: #000; + } + """ + css_provider = Gtk.CssProvider() + css_provider.load_from_data(css) + context = Gtk.StyleContext() + screen = Gdk.Screen.get_default() + context.add_provider_for_screen(screen, css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION) + + self.window.add(self.imagebox) + + self.window.fullscreen() + pass + + def loadImage(self,image): + # remove any existing children + for child in self.imagebox.get_children(): + self.imagebox.remove(child) + + self.imagebox.add(image) + self.imagebox.show_all() + + def loadImageFile(self,imfile): + print("Loading image {0}".format(imfile)) + + image = Gtk.Image() + image.set_from_file(imfile) + self.loadImage(image) + + def loadImageData(self,data): + print("Loading image from data") + loader = GdkPixbuf.PixbufLoader.new() + loader.write(data) + pixbuf = loader.get_pixbuf() + loader.close() + image = Gtk.Image() + image.set_from_pixbuf(pixbuf) + self.loadImage(image) + + def onWindowShow(self,w): + xid = self.window.get_window().get_xid() + print("Retrieved XID for window: {0}".format(xid)) + self.player.link_to_window(xid) + self.loadBaseImage() + + def loadBaseImage(self): + self.loadImageFile(Resources.filename("images/background-base.svg")) + + @dbus.service.method(dbus_interface='nl.miqra.MediaCore.Media', in_signature='s', out_signature='') def QuickPlay(self, file,): """ Directly play back a local file """ if self.loadcount < self.loadmax: - print "Quickplaying file {0}".format(file) + print("Quickplaying file {0}".format(file)) self.quickplay = True self.quickplayduration = 0 self.quickplayloop = False self.player.load(file) - self.loadcount += 1; + self.loadcount += 1 else: - print "Skipping load of file {0} because maximum simultaneous loads ({1}) was reached. Wait until ready....".format(file,self.loadmax); + print("Skipping load of file {0} because maximum simultaneous loads ({1}) was reached. Wait until ready....".format(file,self.loadmax)) @dbus.service.method(dbus_interface='nl.miqra.MediaCore.Media', in_signature='sd', out_signature='') def QuickPlayFor(self, file, duration): """ Directly play back a local file """ if self.loadcount < self.loadmax: - print "Quickplaying file {0} for {1} seconds".format(file,duration) + print("Quickplaying file {0} for {1} seconds".format(file,duration)) self.quickplay = True self.quickplayduration = duration self.quickplayloop = False self.player.load(file) - self.loadcount += 1; + self.loadcount += 1 else: - print "Skipping load of file {0} because maximum simultaneous loads ({1}) was reached. Wait until ready....".format(file,self.loadmax); + print("Skipping load of file {0} because maximum simultaneous loads ({1}) was reached. Wait until ready....".format(file,self.loadmax)) # self.quickplayer.playfor(file,duration) @dbus.service.method(dbus_interface='nl.miqra.MediaCore.Media', in_signature='s', out_signature='') @@ -93,56 +171,56 @@ class MediaService(dbus.service.Object): """ Directly play back a url """ if self.loadcount < self.loadmax: - print "Quickplaying file {0}".format(file) + print("Quickplaying file {0}".format(file)) self.quickplay = True self.quickplayduration = 0 self.quickplayloop = False self.player.load_uri(file) - self.loadcount += 1; + self.loadcount += 1 else: - print "Skipping load of file {0} because maximum simultaneous loads ({1}) was reached. Wait until ready....".format(file,self.loadmax); + print("Skipping load of file {0} because maximum simultaneous loads ({1}) was reached. Wait until ready....".format(file,self.loadmax)) @dbus.service.method(dbus_interface='nl.miqra.MediaCore.Media', in_signature='sd', out_signature='') def QuickPlayUrlFor(self, url, duration): """ Directly play back a url """ if self.loadcount < self.loadmax: - print "Quickplaying file {0} for {1} seconds".format(file,duration) + print("Quickplaying file {0} for {1} seconds".format(file,duration)) self.quickplay = True self.quickplayduration = duration self.quickplayloop = False self.player.load_uri(file) - self.loadcount += 1; + self.loadcount += 1 else: - print "Skipping load of file {0} because maximum simultaneous loads ({1}) was reached. Wait until ready....".format(file,self.loadmax); + print("Skipping load of file {0} because maximum simultaneous loads ({1}) was reached. Wait until ready....".format(file,self.loadmax)) @dbus.service.method(dbus_interface='nl.miqra.MediaCore.Media', in_signature='s', out_signature='') def QuickLoop(self, file,): """ Directly play back a url """ if self.loadcount < self.loadmax: - print "Quickplaying file {0}".format(file) + print("Quickplaying file {0}".format(file)) self.quickplay = True self.quickplayduration = 0 self.quickplayloop = True self.player.load(file) - self.loadcount += 1; + self.loadcount += 1 else: - print "Skipping load of file {0} because maximum simultaneous loads ({1}) was reached. Wait until ready....".format(file,self.loadmax); + print("Skipping load of file {0} because maximum simultaneous loads ({1}) was reached. Wait until ready....".format(file,self.loadmax)) @dbus.service.method(dbus_interface='nl.miqra.MediaCore.Media', in_signature='s', out_signature='') def QuickLoopUrl(self, url,): """ Directly play back a url """ if self.loadcount < self.loadmax: - print "Quickplaying url {0}".format(uri) + print("Quickplaying url {0}".format(uri)) self.quickplay = True self.quickplayduration = 0 self.quickplayloop = True self.player.load_uri(url) - self.loadcount += 1; + self.loadcount += 1 else: - print "Skipping load of file {0} because maximum simultaneous loads ({1}) was reached. Wait until ready....".format(file,self.loadmax); + print("Skipping load of file {0} because maximum simultaneous loads ({1}) was reached. Wait until ready....".format(file,self.loadmax)) @@ -152,32 +230,32 @@ class MediaService(dbus.service.Object): """ Load a local file for playback """ if self.loadcount < self.loadmax: - print "Loading file {0}".format(file) + print("Loading file {0}".format(file)) self.quickplay = False self.player.load(file) - self.loadcount += 1; + self.loadcount += 1 self.OnLoading("file://{0}".format(file)) else: - print "Skipping load of file {0} because maximum simultaneous loads ({1}) was reached. Wait until ready....".format(file,self.loadmax); + print("Skipping load of file {0} because maximum simultaneous loads ({1}) was reached. Wait until ready....".format(file,self.loadmax)) @dbus.service.method(dbus_interface='nl.miqra.MediaCore.Media', in_signature='s', out_signature='') def LoadUrl(self, uri): """ Load an url for playback """ if self.loadcount < self.loadmax: - print "Loading url {0}".format(uri) + print("Loading url {0}".format(uri)) self.quickplay = False self.player.load_uri(uri) self.loadcount += 1; self.OnLoading(uri) else: - print "Skipping load of url {0} because maximum simultaneous loads ({1}) was reached. Wait until ready....".format(uri,self.loadmax); + print("Skipping load of url {0} because maximum simultaneous loads ({1}) was reached. Wait until ready....".format(uri,self.loadmax)) @dbus.service.method(dbus_interface='nl.miqra.MediaCore.Media', in_signature='d', out_signature='') def PlayFor(self, duration): """ Starts playback for [duration] seconds """ - print "Starting playback for {0} seconds".format(duration) + print("Starting playback for {0} seconds".format(duration)) self.player.playfor(duration) @dbus.service.method(dbus_interface='nl.miqra.MediaCore.Media', in_signature='', out_signature='') @@ -185,7 +263,7 @@ class MediaService(dbus.service.Object): """ Starts/resumes playback """ pos = self.player.position() - print "Starting playback at timestamp {0}".format(pos) + print("Starting playback at timestamp {0}".format(pos)) self.player.play() @dbus.service.method(dbus_interface='nl.miqra.MediaCore.Media', in_signature='', out_signature='') @@ -193,21 +271,21 @@ class MediaService(dbus.service.Object): """ Starts/resumes playback """ pos = self.player.position() - print "Starting playback at timestamp {0}".format(pos) + print("Starting playback at timestamp {0}".format(pos)) self.player.loop() @dbus.service.method(dbus_interface='nl.miqra.MediaCore.Media', in_signature='', out_signature='') def Pause(self): """ Pauses playback """ - print "Pausing" + print("Pausing") self.player.pause() @dbus.service.method(dbus_interface='nl.miqra.MediaCore.Media', in_signature='', out_signature='') def Stop(self): """ Stops playback """ - print "Stopping" + print("Stopping") self.player.stop() @dbus.service.method(dbus_interface='nl.miqra.MediaCore.Media', in_signature='', out_signature='d') @@ -230,18 +308,26 @@ class MediaService(dbus.service.Object): ### Callback functions def onPlayerReady(self,player,filename,tags): - print "Loaded {0}".format(filename) - print "Tags:" + print("Loaded {0}".format(filename)) + print("Tags:") taglist = {} for tag in tags: try: taglist[tag] = str(tags[tag]) - print " {0}: {1}".format(tag,taglist[tag]) + print(" {0}: {1}".format(tag,taglist[tag])) except Exception as x: - print "Error converting value for '{0}':\n {1}".format(tag,x) + print("Error converting value for '{0}':\n {1}".format(tag,x)) + + # extract cover art from tags + if "image" in tags: + buffer = tags["image"].get_buffer() # Gst.Buffer + (result, mapinfo) = buffer.map(Gst.MapFlags.READ) + if result: + self.loadImageData(mapinfo.data) + # reset load counter - self.loadcount = 0; + self.loadcount = 0 if self.quickplay: if self.quickplayloop: @@ -261,21 +347,23 @@ class MediaService(dbus.service.Object): self.OnPlaying() def onPlayerStopped(self,player): + self.loadBaseImage() self.OnStopped() def onPlayerPaused(self,player): self.OnPaused() def onPlayerFinished(self,player): + self.loadBaseImage() self.OnFinished() def onPlayerError(self,player,state,error,debug): - print "Player state: {0}".format(state) + print("Player state: {0}".format(state)) if state == "LOADING": - print "Failure during LOAD: {0}".format(error) + print("Failure during LOAD: {0}".format(error)) self.OnLoadFail(error) else: - print "Failure during RUN: {0}".format(error) + print("Failure during RUN: {0}".format(error)) self.OnRunFail(error) def onPlayerVolumeChanged(self,player,volume): @@ -348,19 +436,27 @@ class MediaService(dbus.service.Object): pass def Run(): + + print("Initializing") + + # quick bugfix - set XDG runtime dir if it has not been set + if not 'XDG_RUNTIME_DIR' in os.environ: + os.environ['XDG_RUNTIME_DIR'] = "/run/user/{0}".format(os.getuid()) + mediaservice = MediaService() loop = GObject.MainLoop() loopcontext = loop.get_context() + def onsigint(signal,frame): - print "Quitting" + print("Quitting") loop.quit() signal.signal(signal.SIGINT, onsigint) - print "Starting..." + print("Starting..." ) try: loop.run() except KeyboardInterrupt: - print "Quitting" - loop.quit() \ No newline at end of file + print("Quitting") + loop.quit() diff --git a/mediaserver/monitoredplayer.py b/mediaserver/monitoredplayer.py index 0b47806..bcf648b 100755 --- a/mediaserver/monitoredplayer.py +++ b/mediaserver/monitoredplayer.py @@ -8,9 +8,9 @@ from threading import Thread import time # import from this module -from basicplayer import BasicPlayer +from . basicplayer import BasicPlayer -class MonitorThread:#(Thread): +class Monitor: def __init__(self,player): self.player = player #Thread.__init__(self) @@ -34,8 +34,8 @@ class MonitorThread:#(Thread): if self.player.playtime > 0: if (position - self.player.startpos) > self.player.playtime: #self._player.pause(notify=False) - print "Finished limited play" - self.player._finished() + print("Finished limited play") + self.player.finished() if self._running and time is not None: GObject.timeout_add(100, self.run) @@ -44,7 +44,7 @@ class MonitoredPlayer(BasicPlayer): def __init__(self): BasicPlayer.__init__(self) # setup monitor thread - self.monitor = MonitorThread(self) + self.monitor = Monitor(self) self.monitor.start() self.playtime = -1 self.looping=False @@ -82,7 +82,7 @@ class MonitoredPlayer(BasicPlayer): #self.monitor.stop() - def _finished(self): + def finished(self): if self.looping: print("Finished - looping") self.seek(0) @@ -90,7 +90,7 @@ class MonitoredPlayer(BasicPlayer): self.player_state = "PLAYING" self.pipeline.set_state(Gst.State.PLAYING) else: - BasicPlayer._finished(self) + BasicPlayer.finished(self) GObject.type_register(MonitoredPlayer) diff --git a/mediaserver/resources.py b/mediaserver/resources.py new file mode 100644 index 0000000..0eb022b --- /dev/null +++ b/mediaserver/resources.py @@ -0,0 +1,59 @@ +# License for this source file +# +# Copyright (c) 2014 Miqra Engineering +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE + +import os,sys +import pkg_resources + +class Resources(object): # needs to be explicitly subclassed from object to get the __new__ method to work + + PACKAGE = __name__ + + + @classmethod + def SetPackage(cls, package): + """ + Set the package from which to load localization data + """ + cls.PACKAGE = package + pass + + + @classmethod + def string_from(cls,path): + return pkg_resources.resource_string(cls.PACKAGE, path) + + @classmethod + def filename(cls,path): + return pkg_resources.resource_filename(cls.PACKAGE, path) + + @classmethod + def stream_from(cls,path): + return pkg_resources.resource_stream(cls.PACKAGE, path) + + @classmethod + def isdir(cls,path): + return pkg_resources.resource_isdir(cls.PACKAGE,path) + + @classmethod + def exists(cls,path): + return pkg_resources.resource_exists(cls.PACKAGE,path) + + @classmethod + def listdir(cls,path): + return pkg_resources.resource_listdir(cls.PACKAGE,path) diff --git a/test_client.py b/test_client.py index d6d17a5..6c4ae64 100755 --- a/test_client.py +++ b/test_client.py @@ -30,7 +30,7 @@ class TestController: GObject.timeout_add(10, self.tick) def tick(self): - self.player.QuickLoop("/opt/src/robotvideo/ogen open.mp4") + self.player.QuickPlay(sys.argv[1]) #GObject.timeout_add(3000, self.reboot) pass @@ -85,6 +85,6 @@ def signalSIGTERM(self,signum): signal.signal(signal.SIGTERM, signalSIGTERM) controller = TestController() -controller.Start(); +controller.Start()