Initial commit of current code base
This commit is contained in:
commit
3c6c72fe55
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
deb_dist/
|
||||||
|
*.pyc
|
36
BUILDING.txt
Normal file
36
BUILDING.txt
Normal 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
7
VERSION.py
Normal 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
40
debian/postinst
vendored
Executable 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
39
debian/prerm
vendored
Normal 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
|
17
etc/dbus-1/system.d/nl.miqra.MediaServer.conf
Normal file
17
etc/dbus-1/system.d/nl.miqra.MediaServer.conf
Normal 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
175
etc/init.d/mediaserver
Executable 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
4
mediacore-mediaserver
Executable file
|
@ -0,0 +1,4 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
import mediaserver.mediaserver
|
||||||
|
|
||||||
|
mediaserver.mediaserver.Run()
|
51
mediaserver/PKG_CONFIG.py
Normal file
51
mediaserver/PKG_CONFIG.py
Normal 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
15
mediaserver/__init__.py
Normal 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()
|
||||||
|
"""
|
68
mediaserver/audioplayer.py
Normal file
68
mediaserver/audioplayer.py
Normal 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
227
mediaserver/basicplayer.py
Normal 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
66
mediaserver/event.py
Normal 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
248
mediaserver/mediaserver.py
Normal 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()
|
66
mediaserver/quickplayer.py
Normal file
66
mediaserver/quickplayer.py
Normal 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
4
sbin/mediaserver
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
import mediaserver.mediaserver
|
||||||
|
|
||||||
|
mediaserver.mediaserver.Run()
|
53
setup.py
Executable file
53
setup.py
Executable 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
9
stdeb.cfg
Executable 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
43
test_basicplayer.py
Normal 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()
|
28
usr-share-mediaserver/3d-loudspeaker.svg
Normal file
28
usr-share-mediaserver/3d-loudspeaker.svg
Normal 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 |
BIN
usr-share-mediaserver/background-image.png
Executable file
BIN
usr-share-mediaserver/background-image.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 58 KiB |
266
usr-share-mediaserver/background-image.svg
Executable file
266
usr-share-mediaserver/background-image.svg
Executable 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 |
Loading…
Reference in New Issue
Block a user