--- /dev/null
+#!/usr/bin/env python
+
+import os
+import sys
+import psutil
+import signal
+from time import sleep
+from subprocess import Popen
+
+class gs:
+ #debug = 1 spawn and exit
+ #debug = 2 spawn waiting messages
+ #debug = 3 all messages
+ debug = 0
+
+class daemon:
+ def __init__(self):
+ self.basepath='/home/andrew/.soundstage/'
+ self.pidfile='%s%s.pid'%(self.basepath,self.__class__.__name__)
+ self.statusfile='%s%s.status'%(self.basepath,self.__class__.__name__)
+ self.logfile='%s%s.log'%(self.basepath,self.__class__.__name__)
+ self.arguments=[]
+ self.depends=[]
+ self.postrun=[]
+ self.child=None
+
+ def start(self):
+ child=os.fork()
+ if child: return
+ self.writefile(self.pidfile,os.getpid())
+ signal.signal(signal.SIGINT, self.exit)
+ signal.signal(signal.SIGUSR1, self.exit)
+ signal.signal(signal.SIGTERM, self.exit)
+ while True:
+ self.check_depends()
+ self.spawn_daemon()
+ self.monitor()
+ self.cleanup()
+
+ def check_depends(self):
+ if gs.debug > 1 :print ('Checking depends for %s' %self.name)
+ for requirement in self.depends:
+ while self.depends:
+ if gs.debug > 2 :print ('checking for %s%s' %(self.basepath,requirement))
+ if self.readfile('%s%s.status'%(self.basepath,requirement)) == 'Running...':
+ break
+ if gs.debug > 2: print ('%s not running yet...' %requirement)
+ #sleep(.15)
+
+ def monitor_depends(self):
+ if gs.debug > 1 :print ('Montoring depends for %s' %self.name)
+ status=True
+ for requirement in self.depends:
+ if self.readfile('%s%s.status'%(self.basepath,requirement)) != 'Running...':
+ if gs.debug > 0 :print('we have a broken dependency %s'%requirement)
+ status=False
+ return status
+
+ def spawn_daemon(self):
+ if gs.debug != 0 :print('Spawning %s Daemon...'%self.name)
+ self.child_log=open(self.logfile,'w')
+ self.child=Popen(self.arguments, stderr=self.child_log, stdout=self.child_log)
+ #sleep(.5)
+ for run_me in self.postrun:
+ if gs.debug > 1:print('Running assist: %s'%run_me)
+ assistant=assists[run_me]()
+ assistant.run()
+ #sleep(.5)
+ self.writefile(self.statusfile,'Running...')
+
+ def monitor(self):
+ if gs.debug != 0 :print('Running %s monitor...'%self.name)
+ while self.monitor_depends():
+ status=self.child.poll()
+ if gs.debug > 2 :print('%s status: %s' %(self.name, status))
+ if status==None and self.monitor_depends():
+ sleep(5)
+ else:
+ break
+
+ def cleanup(self):
+ if gs.debug != 0 :print('Running %s cleanup...'%self.name)
+ self.writefile(self.statusfile,'Stopping...')
+ if self.child:
+ self.child.terminate()
+ if not self.child.poll():
+ self.child.kill()
+ self.child_log.close()
+ self.writefile(self.statusfile,'Stopped.')
+
+ def exit(self,sig,fan):
+ if gs.debug > 2 :print('%s caught exit signal...'%self.name)
+ #try:
+ self.cleanup()
+ os.remove(self.pidfile)
+ #except:
+ # pass
+ sys.exit()
+
+ def readfile(self,filename):
+ data=''
+ #try:
+ with open(filename, 'r') as file:
+ data=file.read()
+ #except:
+ # pass
+ return data
+
+ def writefile(self,filename,data):
+ #try:
+ with open(filename, 'w') as file:
+ result=file.write(str(data))
+ #except:
+ # pass
+ return result
+
+class jackd(daemon):
+ def __init__(self):
+ super().__init__()
+ self.arguments=['/usr/bin/chrt','89','/usr/bin/jackd','-dalsa','-dhw:Generic','-r48000','-p1024','-n2']
+ self.postrun=['volumes_3','tv_on']
+
+class qjackctl(daemon):
+ def __init__(self):
+ super().__init__()
+ self.arguments=['/usr/bin/qjackctl']
+ self.depends=['jackd','pulse']
+
+class pulse(daemon):
+ def __init__(self):
+ super().__init__()
+ self.arguments=['/usr/bin/pulseaudio','--fail']
+ self.depends=['jackd']
+ self.postrun=['volumes_1','chrt','volumes_2']
+
+ def killall(self):
+ for proc in psutil.process_iter():
+ if proc.name()=='pulseaudio':
+ os.kill(int(proc.pid),signal.SIGKILL)
+
+ def spawn_daemon(self):
+ if gs.debug != 0 :print('Spawning %s Daemon...'%self.name)
+ self.killall()
+ self.child_log=open(self.logfile,'w')
+ self.child=Popen(self.arguments, stderr=self.child_log, stdout=self.child_log)
+ #sleep(.5)
+ for run_me in self.postrun:
+ if gs.debug > 1:print('Running assist: %s'%run_me)
+ if run_me=='chrt':
+ assistant=assists[run_me](self.child.pid)
+ else:
+ assistant=assists[run_me]()
+ assistant.run()
+ #sleep(.5)
+ self.writefile(self.statusfile,'Running...')
+
+class jalv_1(daemon):
+ def __init__(self):
+ super().__init__()
+ self.arguments=['/usr/bin/chrt','84','/usr/bin/jalv.gtk','-l','/home/andrew/.eq_files/FrontSpeakers/','--jack-name','EQ Front']
+ self.depends=['jackd']
+ self.postrun=['xdotool_1']
+
+class jalv_2(daemon):
+ def __init__(self):
+ super().__init__()
+ self.arguments=['/usr/bin/chrt','84','/usr/bin/jalv.gtk','-l','/home/andrew/.eq_files/AuxSpeakers/','--jack-name','EQ Centre']
+ self.depends=['jackd','jalv_1']
+ self.postrun=['xdotool_2']
+
+class jalv_3(daemon):
+ def __init__(self):
+ super().__init__()
+ self.arguments=['/usr/bin/chrt','84','/usr/bin/jalv.gtk','-l','/home/andrew/.eq_files/RearSpeakers/','--jack-name','EQ Rear']
+ self.depends=['jackd','jalv_1','jalv_2']
+ self.postrun=['xdotool_3']
+
+class jalv_4(daemon):
+ def __init__(self):
+ super().__init__()
+ self.arguments=['/usr/bin/chrt','84','/usr/bin/jalv.gtk','-l','/home/andrew/.eq_files/Headphones/','--jack-name','EQ Headphones']
+ self.depends=['jackd','jalv_1','jalv_2','jalv_3']
+ self.postrun=['xdotool_4','xdotool_5','xdotool_6']
+
+class alsa_out_1(daemon):
+ def __init__(self):
+ super().__init__()
+ self.arguments=['/usr/bin/chrt','84','/usr/bin/alsa_out','-j','HDMI_Audio_TV','-d','hw:0,11','-c','2']
+ self.depends=['jackd']
+
+class alsa_out_2(daemon):
+ def __init__(self):
+ super().__init__()
+ self.arguments=['/usr/bin/chrt','84','/usr/bin/alsa_out','-j','HDMI_Left_Monitor','-d','hw:0,7','-c','2']
+ self.depends=['jackd']
+
+class alsa_out_3(daemon):
+ def __init__(self):
+ super().__init__()
+ self.arguments=['/usr/bin/chrt','84','/usr/bin/alsa_out','-j','HDMI_Right_Monitor','-d','hw:0,10','-c','2']
+ self.depends=['jackd']
+
+class kmix(daemon):
+ def __init__(self):
+ super().__init__()
+ self.arguments=['/usr/bin/kmix']
+ self.depends=['pulse']
+ self.postrun=['welcome']
+
+class conky(daemon):
+ def __init__(self):
+ super().__init__()
+ self.arguments=['/usr/bin/conky']
+ self.depends=['jalv_2']
+
+daemons={
+ 'jackd' :jackd ,
+ 'qjackctl' :qjackctl,
+ 'pulse' :pulse ,
+ 'jalv_1' :jalv_1 ,
+ 'jalv_2' :jalv_2 ,
+ 'jalv_3' :jalv_3 ,
+ 'jalv_4' :jalv_4 ,
+ 'alsa_out_1' :alsa_out_1 ,
+ 'alsa_out_2' :alsa_out_2 ,
+ 'alsa_out_3' :alsa_out_3 ,
+ 'kmix' :kmix ,
+ 'conky' :conky ,
+}
+class assist:
+ def __init__(self):
+ self.args=[]
+
+ def run(self):
+ return_code='none'
+ f=open('/dev/null','w')
+ while return_code != 0:
+ child=Popen(self.args,stderr=f,stdout=f)
+ child.wait()
+ return_code=child.returncode
+ f.close()
+ return return_code
+
+class xdotool_1(assist):
+ def __init__(self):
+ self.args=['xdotool','search','--name','EQ4Q Stereo','set_window','--name','Front Speakers','windowmove','1920','0']
+
+class xdotool_2(assist):
+ def __init__(self):
+ self.args=['xdotool','search','--name','EQ4Q Stereo','set_window','--name','Aux Speakers','windowmove','2110','0']
+
+class xdotool_3(assist):
+ def __init__(self):
+ self.args=['xdotool','search','--name','EQ4Q Stereo','set_window','--name','Rear Speakers','windowmove','2300','0']
+
+class xdotool_4(assist):
+ def __init__(self):
+ self.args=['xdotool','search','--name','EQ10Q Stereo','set_window','--name','Headphones','windowmove','2324','0']
+
+class xdotool_5(assist):
+ def __init__(self):
+ pass
+
+ def run(self):
+ windows=['Headphones','Rear Speakers','Aux Speakers','Front Speakers']
+ for window in windows:
+ Popen(['xdotool','search','--name',window,'windowactivate'])
+ sleep(.125)
+ #Popen(['xdotool','search','--name',window,'windowminimize'])
+
+class xdotool_6(assist):
+ def __init__(self):
+ sleep(.5)
+ self.args=['xdotool','set_desktop','0']
+
+class volumes_1(assist):
+ def __init__(self):
+ self.args=['/usr/bin/pactl','set-sink-volume','0','35%']
+
+class volumes_2(assist):
+ def __init__(self):
+ self.args=['/usr/bin/pactl','set-sink-volume','2','100%']
+
+class volumes_3(assist):
+ def __init__(self):
+ self.args=['/usr/sbin/alsactl','restore','-f','/home/andrew/.asound.state']
+
+class welcome(assist):
+ def __init__(self):
+ self.args=['/usr/bin/ogg123','/usr/share/sounds/Oxygen-Sys-Log-In-Long.ogg']
+
+class DoAsYouAreFuckingToldPulseaudio(assist):
+ def __init__(self,pid):
+ self.args=['/usr/bin/chrt','--pid','75',str(pid)]
+
+ def run(self):
+ f=open('/dev/null','w')
+ child=Popen(self.args, stdout=f,stderr=f)
+ child.wait()
+ f.close()
+ return child.poll()
+
+class tv_on(assist):# aka DoAsYouAreFuckingToldXorgServer
+ def __init__(self):
+ self.args=['/home/andrew/bin/TV-On']
+
+assists={
+ 'xdotool_1' :xdotool_1 ,
+ 'xdotool_2' :xdotool_2 ,
+ 'xdotool_3' :xdotool_3 ,
+ 'xdotool_4' :xdotool_4 ,
+ 'xdotool_5' :xdotool_5 ,
+ 'xdotool_6' :xdotool_6 ,
+ 'volumes_1' :volumes_1 ,
+ 'volumes_2' :volumes_2 ,
+ 'volumes_3' :volumes_3 ,
+ 'welcome' :welcome ,
+ 'chrt' :DoAsYouAreFuckingToldPulseaudio,
+ 'tv_on' :tv_on,
+}
+
+def start():
+ for run_me in daemons:
+ current=daemons[run_me]()
+ current.start()
+
+def startsingle(run_me):
+ current=daemons[run_me]()
+ current.start()
+
+def stopsingle(stop_me):
+ try:
+ current=daemons[stop_me]()
+ pidfile=open(current.pidfile,'r')
+ pid=pidfile.read()
+ pidfile.close()
+ Popen(['kill','-SIGUSR1',pid])
+ except:
+ print('Error: Couldn\'t stop %s!' %stop_me)
+
+def stop():
+ for stop_me in daemons:
+ try:
+ current=daemons[stop_me]()
+ pidfile=open(current.pidfile,'r')
+ pid=pidfile.read()
+ pidfile.close()
+ Popen(['kill','-SIGUSR1',pid])
+ except FileNotFoundError:
+ pass
+ init()
+
+def status():
+ for how_am_i in daemons:
+ current=daemons[how_am_i]()
+ statusfile=open(current.statusfile,'r')
+ status=statusfile.read()
+ print('%s status: %s'%(current.__class__.__name__,status))
+
+def usage():
+ print('Usage: %s [start|stop|status|init]'%sys.argv[0])
+ sys.exit(1)
+
+def advusage():
+ print('Advanced Usage: %s module [module name] [start|stop]'%sys.argv[0])
+ sys.exit(1)
+
+def init():
+ for init_me in daemons:
+ current=daemons[init_me]()
+ if not os.path.exists(current.basepath):
+ os.mkdirs(current.basepath)
+ if os.path.exists(current.pidfile):
+ file=open(current.pidfile,'r')
+ pid=file.read()
+ file.close()
+ os.remove(current.pidfile)
+ try:
+ os.kill(int(pid),signal.SIGKILL)
+ except:
+ pass
+ current.writefile(current.statusfile,'Stopped.')
+
+try:
+ arg=sys.argv[1]
+except IndexError:
+ usage()
+
+try:
+ module=sys.argv[2]
+except IndexError:
+ pass
+
+try:
+ action=sys.argv[3]
+except IndexError:
+ action='start'
+
+if arg=='help':
+ usage()
+elif arg=='start':
+ start()
+elif arg=='module':
+ if action=='start':
+ startsingle(module)
+ elif action=='stop':
+ stopsingle(module)
+ elif action=='restart':
+ stopsingle(module)
+ sleep(5)
+ startsingle(module)
+ else:
+ advusage()
+elif arg=='stop':
+ stop()
+elif arg=='status':
+ status()
+elif arg=='restart':
+ stop()
+ sleep(5)
+ start()
+elif arg=='init':
+ init()
+else:
+ usage()