Commit 00f54fa8 authored by Gottfried Gaisbauer's avatar Gottfried Gaisbauer
Browse files

Communication between cli tool and AuraServer, AuraServer and LiquidServer

parent b1b3764b
<component name="ProjectDictionaryState">
<dictionary name="gg" />
</component>
\ No newline at end of file
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
<option name="processCode" value="true" />
<option name="processLiterals" value="true" />
<option name="processComments" value="true" />
</inspection_tool>
</profile>
</component>
\ No newline at end of file
This diff is collapsed.
......@@ -2,15 +2,14 @@ import signal
import sys
import threading
from datetime import datetime
from libraries.base.config import ConfigReader
from libraries.reporting.messenger import AuraMessenger
from modules.controller.controller import AuraController
from modules.communication.zmq.zmqadapter import ServerZMQAdapter
class Aura(threading.Thread):
class Aura():
server = None
config = None
messenger = None
controller = None
......@@ -20,11 +19,12 @@ class Aura(threading.Thread):
self.config.loadConfig()
messenger = AuraMessenger()
messenger.setChannel("aura")
messenger.set_channel("aura")
server = object
self.controller = AuraController(self.config)
self.controller = AuraController(self.config, debug=True)
self.server = ServerZMQAdapter(self.controller, self.config, debug=True)
def receive_signal(signum, stack):
print("received signal")
......@@ -32,41 +32,16 @@ class Aura(threading.Thread):
signal.signal(signal.SIGUSR1, receive_signal)
def startListening(self):
def join_comm(self):
# start listener thread
server = ServerZMQAdapter(self.controller, self.config)
try:
while server.is_alive():
print(str(datetime.now())+" joining")
server.join()
print("join out")
# if cnt % 30 == 0:
# print(datetime.datetime.now().isoformat())
# server.printLastMessages()
# cnt = 0
# cnt = cnt + 1
except (KeyboardInterrupt, SystemExit):
# Dem Server den Shutdown event setzen
# server.shutdown_event.set()
# Der Server wartet auf Eingabe
# Daher einen Client initiieren, der eine Nachricht schickt
server.halt()
sys.exit('Terminated')
self.server.join_comm()
# # ## ## ## ## ## # #
# # ENTRY FUNCTION # #
# # ## ## ## ## ## # #
def main():
aura = Aura()
aura.startListening()
aura.join_comm()
# # ## ## ## ## ## ## # #
# # End ENTRY FUNCTION # #
......
station_name="Radio FRO"
station_logo="/etc/aura/stationlogo.jpg"
station_fallback_pool="/var/audio/station_fallback_pool"
#Change this settings
daemongroup="gg"
daemonuser="gg"
scheduler_config_file="/etc/aura/scheduler.xml"
# SOUND CARD SETTINGS
line_in_count=1
line_out_count=1
input_device[0]="hw:0"
output_device[0]="hw:0"
# DATABASE SETTINGS
db_user="aura"
db_name="aura"
db_pass="aura"
db_host="localhost"
# ALSA SETTINGS
# if you have no idea what to do here => set use_alsa to "n", then pulseaudio is used
use_alsa="y"
# alsa_buffer => int
alsa_buffer="8192"
# alsa_buffer_length => int
alsa_buffer_length="15"
# alsa_periods => int
alsa_periods="0"
# frame_duration => double
frame_duration="0.4"
# frame_size => int
frame_size=""
socketdir="/home/gg/PycharmProjects/aura/modules/liquidsoap"
logdir="/var/log/aura"
# channelnames for mixing
# leave this alone if you do not know what you are doing
http_channels="http,http2"
line_in_channels="live,live2"
filesystem_channels="filesystem"
adminmail="gogo@servus.at"
playlistdir="/var/audio/playlists/"
#calendarurl="http://localhost/index.php?option=com_jimtawl&view=calendar&format=json&from=#datefrom#&to=#dateto#"
calendarurl="http://bermudafunk-kalender.critmass.de/index.php?option=com_jimtawl&view=calendar&format=json&from=#datefrom#&to=#dateto#"
# how many days in future should the calendar be stored in database - default=7
#calendar_precache_days=7
audiobase="/var/audio/rec"
altaudiobase="/var/audio/preprod"
# hardware settings
# SOUNDCARD FROM STWST:
# HOME CARD
# was player_input_device:
# recinput="soundcard"
# altrecinput="soundcard"
# altrecorder_device="soundcard"
# recorder_device="soundcard"
# track_sensitive => fallback_folder track sensitivity
# max_blank => maximum time of blank from source
# min_noise => minimum duration of noise on source to switch back over
# threshold => power in dB under which the stream is considered silent
fallback_audio_folder="/var/audio/fallback/NightmaresOnWax/Smokers Delight"
fallback_max_blank="5"
fallback_min_noise="30"
fallback_threshold="-40"
stream="y"
stream_type="harbor"
#stream_type="icecast"
stream_bitrate="128"
stream_port="8000"
stream_mountpoint="aura"
stream_user="source"
stream_password="eegah5Hi"
stream_host="localhost"
stream_url="http://www.fro.at"
stream_name="Comba Test Stream"
stream_genre="mixed"
stream_description="Test Stream"
stream_admin_user="admin"
stream_admin_password="ahZ4caeg"
# ZeroMessagingQueue SETTINGS
communication="zmq"
zmqhostip="127.0.0.1"
zmqport="9099"
loglevel="info"
webservice_mode="apache"
#servername=""
#serviceport=""
install_dir="/home/gg/PycharmProjects/aura"
<Config>
<Jobs multiple="true">
<job>
<time>00:00</time>
<until>23:00</until>
<job>play_playlist</job>
<params>no_stop</params>
</job>
<job>
<job>start_recording</job>
<until>00:00</until>
<day>all</day>
<time>00:00</time>
<params>no_stop</params>
</job>
<job>
<daysolder>4</daysolder>
<job>clean_cached</job>
<day>1</day>
<time>00:03</time>
<params></params>
</job>
<job>
<time>01:00</time>
<day>all</day>
<job>precache</job>
<params></params>
</job>
</Jobs>
</Config>
......@@ -195,10 +195,15 @@
"00": "Successfull stored scheduler config",
"01": "Not enough access rights for this operation",
"02": "Could not store a valid scheduler XML"
},
},
"getUserlist": {
"id": "38",
"00": "Userlist was successfully delivered",
"01": "Not enough access rights for this operation"
}
"id": "38",
"00": "Userlist was successfully delivered",
"01": "Not enough access rights for this operation"
},
"get_act_programme": {
"id": "39",
"00": "Successfully fetched the program",
"01": "Cannot fetch actual program"
}
}
#!/usr/bin/python3
import time
import sys
import simplejson
......@@ -15,20 +16,20 @@ class Guru:
config = ConfigReader()
config.loadConfig()
lsc = LiquidSoapCommunicator(False)
# # AuraScheduler(lsc.getClient(), "/etc/comba/scheduler.xml")
#fcd = FetchCalendarData()
zmqclient = ClientZMQAdapter(config.get('zmqhostip'), config.get('zmqport'))
# init liquidsoap communication
lsc = LiquidSoapCommunicator(config, False)
# init internal zmq communication
zmqclient = ClientZMQAdapter(config.get('zmqhostip'), config.get('zmqport'), debug=False)
def __init__(self):
nothing_done = True
try:
parser = ArgumentParser()
# commands
parser.add_argument("-fnp", "--fetch-new-programmes", action="store_true", dest="fetch_new_programme",
default=False, help="Fetch new programmes from calendarurl in comba.ini")
parser.add_argument("-ip", "--init-player", action="store_true", dest="initplayer", default=False,
help="Checks what is the active source and stops everything else")
# getter
parser.add_argument("-gam", "--get-active-mixer", action="store_true", dest="getactivemixer", default=False,
......@@ -39,12 +40,15 @@ class Guru:
help="Prints the actual Programme, the controller holds")
# manipulation
parser.add_argument("-am", "--select-mixer", action="store", dest="selectmixer", default=-1,
parser.add_argument("-am", "--select-mixer", action="store", dest="selectmixer", default=-1, metavar="MIXERNUM",
help="Which mixer should be activated?", type=int)
parser.add_argument("-dm", "--de-select-mixer", action="store", dest="deselectmixer", default=-1,
parser.add_argument("-dm", "--de-select-mixer", action="store", dest="deselectmixer", default=-1, metavar="MIXERNUM",
help="Which mixer should be activated?", type=int)
parser.add_argument("-vm", "--volume", action="store", dest="setvolume", default=0, metavar=("MIXERNUM","VOLUME"), nargs=2,
help="Set volume of a mixer source", type=int)
parser.add_argument("-as", "--add-source", action="store", dest="addsource", default="",
help="Add new source to LiquidSoap mixer [Experimental]")
......@@ -53,68 +57,80 @@ class Guru:
except ValueError:
parser.print_help()
exit(1)
except TypeError:
parser.print_help()
exit(2)
if args.fetch_new_programme:
print("Guru is learning how to fetch new programmes")
self.fetch_new_programme()
nothing_done = False
if args.getactivemixer:
self.getactivemixer()
nothing_done = False
if args.get_active_mixer:
self.get_active_mixer()
if args.printmixerstatus:
self.printmixerstatus()
nothing_done = False
self.print_mixer_status()
if args.printactprog:
self.printactprog()
nothing_done = False
self.print_act_program()
if args.addsource != "":
print("Guru still has to learn to add a source")
nothing_done = False
if args.selectmixer != -1:
self.selectmixer(args.selectmixer)
nothing_done = False
self.select_mixer(args.select_mixer)
if args.deselectmixer != -1:
self.selectmixer(args.deselectmixer, False)
nothing_done = False
self.select_mixer(args.deselectmixer, False)
if nothing_done:
if args.setvolume:
self.set_volume(args.setvolume[0], args.setvolume[1])
if args.initplayer:
self.init_player()
if len(sys.argv) == 1:
parser.print_help()
def fetch_new_programme(self):
reply = self.zmqclient.send("fetch_new_programme")
print(type(reply))
jsonreply = self.zmqclient.send("fetch_new_programme")
#print(reply)
reply = simplejson.loads(jsonreply)
for schedule in reply:
print(schedule["show_name"] + " starts at " + schedule["schedule_start"] + ", ends at " + schedule["schedule_end"] + " and has " + str(len(schedule["playlist"]["entries"])) + " entries in the playlist")
def init_player(self):
reply = self.zmqclient.send("player_startup")
print(reply)
print(simplejson.loads(reply))
def selectmixer(self, mixernumber, activate=True):
return self.lsc.switchmixernumber(mixernumber, activate)
def select_mixer(self, mixernumber, activate=True):
return self.lsc.switch_mixer_number(mixernumber, activate)
def set_volume(self, mixernumber, volume):
print("trying to set volume of "+str(mixernumber)+" to "+str(volume)+"%")
return self.lsc.set_volume(mixernumber, volume)
def getactivemixer(self):
def get_active_mixer(self):
print("Guru thinking...")
am = self.lsc.getactivemixer()
am = self.lsc.get_active_mixer()
if len(am) == 0:
print("Guru recognized a problem: No active source!!!")
elif len(am) > 1:
print("Guru recognized a problem: Multiple active sources!!! " + str(am))
else:
print("Guru thinking result: ActiveMixer: " + str(am[0]))
print("...result: " + str(am))
def printmixerstatus(self):
status = self.lsc.getmixerstatus()
def print_mixer_status(self):
status = self.lsc.get_mixer_status()
for k,v in status.items():
print("source: "+k+"\t status: "+v)
def printactprog(self):
reply = self.zmqclient.send("get_act_programme")
print(reply)
def print_act_program(self):
jsonreply = self.zmqclient.send("get_act_programme")
reply = simplejson.loads(jsonreply)
for entry in reply:
print("schedule id #"+str(entry["schedule_id"])+" and entrynumber #"+str(entry["entry_num"])+" starting @ "+entry["entry_start"]+" playing "+entry["source"]+" and is going to stop @ "+entry["entry_end"])
# # ## ## ## ## ## # #
......@@ -122,10 +138,10 @@ class Guru:
# # ## ## ## ## ## # #
def main():
guru = Guru()
# # ## ## ## ## ## ## # #
# # End ENTRY FUNCTION # #
# # ## ## ## ## ## ## # #
if __name__ == "__main__":
main()
This diff is collapsed.
......@@ -2,11 +2,7 @@ __author__ = 'michel'
# -*- coding: utf-8 -*-
import datetime, os, urllib, sys
import pprint
#from modules.web import db
import decimal
from sqlalchemy import Boolean, Column, Date, DateTime, Float, Integer, String, Text, Time, ForeignKey
from libraries.database.database import db
......@@ -21,72 +17,143 @@ class Model:
def commit(self):
db.session.commit()
# def dump_datetime(self, value):
# """Deserialize datetime object into string form for JSON processing."""
# if value is None:
# return None
# return [value.strftime("%Y-%m-%d"), value.strftime("%H:%M:%S")]
def alchemy_encoder(obj):
"""JSON encoder function for SQLAlchemy special classes."""
if isinstance(obj, datetime.date):
return obj.isoformat()
elif isinstance(obj, decimal.Decimal):
return float(obj)
def _asdict(self):
return self.__dict__
# ------------------------------------------------------------------------------------------ #
class TimeSlotModel(Model):
class ScheduleModel(Model):
def get_length(self):
sec1 = int(datetime.datetime.strptime(self.start[0:16].replace(" ", "T"), "%Y-%m-%dT%H:%M").strftime("%s"))
sec2 = int(datetime.datetime.strptime(self.end[0:16].replace(" ", "T"), "%Y-%m-%dT%H:%M").strftime("%s"))
len = sec2 - sec1
return len
def pretty_print(self):
return pprint.pprint(self)
class TimeSlotEntryModel(Model):
# ------------------------------------------------------------------------------------------ #
class ScheduleEntryModel(Model):
# ------------------------------------------------------------------------------------------ #
@staticmethod
def upcoming(datefrom=datetime.datetime.now()):
upcomingtracks = TimeSlotEntry.query.filter(TimeSlotEntry.start > datefrom).all()
upcomingtracks = ScheduleEntry.query.filter(ScheduleEntry.start > datefrom).all()
return upcomingtracks
# ------------------------------------------------------------------------------------------ #
@staticmethod
def select_all():
return TimeSlotEntry.query.filter().all()
return ScheduleEntry.query.filter().all()
@staticmethod
def select_one(playlist_id, entry_num):
return ScheduleEntry.query.filter(ScheduleEntry.playlist_id == playlist_id, ScheduleEntry.entry_num == entry_num).first()
def __str__(self):
return "TimeSlotEntry starts @ "+TimeSlotEntry.entry_start+" and ends @ "+TimeSlotEntry.entry_end+" and plays "+TimeSlotEntry.source
return "ScheduleEntry starts @ " + ScheduleEntry.entry_start + " and ends @ " + ScheduleEntry.entry_end + " and plays " + ScheduleEntry.source
# ------------------------------------------------------------------------------------------ #
class TimeSlot(db.Model, TimeSlotModel):
class Schedule(db.Model, ScheduleModel):
"""
One specific TimeSlot for a show
One specific Schedule for a show on a timeslot
"""
__tablename__ = 'timeslot'
timeslot_id = Column(Integer, primary_key=True)
__tablename__ = 'schedule'
schedule_id = Column(Integer, primary_key=True, autoincrement=False)
show_id = Column(Integer)
timeslot_start = Column(DateTime, nullable=False)
timeslot_end = Column(DateTime, nullable=False)
show_name = Column(String(255))
show_hosts = Column(String(255))
schedule_start = Column(DateTime, nullable=False)
schedule_end = Column(DateTime, nullable=False)
show_name = Column(String(256))
show_hosts = Column(String(256))
rtr_category = Column(String(256))
comment = Column(String(512))
languages = Column(String(256))
type = Column(String(256))
category = Column(String(256))
topic = Column(String(256))
musicfocus = Column(String(256))
is_repetition = Column(Boolean())
fallback_playlist = Column(String(255))
fallback_pool = Column(String(255))
station_fallback_pool = Column(String(255))
playlist_id = Column(Integer)
timeslot_fallback_id = Column(Integer)
show_fallback_id = Column(Integer)
station_fallback_id = Column(Integer)
@property
def serialize(self):
"""Return object data in easily serializeable format"""
return {
'schedule_id': self.schedule_id,
'show_id': self.show_id,
'schedule_start': self.dump_datetime(self.schedule_start),
'schedule_end': self.dump_datetime(self.schedule_end),
'show_name': self.show_name,
'show_hosts': self.show_hosts,
'is_repetition': self.is_repetition,
'fallback_playlist': self.fallback_playlist,
'fallback_pool': self.fallback_pool,
'station_fallback_pool': self.station_fallback_pool
}
# entry_start = Column(DateTime, nullable=False)
# entry_end = Column(DateTime, nullable=False)
# source = Column(String(255))
def print(self):
return "TimeSlot starts @ "+self.timeslot_start+" and ends @ "+self.timeslot_end+" and plays "+self.source
class TimeSlotEntry(db.Model, TimeSlotEntryModel):
# ------------------------------------------------------------------------------------------ #
class ScheduleEntry(db.Model, ScheduleEntryModel):
"""
One show can have multiple entries
One schedule can have multiple entries
"""
#entry_id = Column(Integer, primary_key=True, autoincrement=True)
__tablename__ = 'timeslotentry'
timeslot_id = Column(Integer, ForeignKey("timeslot.timeslot_id"))
entry_start = Column(DateTime, primary_key=True, nullable=False)
entry_end = Column(DateTime, primary_key=True, nullable=False)
source = Column(String(255))
__tablename__ = 'schedule_entry'
playlist_id = Column(Integer, primary_key=True, nullable=False, autoincrement=False)
entry_num = Column(Integer, primary_key=True, nullable=False, autoincrement=False)
schedule_id = Column(Integer, ForeignKey("schedule.schedule_id"))
entry_start = Column(DateTime, nullable=False)
entry_end = Column(DateTime, nullable=False)
source = Column(String(256))
artist = Column(String(256))
track = Column(String(256))
albumname = Column(String(256))
genre = Column(String(256))
tracknum = Column(String(256))
cdnum = Column(String(256))
year = Column(String(5)) # well should be int, but can also be ""
# def __init__(self, playlist_id, entry_num, schedule_id, entry_start, entry_end, source, artist, track, albumname, genre, tracknum, cdnum, year):
# self.playlist_id = playlist_id
# self.entry_num = entry_num
# self.schedule_id = schedule_id
# self.entry_start = entry_start
# self.entry_end = entry_end
# self.source = source
# self.artist = artist
# self.track = track
# self.albumname = albumname
# self.genre = genre
# self.tracknum = tracknum
# self.cdnum = cdnum
# self.year = year