diff --git a/fmtools.spec b/fmtools.spec index c38aeee..6989b13 100644 --- a/fmtools.spec +++ b/fmtools.spec @@ -1,9 +1,10 @@ %bcond_with pylirc +%bcond_without pulse Summary: Simple Video for Linux radio card programs Name: fmtools Version: 2.0.1 -Release: 6%{?dist} +Release: 9%{?dist} License: GPLv2+ Group: Applications/Multimedia URL: http://benpfaff.org/fmtools @@ -36,8 +37,10 @@ Requires: python, notify-python # Not available on RHEL6 %{?with_pylirc:Requires: python-lirc, python-mtTkinter} Requires: vorbis-tools, tkinter, alsa-utils +%if %{with pulse} Requires: pulseaudio-utils BuildArch: noarch +%endif %description tkradio This package provides a GUI for %{name}, with lirc support. @@ -98,6 +101,15 @@ rm -rf %{buildroot} %changelog +* Sun Mar 27 2011 Paulo Roma 2.0.1-9 +- Using signal module. + +* Sun Mar 13 2011 Paulo Roma 2.0.1-8 +- Using Master for controling the volume. + +* Tue Mar 10 2011 Paulo Roma 2.0.1-7 +- Restoring the saved state (persistency). + * Sat Feb 26 2011 Paulo Roma 2.0.1-6 - Ported to python3. diff --git a/tkradio.py b/tkradio.py index 855d941..ad7d342 100644 --- a/tkradio.py +++ b/tkradio.py @@ -4,8 +4,8 @@ # Date: 23/12/2009 # The radio is turned off on exit. -import os, sys, string -import datetime, time +import os, sys, string, pickle, math +import datetime, time, signal from threading import Thread from subprocess import Popen, PIPE @@ -77,6 +77,8 @@ FM = "/usr/bin/fm" # fmtools OGG = "/usr/bin/oggenc" # vorbis-tools RPNG = "/usr/share/pixmaps/radio.png" RGIF = "/usr/share/fmtools/radio.gif" +#CHANNEL = "PCM" +CHANNEL = "Master" class IRRec(Thread): """Class for interacting with lirc.""" @@ -130,7 +132,7 @@ class IRRec(Thread): elif ( code["config"] == "loop" ): loopon() elif ( code["config"] == "quit" ): - quit() + fini() else: # Print all the configs... print ( "Command: %s, Repeat: %d" % (code["config"], code["repeat"]) ) @@ -166,7 +168,7 @@ class FMRec(Thread): tid = 0 if ( self.__pid ): - os.kill ( self.__pid, 9 ) + os.kill ( self.__pid, signal.SIGTERM ) self.__pid = 0 self.__on = False @@ -281,18 +283,15 @@ def changeStation ( st ): freq.insert(0,st.split()[0]) station.set ( st ) -def quit(msg=""): +def fini(): """Quit the radio.""" - if ( msg ): - print (msg) - else: - radio ("off") + radio ("off") # kill all threads if ( fmrec ): fmrec.stop() if ( irrec ): irrec.stop() - if ( lid ): os.kill ( lid, 9 ) - + if ( lid ): os.kill ( lid, signal.SIGTERM ) + os._exit (0) def mute(): @@ -311,11 +310,19 @@ def mute(): btmute.set ( "Off" ) btm.config(state=NORMAL) +def setVolume ( v ): + os.system(MIXER + " -q -c 0 set " + CHANNEL + " " + str(v) + "%") + +def getVolume ( ): + vol = os.popen (MIXER + " -c 0 get " + CHANNEL + " | " + GREP + " -E \"%\"").readline() + i = str.find (vol,"%") + j = str.find (vol,"[",0,i) + return int(vol[j+1:i]) + def on_move(value=0): """Use slider position to set the volume.""" - v = scale.get() - os.system(MIXER + " -q -c 0 set PCM "+str(v)+"%") + setVolume ( scale.get() ) def volup (): """Increase the volume.""" @@ -323,7 +330,7 @@ def volup (): v = scale.get() + 5 if ( v > 100 ): v = 100 scale.set ( v ) - os.system(MIXER + " -q -c 0 set PCM "+str(v)+"%") + setVolume ( v ) def voldown(): """Decrease the volume.""" @@ -331,7 +338,7 @@ def voldown(): v = scale.get() - 5 if ( v < 0 ): v = 0 scale.set ( v ) - os.system(MIXER + " -q -c 0 set PCM "+str(v)+"%") + setVolume ( v ) def enter (): "Enter a new frequency.""" @@ -400,7 +407,7 @@ def loop(): n.show() else: if ( lid ): - os.kill ( lid, 9 ) + os.kill ( lid, signal.SIGTERM ) lid = 0 def loopon(): @@ -458,10 +465,25 @@ def getpid(proc): aid = aid.replace('\n','') return str2num(aid) +class radioState: + """Holds the state of the radio (used for persistency).""" + + def __init__ ( self, intial_station ): + self.volume = getVolume() + self.loop = "OFF" + self.mute = False + self.station = intial_station + self.pos = "" + + def __str__ (self): + return " Volume = %s\n Loop = %s\n Mute = %d\n Station = %s\n Pos = %s\n" % \ + ( self.volume, self.loop, self.mute, self.station, self.pos ) + def main (argv=None): """Main program.""" global scale # volume scale + global state # toggle mute/umute global station # variable for the station radio buttons global btmute # variable for the text in the mute button global btm # mute button @@ -473,11 +495,23 @@ def main (argv=None): global loopvar # variable for setting loopback on/off global lid # loopback process id + def cleanup(): + savedState.volume = scale.get() + savedState.loop = loopvar.get() + savedState.mute = state + savedState.station = station.get() + savedState.pos = mw.geometry() + pf = open(statfile,'wb') + pickle.dump ( savedState, pf ) + pf.close() + # print ( savedState ) + raise SystemExit + if argv is None: argv = sys.argv pyversion = str.split(sys.version)[0] - print ( "Python Version: ", pyversion ) + print ( "Python Version: %s" % pyversion ) # check whether tkradio is already running stat = os.popen (PS + " aux | " + GREP + " -E \"python(" + pyversion[0:3] + ")? " + argv[0] + "\"").readline() @@ -487,15 +521,27 @@ def main (argv=None): if ( cid != int(pid) ): sys.exit ( "%s is already running: pid = %s" %(argv[0], pid) ) + path = os.environ.get("HOME") + statfile = path + '/.tkradio' + if (sys.hexversion > 0x03000000): + statfile += '3' + if ( not os.path.exists (statfile) ): + savedState = radioState(radbut) + else: + pf = open(statfile,'rb') + savedState = pickle.load(pf) + pf.close() + mw = Tk() # do not resize the radio mw.resizable(False,False) station = StringVar() - station.set ( radbut ) + station.set (savedState.station) btmute = StringVar() - btmute.set ( "Off" ) + state = not savedState.mute + btmute.set ( "OFF" ) top = Frame(); top.pack() bbt = Frame(); bbt.pack() @@ -510,9 +556,9 @@ def main (argv=None): # sets the recording type: alsa or pulse if ( set_rec_type() ): - Label(top, text = 'volume: pulse').pack() + Label(top, text = 'pulse: '+CHANNEL).pack() else: - Label(top, text = 'volume: alsa').pack() + Label(top, text = 'alsa: '+CHANNEL).pack() # make tuner buttons for st in fmstations: @@ -521,7 +567,7 @@ def main (argv=None): scale = Scale(top, from_=0, to=100, orient=HORIZONTAL, command=on_move, bd=0, sliderlength=10, width=5, showvalue=0) scale.pack(side='top') - scale.set(volume) + scale.set(savedState.volume) # the current radio frequency Button(bbt,text="<", command = previous).pack(side="left",anchor=E) @@ -531,7 +577,7 @@ def main (argv=None): freq.insert(0,station.get()) freq.pack(side="bottom") - recvar = StringVar() # creates a checkbutton for the alarm state + recvar = StringVar() # creates a checkbutton for the recording state loopvar = StringVar() # creates a checkbutton for the loopback recvar.set ( "OFF" ) aid = getpid ( str.rsplit(REC,'/',1)[1] ) @@ -539,10 +585,11 @@ def main (argv=None): loopvar.set ( "ON" ) lid = aid else: - loopvar.set ( "OFF" ) + loopvar.set ( savedState.loop ) + loop () # create quit and mute buttons - Button(top,text="Exit", command = quit).pack(side="right") + Button(top,text="Exit", command = cleanup).pack(side="right") btm=Button(top,text="Off", command = mute, textvariable = btmute) btm.pack(side="left") Checkbutton (top, text="Rec", variable=recvar, onvalue="ON", offvalue="OFF", command=rec).pack(side="top",anchor=W) @@ -554,7 +601,7 @@ def main (argv=None): # turn the radio on setstation() - radio ("on") + mute() # set an icon for the window icon_img = PhotoImage(file=RGIF) @@ -564,10 +611,14 @@ def main (argv=None): if ( use_lirc ): start_irrec() - top.mainloop() + mw.protocol("WM_DELETE_WINDOW", cleanup) -try: - if __name__=="__main__": - sys.exit(main()) -except (KeyboardInterrupt,SystemExit) as msg: - quit(msg) + if ( savedState.pos ): mw.geometry(savedState.pos) + + mw.mainloop() + +if __name__=="__main__": + try: + sys.exit(main()) + except (KeyboardInterrupt,SystemExit): + fini()