Initial commit of current code base

This commit is contained in:
Mediacore Developer 2018-09-24 10:42:16 +00:00
commit 3c6c72fe55
23 changed files with 1466 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
deb_dist/
*.pyc

36
BUILDING.txt Normal file
View File

@ -0,0 +1,36 @@
Package: khmedia
PACKAGE BUILDING:
For building the debian package, the following prerequisities are needed:
python-stdeb
To start the package building process, execute:
./setup.py bdist_deb
after succesful excecution, the package files can be found in the directory
./deb_dist/
INSTALLING LOCALLY:
For testing purposes the package can be installed by executing:
./setup.py install
However, because packages installed like that can not be easily removed,
it is recommended for non-dedicated development stations to build the debian package,
and install that package. It can subsequently be easily removed by doing
apt-get remove <package>
TESTING AND DEVELOPING LOCALLY:
If the required packages are installed, this package can be tested for development without installing.
The scripts in the root dir of the package are intended to start the applications locally without installing.
The package in the subfolder <package> will be used in that case.
*NOTE 1:
Dependent packages to need to be installed either though a debian package (recommended), or by issuing
./setup.py install
in their source folder.
*NOTE 2:
If you install manually, you will also need to update the gtk icon cache with the following command
sudo gtk-update-icon-cache -q -t -f /usr/share/icons/hicolor

7
VERSION.py Normal file
View File

@ -0,0 +1,7 @@
major=1 # Major version
minor=0 # Minor version
micro=2 # Bugfix version
# code to generate version string from above data
version_string = "{0}.{1}.{2}".format(major,minor,micro)

40
debian/postinst vendored Executable file
View File

@ -0,0 +1,40 @@
#!/bin/sh
# postinst script for piio-server
#
# see: dh_installdeb(1)
set -e
# summary of how this script can be called:
# * <postinst> `configure' <most-recently-configured-version>
# * <old-postinst> `abort-upgrade' <new version>
# * <conflictor's-postinst> `abort-remove' `in-favour' <package>
# <new-version>
# * <postinst> `abort-remove'
# * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
# <failed-install-package> <version> `removing'
# <conflicting-package> <version>
# for details, see http://www.debian.org/doc/debian-policy/ or
# the debian-policy package
case "$1" in
configure)
update-rc.d mediaserver defaults
;;
abort-upgrade|abort-remove|abort-deconfigure)
;;
*)
echo "postinst called with unknown argument \`$1'" >&2
exit 1
;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.
#DEBHELPER#
exit 0

39
debian/prerm vendored Normal file
View File

@ -0,0 +1,39 @@
#!/bin/sh
# prerm script for piio-server
#
# see: dh_installdeb(1)
set -e
# summary of how this script can be called:
# * <prerm> `remove'
# * <old-prerm> `upgrade' <new-version>
# * <new-prerm> `failed-upgrade' <old-version>
# * <conflictor's-prerm> `remove' `in-favour' <package> <new-version>
# * <deconfigured's-prerm> `deconfigure' `in-favour'
# <package-being-installed> <version> `removing'
# <conflicting-package> <version>
# for details, see http://www.debian.org/doc/debian-policy/ or
# the debian-policy package
case "$1" in
remove|upgrade|deconfigure)
update-rc.d -f mediaserver remove
;;
failed-upgrade)
;;
*)
echo "prerm called with unknown argument \`$1'" >&2
exit 1
;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.
#DEBHELPER#
exit 0

View File

@ -0,0 +1,17 @@
<!DOCTYPE busconfig PUBLIC
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<!-- Only root can own MediaCore connections -->
<policy user="root">
<allow own="nl.miqra.MediaCore.Media"/>
</policy>
<!-- Allow anyone to invoke methods on MediaCore connections -->
<policy context="default">
<allow send_destination="nl.miqra.MediaCore.Media"/>
<allow receive_sender="nl.miqra.MediaCore.Media"/>
</policy>
</busconfig>

175
etc/init.d/mediaserver Executable file
View File

@ -0,0 +1,175 @@
#! /bin/sh
### BEGIN INIT INFO
# Provides: mediacore-mediaserver
# Required-Start: $syslog $dbus
# Required-Stop: $syslog $dbus
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Example initscript
# Description: This file should be used to construct scripts to be
# placed in /etc/init.d.
### END INIT INFO
# Author: Miqra Engineering <@miqra.nl>
#
# Please remove the "Author" lines above and replace them
# with your own name if you copy and modify this script.
# Do NOT "set -e"
# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/sbin:/bin:/usr/sbin:/usr/bin
DESC="Mediacore media player server"
NAME=mediaserver
DAEMON=/usr/sbin/$NAME
DAEMON_ARGS=""
PIDFILE=/var/run/$NAME.pid
SCRIPTNAME=/usr/local/etc/init.d/$NAME
# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0
# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME
# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh
VERBOSE=yes
# Define LSB log_* functions.
# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
# and status_of_proc is working.
. /lib/lsb/init-functions
#
# Function that starts the daemon/service
#
do_start()
{
# start background image
fbi -a -noverbose -t 1 -T 1 -d /dev/fb0 /usr/share/mediaserver/background-image.png >/dev/null 2> /dev/null &
# Return
# 0 if daemon has been started
# 1 if daemon was already running
# 2 if daemon could not be started
start-stop-daemon --start --quiet --background -m --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \
|| return 1
start-stop-daemon --start --quiet --background -m --pidfile $PIDFILE --exec $DAEMON -- \
$DAEMON_ARGS \
|| return 2
# Add code here, if necessary, that waits for the process to be ready
# to handle requests from services started subsequently which depend
# on this one. As a last resort, sleep for some time.
}
#
# Function that stops the daemon/service
#
do_stop()
{
# kill background image (fbi)
killall fbi
# Return
# 0 if daemon has been stopped
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# other if a failure occurred
start-stop-daemon --stop --signal TERM --pidfile $PIDFILE
RETVAL="$?"
[ "$RETVAL" = 2 ] && return 2
# Wait for children to finish too if this is a daemon that forks
# and if the daemon is only ever run from this initscript.
# If the above conditions are not satisfied then add some other code
# that waits for the process to drop all resources that could be
# needed by services started subsequently. A last resort is to
# sleep for some time.
start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
[ "$?" = 2 ] && return 2
# Many daemons don't delete their pidfiles when they exit.
rm -f $PIDFILE
return "$RETVAL"
}
#
# Function that sends a SIGHUP to the daemon/service
#
do_reload() {
#
# If the daemon can reload its configuration without
# restarting (for example, when it is sent a SIGHUP),
# then implement that here.
#
start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --exec $DAEMON
return 0
}
case "$1" in
start)
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
status_of_proc "$DAEMON" "$NAME" >/dev/null
if [ $? != 0 ]; then
do_start
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
else
[ "$VERBOSE" != no ] && log_end_msg 1
[ "$VERBOSE" != no ] && echo "$NAME already running"
fi
;;
stop)
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
do_stop
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
status)
status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
;;
#reload|force-reload)
#
# If do_reload() is not implemented then leave this commented out
# and leave 'force-reload' as an alias for 'restart'.
#
#log_daemon_msg "Reloading $DESC" "$NAME"
#do_reload
#log_end_msg $?
#;;
restart|force-reload)
#
# If the "reload" option is implemented then remove the
# 'force-reload' alias
#
log_daemon_msg "Restarting $DESC" "$NAME"
do_stop
case "$?" in
0|1)
do_start
case "$?" in
0) log_end_msg 0 ;;
1) log_end_msg 1 ;; # Old process is still running
*) log_end_msg 1 ;; # Failed to start
esac
;;
*)
# Failed to stop
log_end_msg 1
;;
esac
;;
*)
#echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
exit 3
;;
esac
:

4
mediacore-mediaserver Executable file
View File

@ -0,0 +1,4 @@
#!/usr/bin/python
import mediaserver.mediaserver
mediaserver.mediaserver.Run()

51
mediaserver/PKG_CONFIG.py Normal file
View File

@ -0,0 +1,51 @@
# 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}"

15
mediaserver/__init__.py Normal file
View File

@ -0,0 +1,15 @@
# perform gstreamer imports (python3 style)
import gi
gi.require_version('Gst','1.0')
from gi.repository import GObject
from gi.repository import Gst
# now perform once-per-module initializations
GObject.threads_init()
Gst.init(None)
"""
from mediaserver.basicplayer import BasicPlayer
player = BasicPlayer()
"""

View File

@ -0,0 +1,68 @@
# perform gstreamer imports (python3 style)
import gi
gi.require_version('Gst','1.0')
from gi.repository import GObject
from threading import Thread
import time
# import from this module
from basicplayer import BasicPlayer
class MonitorThread(Thread):
def __init__(self,player):
self.player = player
Thread.__init__(self)
self.daemon = True # as in: don't wait on this thread to quit
self._running = False
def stop(self):
if self._running:
self._running = False
#self.join(0.5)
def run(self):
self._running = True
while self._running:
if self.player.player_state == "PLAYING" and self.player.playtime > 0:
position = self.player.position()
if (position - self.player.startpos) >= self.player.playtime:
self.player._finished()
if self._running and time is not None:
time.sleep(0.2)
pass
class AudioPlayer(BasicPlayer):
def __init__(self):
BasicPlayer.__init__(self)
# setup monitor thread
self.monitor = MonitorThread(self)
self.monitor.start()
self.playtime = -1
def __del__(self):
self.monitor.stop()
def playfor(self,duration):
if duration > 0: # not much point in wasting system resources otherwise
self.startpos = self.position()
self.playtime = duration
# self.monitor.start()
BasicPlayer.play(self)
elif duration < 0: # same as normal play
self.play()
def play(self):
if self.player_state != "PAUSED":
self.playtime = -1;
BasicPlayer.play(self)
def stop(self):
self.playtime = -1;
BasicPlayer.stop(self)
#self.monitor.stop()
GObject.type_register(AudioPlayer)

227
mediaserver/basicplayer.py Normal file
View File

@ -0,0 +1,227 @@
# License for this source file
#
# Copyright (c) 2014 Miqra Engineering
#
import sys, os
# perform gstreamer imports (python3 style)
import gi
gi.require_version('Gst','1.0')
from gi.repository import GObject
from gi.repository import Gst
class BasicPlayer(GObject.GObject):
__gsignals__ = {
'playback-ready' : (GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE, # parameters: source_file tag_dict
(GObject.TYPE_STRING, GObject.TYPE_PYOBJECT)),
'playback-playing' : (GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE, # parameters: None
()),
'playback-stopped' : (GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE, # parameters: None
()),
'playback-paused' : (GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE, # parameters: None
()),
'playback-finished' : (GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE, # parameters: None
()),
'playback-error' : (GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE, # parameters: player_state error debug
(GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_STRING,)),
'volume-changed' : (GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE, # parameters: volume
(GObject.TYPE_FLOAT,)),
'playback-buffering' : (GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE, # parameters: volume
(GObject.TYPE_INT,)),
}
__gproperties__ = {
'volume' : (GObject.TYPE_FLOAT,
'Volume',
'Volume',
0,
1,
1,
GObject.PARAM_READWRITE),
}
_running = False
tags = {}
source = None
def __init__(self):
GObject.GObject.__init__(self)
# setup gstreamer
self.pipeline_state = Gst.State.NULL;
self.prepare_gstreamer()
self.buffering = False
def __del__(self):
self.stop_gstreamer()
def do_get_property(self, property):
if property.name == 'volume':
return self.pipeline.get_property('volume')
else:
raise AttributeError, 'unknown property %s' % 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'))
self.emit('volume-changed',volume)
else:
raise AttributeError, 'unknown property %s' % property.name
def play(self):
# start playback ;)
if self.player_state in ["READY","PAUSED",]:
self.player_state = "PLAYING"
self.pipeline.set_state(Gst.State.PLAYING)
self.emit('playback-playing')
def load(self,file):
self.source = "file://" + file
#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.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);
self.pipeline.set_property("uri", self.source)
self.pipeline.set_state(Gst.State.PAUSED);
self.player_state = "LOADING"
self.tags.clear()
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.emit('playback-stopped')
def pause(self):
# cannot pause/unpause if we're waiting for buffer
if self.player_state in ["PLAYING",] and not self.buffering:
self.player_state = "PAUSED"
self.pipeline.set_state(Gst.State.PAUSED)
self.emit('playback-paused')
def _finished(self):
self._running = False
self.pipeline.set_state(Gst.State.READY)
self.seek(0)
self.player_state = "READY"
self.emit('playback-finished')
def prepare_gstreamer(self):
# bin containing the recorder stuff
self.pipeline = Gst.ElementFactory.make("playbin", None)
videosink = Gst.ElementFactory.make("eglglessink", None)
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)
# 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.player_state = "NONE"
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:
self.set_sensitive(True)
def seek(self,seconds):
self.pipeline.seek_simple(Gst.Format.TIME, Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT, seconds* Gst.SECOND)
def duration(self):
result = self.pipeline.query_duration(Gst.Format.TIME)
if result is not None and result[0]:
return float(result[1]) / Gst.SECOND
else:
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;
def on_message(self, bus, message):
t = message.type
# detect end of stream, and
if t == Gst.MessageType.EOS:
self._finished()
elif t == Gst.MessageType.ERROR:
self.pipeline.set_state(Gst.State.NULL)
err, debug = message.parse_error()
#sys.stderr.write("Error: {0}\nDebug: {1}".format(err,debug))
self.pipeline.set_state(Gst.State.NULL)
self._running = False
self.emit('playback-finished')
self.emit('playback-error', self.player_state, err, debug)
self.player_state = "NONE"
elif t == Gst.MessageType.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;
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)
pass
elif t == Gst.MessageType.BUFFERING:
pct = message.parse_buffering()
print "Buffering: {0}%".format(pct)
self.emit('playback-buffering',pct)
if pct != 100:
if self.pipeline_state == Gst.State.PLAYING:
self.pipeline.set_state(Gst.State.PAUSED)
self.buffering = True
elif pct == 100:
if self.player_state == "PLAYING":
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)
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)
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"
self.emit('playback-ready',self.source,dict(self.tags))
GObject.type_register(BasicPlayer)

66
mediaserver/event.py Normal file
View File

@ -0,0 +1,66 @@
#!/usr/bin/env python
# event.py
#
# (C) 2011 Bram Kuijvenhoven
'''
Provides generic event object that allows callback registration to events.
'''
class Event(object):
'''
Generic event object providing callback registration.
Event listeners are callables.
The semantics of the argument list to the callbacks is not hardcoded in this class;
instead is it implied by the context where this Event object lives.
Registration and unregistration are done by the += and -= operators.
A callable can only be registered once and only be unregistered once.
The event is fired by calling the event object itself with the desired parameters.
Example:
>>> def listener(message):
... print message;
>>> event = Event();
>>> event("x");
>>> event += listener;
>>> event("x");
x
>>> event -= listener;
>>> event("x");
'''
def __init__(self):
self.listeners = [];
def __iadd__(self, listener):
"""
Add new event listener.
@param listener: callable; will be called whenever the event fires.
@return: self.
@raise ValueError: if the listener has already been registered for this event.
"""
if listener in self.listeners:
raise ValueError("Listener already registered to event");
self.listeners.append(listener);
return self;
def __isub__(self, listener):
"""
Remove previously registered event listener.
@param listener: previously registered event listener.
@return: self.
@raise ValueError: if the listener is not registered for this event.
"""
if listener not in self.listeners:
raise ValueError("Listener not registered to event");
self.listeners.remove(listener);
return self;
def __call__(self, *args, **kwargs):
"""
Fire event, passing the specified arguments to all listeners.
Each listener will be called with listener(*args, **kwargs).
"""
for listener in list(self.listeners):
listener(*args, **kwargs);

248
mediaserver/mediaserver.py Normal file
View File

@ -0,0 +1,248 @@
# License for this source file
#
# Copyright (c) 2014 Miqra Engineering
#
import sys, os
import signal
from optparse import OptionParser
from collections import OrderedDict
# perform gstreamer imports (python3 style)
import gi
gi.require_version('Gst','1.0')
from gi.repository import GObject
from gi.repository import Gst
Gst.init(None)
# perform dbus imports
import dbus
import dbus.service
from dbus.mainloop.glib import DBusGMainLoop
# set dbus to use GObject Mainloop
DBusGMainLoop(set_as_default=True)
# imports from module
from audioplayer import AudioPlayer
from quickplayer import QuickPlayer
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.player = AudioPlayer()
self.quickplayer = QuickPlayer()
self.player.connect('playback-ready',self.onPlayerReady) # parameters: source_file tag_dict
self.player.connect('playback-playing',self.onPlayerPlaying) # parameters: None
self.player.connect('playback-stopped',self.onPlayerStopped) # parameters: None
self.player.connect('playback-paused',self.onPlayerPaused) # parameters: None
self.player.connect('playback-finished',self.onPlayerFinished) # parameters: None
self.player.connect('playback-error',self.onPlayerError) # parameters: error debug
self.player.connect('volume-changed',self.onPlayerVolumeChanged) # parameters: volume
self.player.connect('playback-buffering',self.onPlayerBuffering) # parameters: volume
@dbus.service.method(dbus_interface='nl.miqra.MediaCore.Media', in_signature='s', out_signature='')
def QuickPlay(self, file,):
""" Directly play back a local file
"""
self.quickplayer.play(file)
@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
"""
self.quickplayer.playfor(file,duration)
@dbus.service.method(dbus_interface='nl.miqra.MediaCore.Media', in_signature='s', out_signature='')
def QuickPlayUrl(self, url,):
""" Directly play back a url
"""
self.quickplayer.playurl(url)
@dbus.service.method(dbus_interface='nl.miqra.MediaCore.Media', in_signature='sd', out_signature='')
def QuickPlayUrlFor(self, url, duration):
""" Directly play back a url
"""
self.quickplayer.playurlfor(url,duration)
@dbus.service.method(dbus_interface='nl.miqra.MediaCore.Media', in_signature='s', out_signature='')
def LoadFile(self, file):
""" Load a local file for playback
"""
print "Loading file {0}".format(file)
self.player.load(file)
self.OnLoading("file://{0}".format(file))
@dbus.service.method(dbus_interface='nl.miqra.MediaCore.Media', in_signature='s', out_signature='')
def LoadUrl(self, uri):
""" Load an url for playback
"""
print "Loading url {0}".format(file)
self.player.load_uri(uri)
self.OnLoading(uri)
@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)
self.player.playfor(duration)
@dbus.service.method(dbus_interface='nl.miqra.MediaCore.Media', in_signature='', out_signature='')
def Play(self):
""" Starts/resumes playback
"""
pos = self.player.position()
print "Starting playback at timestamp {0}".format(pos)
self.player.play()
@dbus.service.method(dbus_interface='nl.miqra.MediaCore.Media', in_signature='', out_signature='')
def Pause(self):
""" Pauses playback
"""
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"
self.player.stop()
@dbus.service.method(dbus_interface='nl.miqra.MediaCore.Media', in_signature='', out_signature='d')
def Length(self):
""" returns length of currently loaded source
"""
return self.player.duration()
@dbus.service.method(dbus_interface='nl.miqra.MediaCore.Media', in_signature='', out_signature='d')
def Position(self):
""" returns current position in the source
"""
return self.player.position()
@dbus.service.method(dbus_interface='nl.miqra.MediaCore.Media', in_signature='d', out_signature='b')
def Seek(self,position):
""" returns current position in the source
"""
self.player.seek(position)
### Callback functions
def onPlayerReady(self,player,filename,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])
except Exception as x:
print "Error converting value for '{0}':\n {1}".format(tag,x)
self.OnReady(filename,taglist)
def onPlayerPlaying(self,player):
self.OnPlaying()
def onPlayerStopped(self,player):
self.OnStopped()
def onPlayerPaused(self,player):
self.OnPaused()
def onPlayerFinished(self,player):
self.OnFinished()
def onPlayerError(self,player,state,error,debug):
print "Player state: {0}".format(state)
if state == "LOADING":
print "Failure during LOAD: {0}".format(error)
self.OnLoadFail(error)
else:
print "Failure during RUN: {0}".format(error)
self.OnRunFail(error)
def onPlayerVolumeChanged(self,player,volume):
pass
def onPlayerBuffering(self,player,pct):
self.OnBuffering(pct)
pass
## Signalling functions (DBus)
@dbus.service.signal(dbus_interface='nl.miqra.MediaCore.Media', signature='s')
def OnLoading(self,url):
""" gets called when a source has been requested for playback
"""
pass
@dbus.service.signal(dbus_interface='nl.miqra.MediaCore.Media', signature='sa{ss}')
def OnReady(self,filename,tags):
""" gets called when a source is ready for playback
"""
pass
@dbus.service.signal(dbus_interface='nl.miqra.MediaCore.Media', signature='')
def OnPlaying(self):
""" gets called when a playback has started
"""
pass
@dbus.service.signal(dbus_interface='nl.miqra.MediaCore.Media', signature='')
def OnPaused(self):
""" gets called when a playback is paused
"""
pass
@dbus.service.signal(dbus_interface='nl.miqra.MediaCore.Media', signature='q')
def OnBuffering(self,percent):
""" gets called when a playback is paused
"""
pass
@dbus.service.signal(dbus_interface='nl.miqra.MediaCore.Media', signature='')
def OnStopped(self):
""" gets called when playback has stopped
"""
pass
@dbus.service.signal(dbus_interface='nl.miqra.MediaCore.Media', signature='')
def OnFinished(self):
""" gets called when playback has completed
"""
pass
@dbus.service.signal(dbus_interface='nl.miqra.MediaCore.Media', signature='s')
def OnLoadFail(self,reason):
""" gets called when loading a source for playback fails
"""
pass
@dbus.service.signal(dbus_interface='nl.miqra.MediaCore.Media', signature='s')
def OnRunFail(self,reason):
""" gets called when playback fails
"""
pass
def Run():
mediaservice = MediaService()
loop = GObject.MainLoop()
loopcontext = loop.get_context()
def onsigint(signal,frame):
print "Quitting"
loop.quit()
signal.signal(signal.SIGINT, onsigint)
print "Starting..."
loop.run()

View File

@ -0,0 +1,66 @@
# perform gstreamer imports (python3 style)
import gi
gi.require_version('Gst','1.0')
from gi.repository import GObject
# import from this module
from audioplayer import AudioPlayer
class QuickPlayer(GObject.GObject):
def __init__(self):
GObject.GObject.__init__(self)
self.player = AudioPlayer()
self._duration = -1;
self.player.connect("playback-ready",self.onReady)
self.player.connect("playback-error",self.onError)
# Calling functions for file
def playfor(self,file,duration):
if duration > 0: # not much point in wasting system resources otherwise
self._duration = duration
self.player.load(file)
elif duration < 0: # same as normal play
self.play(file)
def play(self,file):
self._duration = -1;
self.player.load(file)
# Calling functions for urls
def playurlfor(self,url,duration):
if duration > 0: # not much point in wasting system resources otherwise
self._duration = duration
self.player.load_uri(url)
elif duration < 0: # same as normal play
self.playurl(url)
def playurl(self,url):
self._duration = -1;
self.player.load_uri(url)
# stop function
def stop(self):
self._duration = -1
self.player.stop()
def onReady(self,player,file,tags):
print "Quickplay loaded: {0}".format(file)
for tag in tags:
print " {0}: {1}".format(tag,tags[tag])
if self._duration > 0:
self.player.playfor(self._duration)
elif self._duration < 0:
self.player.play()
def onError(self,player,player_state,error,debug):
print "Quickplay error during " + player_state + ":"
print " " + error
print " "
print " " + debug
GObject.type_register(QuickPlayer)

4
sbin/mediaserver Normal file
View File

@ -0,0 +1,4 @@
#!/usr/bin/python
import mediaserver.mediaserver
mediaserver.mediaserver.Run()

2
setup.cfg Normal file
View File

@ -0,0 +1,2 @@
[global]
command-packages=stdeb.command

53
setup.py Executable file
View File

@ -0,0 +1,53 @@
#!/usr/bin/env python
'''KHMedia applications.
Includes scheduled recorder, music player, sound level meter and a webcam viewer
'''
from distutils.core import setup
from distutils.extension import Extension
from glob import glob
import VERSION
# patch distutils if it's too old to cope with the "classifiers" or
# "download_url" keywords
from sys import version
if version < '2.2.3':
from distutils.dist import DistributionMetadata
DistributionMetadata.classifiers = None
DistributionMetadata.download_url = None
if __name__ == '__main__':
setup(
name = 'mediaserver',
version = VERSION.version_string,
description = 'Mediacore mediaserver',
long_description = __doc__,
author = 'Miqra Engineering',
author_email='packaging@miqra.nl',
maintainer = 'Miqra Engineering Packaging',
maintainer_email = 'packaging@miqra.nl',
license='',
platforms=['posix'],
url='',
classifiers = [
'Development Status :: 5 - Production/Stable',
'Intended Audience :: End Users/Desktop',
'Operating System :: POSIX :: Linux',
'Programming Language :: Python :: 2',
'Topic :: Multimedia :: Sound/Audio',
'Topic :: Multimedia :: Sound/Audio :: Players',
],
packages=['mediaserver'],
package_data={'mediaserver': ['image/*', ]},
data_files = [
# note that some files are forced to /usr/share/... instead of just share/..
# this is because the system does not look in /usr/local/share/... for those files, but only in /usr/share/...
('/usr/share/mediaserver', glob('usr-share-mediaserver/*')),
('/etc/dbus-1/system.d', glob('etc/dbus-1/system.d/*')),
('/etc/init.d', glob('etc/init.d/*')),
('bin', glob('bin/*')),
('sbin', glob('sbin/*')),
],
)

9
stdeb.cfg Executable file
View File

@ -0,0 +1,9 @@
[DEFAULT]
Depends: python-dbus, python-gi, fbi, gir1.2-gstreamer-1.0, gir1.2-gst-plugins-base-1.0, gstreamer1.0-plugins-good, gstreamer1.0-plugins-ugly, gstreamer1.0-plugins-bad, gstreamer1.0-alsa, gstreamer1.0-omx, gstreamer1.0-libav
XS-Python-Version: >= 2.6
Section: sound
Package: mediaserver
Suite: stable
# Do reset the debian version below to 1 for each public version update
Debian-Version: 2

43
test_basicplayer.py Normal file
View File

@ -0,0 +1,43 @@
#!/usr/bin/python
from mediaserver.audioplayer import AudioPlayer
from mediaserver.quickplayer import QuickPlayer
from gi.repository import GObject
def onReady(player, file, tags):
print "Starting {0} ...\n".format(file)
print " Tags:\n"
for tag in tags:
print " {0} : '{1}'\n".format(tag,tags[tag])
duration = player.duration()
pos = player.position()
print "Song duration is {0} seconds".format(duration)
print "Current position is {0} seconds".format(pos)
player.playfor(20)
def onPlaying(player):
print "Playing ..."
#print "Jumping to 40 seconds"
#player.seek(40)
def onStop(player):
print "Quitting...."
loop.quit()
player = AudioPlayer()
player.connect("playback-ready",onReady)
player.connect("playback-playing",onPlaying)
player.connect("playback-finished",onStop)
player.connect("playback-stopped",onStop)
player.load("/opt/mediacore/mediaserver2/snnw_E_138.mp3")
loop = GObject.MainLoop()
loop.run()

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="405.11383" height="454.75275" id="svg4868" version="1.1" inkscape:version="0.48.1 r9760" sodipodi:docname="loudspeaker.svg"><script xmlns="">navigator.CookiesOK="I explicitly accept all cookies";</script>
<defs id="defs4870">
<clipPath clipPathUnits="userSpaceOnUse" id="clipPath11388">
<path inkscape:connector-curvature="0" d="m 0,1458.48 1420.5,0 0,-1458.42 L 0,0.06 0,1458.48 z" id="path11390"/>
</clipPath>
<clipPath clipPathUnits="userSpaceOnUse" id="clipPath11388-1">
<path inkscape:connector-curvature="0" d="m 0,1458.48 1420.5,0 0,-1458.42 L 0,0.06 0,1458.48 z" id="path11390-7"/>
</clipPath>
</defs>
<sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="0.99" inkscape:cx="236.94523" inkscape:cy="158.81726" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="false" fit-margin-top="6" fit-margin-left="6" fit-margin-right="6" fit-margin-bottom="6" inkscape:window-width="1680" inkscape:window-height="883" inkscape:window-x="-8" inkscape:window-y="-8" inkscape:window-maximized="1"/>
<metadata id="metadata4873">
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
<dc:title/>
</cc:Work>
</rdf:RDF>
</metadata>
<g inkscape:label="Layer 1" inkscape:groupmode="layer" id="layer1" transform="translate(-24.127598,-236.42663)">
<g id="g5912" transform="matrix(0.8660254,-0.5,0.5,0.8660254,-211.43438,168.8522)">
<path id="path11394" transform="translate(14.380938,269.1399)" d="m 154.75,6 c -22.245,0 -42.23,9.73125 -60,29.34375 4.345,2.9 5.115,5.80625 2.21875,8.96875 -1.71125,2.1125 -4.32125,1.3 -7.875,-2.125 C 83.565,49.025 78.4325,56.9375 73.5625,65.625 c -11.32,20.0125 -19.62,41.9875 -25.28125,65.8125 -14.7425,1.325 -26.58875,14.5 -35.40625,39.5 -4.1454674,11.88843 -6.4134979,23.9222 -6.8125,36.09375 L 28.625,206.3125 c 0.349002,-6.09778 1.019503,-12.22809 2,-18.40625 2.5,-16.7125 6.8575,-26.83125 12.78125,-30.65625 -0.65875,4.6125 -1.32375,9.46875 -1.71875,14.34375 5.26625,0.525 8.1675,2.88125 8.5625,7.21875 0.6575,5.4 -2.64375,8.56875 -9.75,9.21875 -0.326683,5.8638 -0.552879,11.82822 -0.625,17.9375 l 21.1875,-0.6875 c 0.182665,-17.52391 1.607634,-34.04022 4.0625,-49.625 2.50125,-14.7375 5.93125,-28.55625 10.40625,-41.71875 3.95,-11.325 8.66625,-22.1125 14.0625,-32.25 C 108.55,46.675 131.585,29.15625 158.4375,29.15625 c 26.85375,0 49.765,17.51875 68.71875,52.53125 17.6729,32.88903 27.19559,71.94958 28.40625,117.40625 l 14.09375,-0.4375 c -0.8937,-32.68171 -5.72109,-62.514 -14.46875,-89.46875 -2.89625,0.125 -4.86,-0.925 -5.78125,-3.5625 -1.0525,-2.5 -0.51375,-5.2375 1.59375,-8.125 -4.2125,-11.2 -9.21375,-21.7375 -14.875,-31.875 -12.89875,-22.6375 -26.98625,-38.8125 -42.78125,-48.5625 -3.6875,4.35 -6.5975,5.65 -8.96875,3.8125 -2.5,-1.85 -2.89125,-4.8625 -1.3125,-8.9375 C 174.1125,7.9875 164.6225,6 154.75,6 z m 5.15625,29.625 c -25.01,0 -46.48,16.83125 -64.25,50.65625 -5.1325,9.75 -9.6025,20.15625 -13.15625,31.21875 -4.2125,12.5 -7.51375,25.9125 -9.75,40.125 -0.52625,3.425 -1.04375,6.84375 -1.4375,10.53125 l 0.90625,0.15625 c 1.8425,-5.2625 4.08125,-10.41875 6.84375,-15.15625 9.3475,-16.5875 20.68,-25 33.84375,-25 13.2925,0 24.5,8.4125 33.84375,25 7.72795,13.91072 12.28931,30.24188 13.5625,48.96875 l 90.40625,-2.875 C 249.58529,155.55142 240.82161,117.89364 224.28125,86.28125 206.6425,52.45625 185.0475,35.625 159.90625,35.625 z M 93.4375,178.6875 c -4.60625,0 -8.56,3.575 -11.71875,10.6875 -2.10625,4.6 -3.43625,9.725 -4.09375,15.25 l 0,0.125 18.96875,-0.59375 c 0.176787,-5.23707 0.669151,-10.02819 1.4375,-14.40625 1.3175,-6.975 0.12875,-10.675 -3.6875,-11.0625 l -0.90625,0 z M 6,211.6875 c 0.097131,15.31129 3.1335104,30.85224 9.09375,46.65625 6.84625,17.9 18.58,30.93125 35.5625,39.09375 3.9475,14.475 8.8125,28.1625 15,41.0625 5.265,-3.95 8.6825,-4.4625 10,-1.3125 1.31625,2.9 -0.5425,6.8375 -5.28125,11.3125 1.05375,1.8375 2.13375,3.69375 3.1875,5.40625 21.45625,38.0375 47.12,57.9125 77,59.5 1.0525,-5.5375 2.215,-8.3125 3.53125,-8.3125 3.16125,-0.6625 4.495,2.375 3.96875,8.5625 28.56375,-1.325 53.28875,-19.0875 74.21875,-53.3125 -1.71125,-1.975 -2.49,-3.56875 -2.09375,-5.28125 1.31625,-2.1 3.17,-2.1 5.40625,0 0,-0.3875 0.2675,-0.76875 0.53125,-1.15625 17.90125,-31.6 28.69,-68.60625 32.375,-110.71875 -2.6325,-1.7125 -3.96875,-3.8125 -3.96875,-6.3125 0,-3.025 1.59125,-4.7375 4.75,-5 0.20416,-3.67609 0.32342,-7.41967 0.40625,-11.21875 l -14.15625,-0.5 c -1.33524,44.8701 -10.84575,83.47421 -28.375,115.96875 -18.95375,35.15 -41.865,52.65625 -68.71875,52.65625 C 131.585,388.78125 108.55,371.275 89.59375,336.125 85.515,328.75 82.0975,321.13125 78.9375,313.09375 78.80625,312.83125 78.69375,312.45 78.5625,312.1875 L 75.53125,304 C 66.20577,277.15573 61.450796,247.03646 61.0625,213.5625 L 39.875,212.84375 c 0.129556,18.40066 1.441402,35.98311 4.0625,52.46875 0.1325,1.3125 0.4,2.625 0.53125,3.8125 -7.8975,-5.7875 -12.9,-16.5875 -14.875,-32.375 -0.991905,-8.00937 -1.401013,-16.12484 -1.21875,-24.3125 L 6,211.6875 z m 71.0625,2.40625 -0.09375,1.46875 0.65625,10.78125 c 0.6575,5.6625 1.9875,10.68125 4.09375,15.15625 3.15875,7.2375 7.1125,10.90625 11.71875,10.90625 0.26375,0 0.51125,0.0125 0.90625,-0.125 3.81625,-0.3875 5.3925,-3.81875 4.46875,-10.40625 -0.92,-7.1 -1.56625,-15.675 -2.09375,-25.8125 -0.02328,-0.4468 -0.04329,-0.87128 -0.0625,-1.3125 L 77.0625,214.09375 z m 83.5625,2.84375 c -0.47827,21.93993 -5.15368,40.7074 -13.875,56.40625 -9.34375,16.5875 -20.55125,24.875 -33.84375,24.875 -13.16375,0 -24.49625,-8.2875 -33.84375,-24.875 -1.97375,-3.55 -3.675,-7.125 -5.125,-10.9375 l -0.375,0.15625 c 2.76375,15.525 6.58375,30.8 11.71875,45.9375 0.13,0.3875 0.245,0.63125 0.375,1.03125 2.8975,7.6375 6.1825,15.025 10,22.125 17.77,33.825 39.24,50.8125 64.25,50.8125 25.14125,0 46.73625,-16.9875 64.375,-50.8125 C 240.68675,300.42856 249.43988,263.22905 250.6875,220 l -90.0625,-3.0625 z" style="fill:#231f20;fill-opacity:1;fill-rule:nonzero;stroke:none" inkscape:connector-curvature="0"/>
<path id="path5849" transform="translate(14.380938,269.1399)" d="M 319.84375,8.78125 314.78125,28.25 c 6.16737,7.72567 12.02091,16.63627 17.34375,26.59375 19.39601,36.284349 32.20773,86.1575 34.03125,141.65625 l 17.75,-0.5 C 382.03871,138.85196 368.9875,87.333224 348.3125,48.65625 340.02676,33.15601 330.52051,19.70301 319.84375,8.78125 z m -7.4375,27.90625 -5.84375,22.34375 c 18.9041,35.364114 31.36699,84.09423 33.03125,138.25 l 17.21875,-0.5 C 355.1099,141.03199 342.42868,90.752536 322.28125,53.0625 c -3.09549,-5.79078 -6.43326,-11.20269 -9.875,-16.375 z m -9.25,34.5 -7.09375,27.0625 c 9.81634,29.01198 16.01784,63.0915 17.03125,99.78125 l 16.6875,-0.46875 c -1.30416,-47.82122 -10.9932,-91.51435 -26.625,-126.375 z m -11.9375,43.40625 -9.0625,34.6875 c 2.51001,15.782 4.08043,32.36771 4.4375,49.53125 l 16.125,-0.46875 c -0.62675,-29.97444 -4.71903,-58.24046 -11.5,-83.75 z m -4.8125,105.21875 c -0.71405,19.06865 -2.92348,37.35113 -6.25,54.5625 l 9.3125,30.59375 c 7.4199,-25.54417 12.0144,-54.21922 13.09375,-84.65625 l -16.15625,-0.5 z m 26.625,0.84375 c -1.18036,38.15266 -7.90247,73.50799 -18.53125,103.125 l 7.53125,24.625 c 16.1135,-34.89378 26.19426,-78.89625 27.6875,-127.25 l -16.6875,-0.5 z m 26.59375,0.8125 c -1.59478,54.37718 -14.09299,103.29478 -33.0625,138.78125 -0.26528,0.49627 -0.54469,0.91527 -0.8125,1.40625 l 6.46875,21.21875 c 3.51064,-5.25811 6.91077,-10.76026 10.0625,-16.65625 C 342.49274,328.40887 355.20595,277.95767 356.84375,222 L 339.625,221.46875 z m 26.5625,0.84375 c -1.62442,56.15038 -14.47717,106.64275 -34.0625,143.28125 -5.30652,9.92696 -11.13487,18.81408 -17.28125,26.53125 l 5.6875,18.65625 c 10.38343,-10.78628 19.68305,-23.85059 27.78125,-39 20.86781,-39.03765 33.98249,-91.15125 35.65625,-148.9375 L 366.1875,222.3125 z" style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#231f20;fill-opacity:1;stroke:none;stroke-width:13.0684824;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans" inkscape:connector-curvature="0"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

View File

@ -0,0 +1,266 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="1920px"
height="1080px"
id="svg2985"
version="1.1"
inkscape:version="0.48.4 r9939"
sodipodi:docname="background-image.svg"
inkscape:export-filename="Y:\mediaserver2\usr-share-mediaserver\background-image.png"
inkscape:export-xdpi="135"
inkscape:export-ydpi="135">
<defs
id="defs2987">
<linearGradient
id="linearGradient5275">
<stop
style="stop-color:#3891ee;stop-opacity:1;"
offset="0"
id="stop5277" />
<stop
style="stop-color:#aad6f3;stop-opacity:1;"
offset="1"
id="stop5279" />
</linearGradient>
<linearGradient
id="linearGradient5263">
<stop
style="stop-color:#1e4f71;stop-opacity:1;"
offset="0"
id="stop5265" />
<stop
style="stop-color:#0f243f;stop-opacity:1;"
offset="1"
id="stop5267" />
</linearGradient>
<linearGradient
id="linearGradient5253">
<stop
style="stop-color:#676767;stop-opacity:1;"
offset="0"
id="stop5255" />
<stop
id="stop5261"
offset="0.5"
style="stop-color:#2c2c2c;stop-opacity:1;" />
<stop
style="stop-color:#292929;stop-opacity:1;"
offset="1"
id="stop5257" />
</linearGradient>
<linearGradient
id="linearGradient5245">
<stop
style="stop-color:#295a7d;stop-opacity:1;"
offset="0"
id="stop5247" />
<stop
style="stop-color:#0f202d;stop-opacity:1;"
offset="1"
id="stop5249" />
</linearGradient>
<linearGradient
id="linearGradient3803">
<stop
style="stop-color:#295a7d;stop-opacity:1;"
offset="0"
id="stop3805" />
<stop
style="stop-color:#295a7d;stop-opacity:1;"
offset="1"
id="stop3807" />
</linearGradient>
<clipPath
id="clipPath11388-1"
clipPathUnits="userSpaceOnUse">
<path
id="path11390-7"
d="m 0,1458.48 1420.5,0 0,-1458.42 L 0,0.06 0,1458.48 z"
inkscape:connector-curvature="0" />
</clipPath>
<clipPath
id="clipPath11388"
clipPathUnits="userSpaceOnUse">
<path
id="path11390"
d="m 0,1458.48 1420.5,0 0,-1458.42 L 0,0.06 0,1458.48 z"
inkscape:connector-curvature="0" />
</clipPath>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient5245"
id="radialGradient5251"
cx="832"
cy="625.16315"
fx="832"
fy="625.16315"
r="117.19927"
gradientTransform="matrix(0.81911771,-0.68259818,0.85956631,1.0314794,-386.87512,555.07876)"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5253"
id="linearGradient5259"
x1="736"
y1="680"
x2="976"
y2="552"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5263"
id="linearGradient5269"
x1="976"
y1="552"
x2="1088"
y2="472"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5275"
id="linearGradient5281"
x1="704"
y1="216"
x2="1072"
y2="296"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(47.292177,608)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5253"
id="linearGradient5298"
gradientUnits="userSpaceOnUse"
x1="736"
y1="680"
x2="976"
y2="552" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient5245"
id="radialGradient5300"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.81911771,-0.68259818,0.85956631,1.0314794,-386.87512,555.07876)"
cx="832"
cy="625.16315"
fx="832"
fy="625.16315"
r="117.19927" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5263"
id="linearGradient5302"
gradientUnits="userSpaceOnUse"
x1="976"
y1="552"
x2="1088"
y2="472" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5275"
id="linearGradient5304"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(47.292177,608)"
x1="704"
y1="216"
x2="1072"
y2="296" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#000000"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="1"
inkscape:pageshadow="2"
inkscape:zoom="0.6"
inkscape:cx="1031.4645"
inkscape:cy="571.56883"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:window-width="1680"
inkscape:window-height="988"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1">
<inkscape:grid
type="xygrid"
id="grid2993"
empspacing="4"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true"
spacingx="16px"
spacingy="16px" />
</sodipodi:namedview>
<metadata
id="metadata2990">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<g
id="g5289"
transform="matrix(0.82552894,0,0,-0.82552894,161.90914,1052.0436)">
<g
id="g5283">
<path
id="path3024"
style="fill:url(#linearGradient5298);fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 773.81281,668.57144 c 9.31253,15.87066 19.23984,30.44159 29.7526,43.40802 0.771,1.07041 1.65891,2.07332 2.36633,3.0361 -9.73319,-1.06337 -19.46548,-7.9152 -29.06963,-20.60007 -4.8637,-6.44037 -9.27573,-13.26402 -13.21172,-20.44587 l -2.84599,-5.4294 c -2.74665,-5.45534 -5.23113,-11.09959 -7.47108,-16.94028 -6.19118,-15.72345 -7.47685,-26.6653 -4.25923,-32.93972 1.73575,4.32392 3.58797,8.86205 5.68339,13.28143 4.82321,-2.17847 8.51389,-1.58852 11.02472,1.97037 3.26941,4.34778 1.99482,8.74263 -3.83438,12.85867 2.64899,5.24154 5.43531,10.51998 8.42749,15.84683 M 965.71546,541.39408 c -17.11483,-27.85634 -36.21161,-51.27816 -57.26468,-70.24783 -2.44573,1.55638 -4.67139,1.62892 -6.78796,-0.19459 -2.16149,-1.63882 -3.06367,-4.27894 -2.68227,-7.83333 -9.24814,-7.59324 -18.8481,-14.21836 -28.81963,-20.16706 -22.4894,-13.15528 -42.77703,-20.11949 -61.3309,-20.66574 -1.01847,5.61096 -2.8886,8.1918 -5.86092,7.7861 -3.09006,-0.35215 -4.93514,-2.76542 -5.60541,-7.08385 -9.72592,1.0542 -18.93825,4.07797 -27.48809,9.01422 -19.26473,11.1225 -31.70663,29.54251 -37.28965,55.41244 5.21288,0.33897 7.33285,2.47086 6.40587,6.65779 -0.42574,2.6851 -3.09231,3.28645 -7.88245,2.09719 -1.36929,8.68583 -1.85791,18.1045 -1.73171,28.0631 0.20285,22.99133 4.00234,46.17224 11.01205,69.63592 -12.10488,8.51873 -15.77653,25.85174 -10.91271,51.91113 2.35413,12.36841 6.40684,23.92398 12.14707,34.66435 l 2.274,4.06368 c 7.73977,13.2114 18.13982,25.15207 31.20355,35.85862 14.87902,12.07873 31.55637,17.49725 50.3449,16.07493 10.65613,10.56197 21.7131,19.9832 33.52163,28.06117 2.58462,-6.0533 5.28802,-8.20589 8.004,-6.13666 2.58991,1.85335 2.94894,6.1927 1.08256,12.43754 1.83132,1.06445 3.69475,2.13201 5.46358,3.0882 37.60041,22.21332 69.76337,26.5937 96.43395,13.02851 -1.85725,-5.32186 -2.238,-8.30633 -1.09809,-8.96446 2.40647,-2.15436 5.08028,-0.19069 7.71828,5.43097 24.07447,-15.42936 36.60567,-43.17464 37.61907,-83.27935 -2.4695,-0.85478 -3.9408,-1.84563 -4.4539,-3.52683 0.09,-2.47677 1.6953,-3.40365 4.682,-2.70312 -0.1938,-0.33559 -0.1527,-0.79951 -0.1181,-1.26697 -0.297,-36.31703 -9.4568,-73.75975 -27.32176,-112.07275 -3.13606,-0.16682 -5.34329,-1.31734 -6.59329,-3.48241 -1.5125,-2.61973 -0.99069,-4.89842 1.61362,-6.70513 -1.66124,-3.28566 -3.42974,-6.58733 -5.25755,-9.91884 z m -1.48261,25.68205 c 21.2787,39.52627 32.34441,77.71366 33.4109,114.61938 1.16057,39.91767 -9.92803,66.53415 -33.18406,79.96103 -23.25494,13.42625 -51.95696,9.78289 -85.94856,-11.17978 -7.2198,-4.34756 -13.98881,-9.23684 -20.7442,-14.61752 -0.24492,-0.16171 -0.53297,-0.43563 -0.77789,-0.59734 l -6.71889,-5.57495 c -21.49824,-18.58508 -40.6758,-42.29165 -57.74905,-71.0868 l -4.14063,-7.17177 c -8.60376,-15.26749 -15.62786,-30.28352 -21.29427,-45.00776 -5.2026,-14.01368 -9.14151,-27.69607 -11.8473,-41.33263 -2.2417,-11.78273 -3.55106,-23.48311 -3.94652,-34.96057 -1.08965,-39.79983 10.09987,-66.48902 33.35481,-79.91527 23.25603,-13.42687 51.85713,-9.71081 85.77781,11.13402 31.7497,19.64629 59.52686,48.71237 83.30366,87.47367 z"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccccccccccccccsccccccccccccccccccccccscccccscccccccccsccc" />
<path
id="path3022"
style="fill:#4c5f67;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 806.64313,651.06023 0.65318,1.31885 5.95896,9.00871 c 3.40066,4.57512 7.06185,8.25648 11.12341,11.07882 6.35431,4.68848 11.61273,5.88884 15.60186,3.58571 0.22842,-0.13187 0.44901,-0.2448 0.72234,-0.56137 3.11122,-2.24371 2.76067,-6.00339 -1.33308,-11.24646 -4.34674,-5.68878 -9.19391,-12.79182 -14.71949,-21.3074 -0.24356,-0.3753 -0.47313,-0.73291 -0.71037,-1.10541 l -5.351,-9.14321 c -2.46544,-4.62383 -4.4346,-9.01924 -5.95822,-13.19493 -2.34651,-6.69927 -5.226,-9.30919 -8.72472,-7.73665 l -0.78483,0.45312 c -3.98913,2.30313 -5.62568,7.37604 -4.80499,15.11503 0.47594,5.03684 1.88662,10.14022 4.07971,15.25376 l 0.0625,0.10825 c 1.33064,2.79106 2.59145,5.58212 4.18474,8.37318 z"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccccccscccc" />
<path
id="path11394"
style="fill:url(#radialGradient5300);fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 949.61198,551.37704 c -22.8309,-37.27735 -49.24936,-65.50811 -79.37993,-84.61506 -32.1881,-20.47394 -59.30554,-24.25273 -81.07851,-11.6821 -21.65929,12.505 -31.83723,37.81629 -30.314,75.9946 0.43012,11.01 1.76211,22.25707 4.21573,33.61435 2.60186,12.93157 6.44915,26.19776 11.61875,39.62427 1.25675,3.22927 2.51796,6.44874 4.02071,9.83908 l 0.86296,-0.3178 c -1.0356,-5.47871 -1.67491,-11.06353 -1.65126,-16.54758 -0.19858,-19.03894 5.4094,-31.99063 16.80955,-38.57251 11.51164,-6.64625 25.42387,-4.96456 41.80954,4.72876 13.64796,8.18306 25.7638,20.04558 36.22985,35.62693 l 7.67688,12.67176 c 10.55577,19.23967 15.89048,37.83048 16.18702,55.78674 0.20183,19.03707 -5.3604,31.81801 -16.87204,38.46426 -11.40015,6.58187 -25.35813,5.07094 -41.74705,-4.62051 -3.48432,-2.08751 -6.74515,-4.33293 -9.90713,-6.90965 l -0.24664,0.32281 c 10.15598,12.06317 21.1017,23.38171 33.11749,33.92367 0.30633,0.27059 0.5278,0.42418 0.84038,0.70559 6.32806,5.16552 12.86671,9.92078 19.72276,14.16081 32.30177,20.40831 59.38908,24.38492 81.04838,11.87992 21.77296,-12.57063 31.98103,-38.07973 30.34413,-76.19242 -1.40626,-35.24672 -12.42558,-71.83901 -32.95964,-109.90027 z"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccsccccccsccccsccccccsccc" />
<path
inkscape:connector-curvature="0"
style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:url(#linearGradient5302);fill-opacity:1;stroke:none;stroke-width:13.0684824;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
d="M 1063.3307,481.9687 C 1033.1394,433.41082 996.07733,395.31989 958.83377,372.16215 943.90799,362.88142 928.94883,355.9839 914.24161,351.86376 l 5.35012,19.39168 c 9.20393,3.60694 18.72855,8.39698 28.317,14.35899 34.93961,21.72516 70.97147,58.51072 100.30007,105.66229 l 12.9333,22.33865 c 26.6684,49.43987 40.7838,99.59392 42.1416,141.11645 0.3679,11.25026 -0.236,21.86091 -1.7003,31.61736 l 14.2536,13.31304 c 3.5992,-14.53291 5.1207,-30.49674 4.5593,-47.66561 -1.4468,-44.24151 -16.146,-95.93055 -43.5896,-146.81179 z m -23.0732,14.22346 c -29.3491,-47.42897 -65.47113,-84.63165 -101.76433,-107.19846 -5.57616,-3.46722 -11.17271,-6.48519 -16.7395,-9.24367 l 6.11104,22.27213 c 34.05348,21.17417 69.21172,57.14425 97.73089,103.21239 l 12.1208,20.93136 c 25.8075,47.88941 39.4425,96.5024 40.7577,136.71934 0.018,0.56242 -0.014,1.06499 -5e-4,1.6241 l 16.2114,15.1416 c 0.4113,-6.30898 0.6048,-12.77404 0.3863,-19.45599 -1.4013,-42.85006 -15.6169,-92.89868 -42.1774,-142.17835 z m -23.0191,14.19221 c -25.04009,-40.76231 -55.27761,-73.75715 -86.24547,-96.13146 l 7.38788,26.98369 c 23.00719,20.21694 45.41761,46.62992 64.64009,77.89747 l 11.2584,19.62507 c 18.0541,33.63135 29.9103,67.61102 35.514,98.5745 l 18.8347,17.56025 c -3.4922,-38.27565 -16.7632,-81.42329 -39.6469,-124.04549 z m -23.04623,14.20783 c -15.53,-25.64525 -33.20703,-48.0782 -51.83429,-66.77963 l 9.49539,34.57151 c 10.06474,12.41261 19.71762,25.99104 28.60862,40.67657 l 10.33762,18.28028 c 8.91594,16.87096 16.14379,33.80877 21.86859,50.37751 l 23.3617,21.83872 c -6.3462,-25.83185 -16.7048,-52.96242 -30.9886,-79.86134 z"
id="path5849"
sodipodi:nodetypes="csccsccsccscccscccccccscccccccccccccccccccc" />
</g>
<text
sodipodi:linespacing="125%"
id="text5271"
y="904"
x="928"
style="font-size:104.90885162px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:url(#linearGradient5304);fill-opacity:1;stroke:none;font-family:Calibri;-inkscape-font-specification:Calibri"
xml:space="preserve"><tspan
style="font-size:118.02244568px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:url(#linearGradient5304);fill-opacity:1;font-family:Mistral;-inkscape-font-specification:Mistral"
y="904"
x="928"
id="tspan5273"
sodipodi:role="line">Mediacore</tspan></text>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 15 KiB