Difference between revisions of "Fm radio"
(→remoteRadio.sh) |
(→Channel changing with a remote through lirc) |
||
Line 315: | Line 315: | ||
8 october 2014: Added support for non IVTV cards. ivtv-radio can tune and play them, but the audio setup is different. Mainly for cards cable connected to an audio-card. Also added comments to radioFunctions.conf and corrected some errors. | 8 october 2014: Added support for non IVTV cards. ivtv-radio can tune and play them, but the audio setup is different. Mainly for cards cable connected to an audio-card. Also added comments to radioFunctions.conf and corrected some errors. | ||
+ | 16 october 2014: Added a check whether the TV-tuner is known and in use by MythTV. If so the radio refuses to start. If it is unknown the TV refuses to tune. | ||
===The scripts=== | ===The scripts=== | ||
Line 326: | Line 327: | ||
- the gentoo style runscript: radiocontrol | - the gentoo style runscript: radiocontrol | ||
- and its accompanying config file | - and its accompanying config file | ||
+ | - querytuner.py. Checks the TV tuner status in MythTV. Tested with 0.27.3 | ||
Further are the following files created as needed: | Further are the following files created as needed: | ||
Line 984: | Line 986: | ||
[ $RadioStarted -eq 1 ] && RadioLog 1 "Radio already Started" && return | [ $RadioStarted -eq 1 ] && RadioLog 1 "Radio already Started" && return | ||
+ | getTVstatus | ||
+ | [ $? -eq -2 ] && RadioLog 1 "Error retrieving TV status" | ||
+ | [ $? -eq -1 ] && RadioLog 1 "TV card not found" | ||
+ | [ $? -gt 0 ] && RadioLog 1 "TV card busy" && return | ||
[ $MainCardNr -ne $AudioCardNr ] && SetMute 0 $MainCardNr | [ $MainCardNr -ne $AudioCardNr ] && SetMute 0 $MainCardNr | ||
Line 1,035: | Line 1,041: | ||
StartRadio | StartRadio | ||
fi | fi | ||
+ | } | ||
+ | function getTVstatus { | ||
+ | ${ScriptDir}/querytuner.py --card ${VideoDevice} | ||
+ | return $? | ||
} | } | ||
Line 1,163: | Line 1,173: | ||
local Frequency=$1 | local Frequency=$1 | ||
RadioLog 32 "TuneTV called" | RadioLog 32 "TuneTV called" | ||
+ | getTVstatus | ||
+ | [ $? -eq -2 ] && RadioLog 1 "Error retrieving TV status" && return | ||
+ | [ $? -eq -1 ] && RadioLog 1 "TV card not found" && return | ||
StopRadio | StopRadio | ||
${TVtuneCommand} --device=$VideoDevice --frequency=$Frequency \ | ${TVtuneCommand} --device=$VideoDevice --frequency=$Frequency \ | ||
Line 1,358: | Line 1,371: | ||
MaxLogSize=10240 | MaxLogSize=10240 | ||
MaxOldLogs=5 | MaxOldLogs=5 | ||
+ | </pre> | ||
+ | |||
+ | ====querytuner.py==== | ||
+ | This is a small python script to check the tv-tuner status run it with --help to see its options: | ||
+ | <pre> | ||
+ | #!/usr/bin/env python2 | ||
+ | # -*- coding: utf-8 -*- | ||
+ | |||
+ | import argparse, socket, urllib2, sys | ||
+ | from urllib2 import urlopen | ||
+ | from xml.etree import cElementTree as ET | ||
+ | |||
+ | parser = argparse.ArgumentParser(description='Get Status of Backend Encoders.') | ||
+ | |||
+ | parser.add_argument('-c', '--card', type=str, required=False, | ||
+ | metavar='<device>', default='/dev/video0', | ||
+ | help='tv capture device, defaults to </dev/video0>') | ||
+ | |||
+ | parser.add_argument('-m', '--host', type=str, required=False, | ||
+ | metavar='<hostname>', default=socket.gethostname(), | ||
+ | help='backend dns hostname, defaults to the local hostname') | ||
+ | |||
+ | parser.add_argument('-v', '--verbose', action='store_true', | ||
+ | required=False, help='print the result to the screen') | ||
+ | |||
+ | args = parser.parse_args() | ||
+ | |||
+ | URL0 = 'http://{}:6544//Myth/GetHostName'.format(args.host) | ||
+ | try: | ||
+ | response = ET.parse(urlopen(URL0)) | ||
+ | root = response.getroot() | ||
+ | except: | ||
+ | if args.verbose: | ||
+ | print 'GetHostName failed, is the backend running?' | ||
+ | sys.exit(-2) | ||
+ | |||
+ | URL1 = 'http://{}:6544/Capture/GetCaptureCardList?HostName={}' \ | ||
+ | .format(args.host, root.text) | ||
+ | try: | ||
+ | response = ET.parse(urlopen(URL1)) | ||
+ | except: | ||
+ | if args.verbose: | ||
+ | print 'GetCaptureCardList failed, is the backend running?' | ||
+ | sys.exit(-2) | ||
+ | |||
+ | for element1 in response.findall('CaptureCards/CaptureCard'): | ||
+ | if element1.findtext('VideoDevice') == args.card: | ||
+ | URL2 = 'http://{}:6544/Dvr/GetEncoderList'.format(args.host) | ||
+ | try: | ||
+ | response = ET.parse(urlopen(URL2)) | ||
+ | except: | ||
+ | if args.verbose: | ||
+ | print'GetEncoderList failed, is the backend running?' | ||
+ | sys.exit(-2) | ||
+ | for element2 in response.findall('Encoders/Encoder'): | ||
+ | if element2.findtext('Id') == element1.findtext('CardId'): | ||
+ | if args.verbose: | ||
+ | if int(element2.findtext('State')) == -1: | ||
+ | print 'The status of %s on %s is: -1, not Connected' \ | ||
+ | % (args.card, args.host) | ||
+ | elif int(element2.findtext('State')) == 0: | ||
+ | print 'The status of %s on %s is: 0, Inactive' \ | ||
+ | % (args.card, args.host) | ||
+ | elif int(element2.findtext('State')) == 1: | ||
+ | print 'The status of %s on %s is: 1, watching Live TV' \ | ||
+ | % (args.card, args.host) | ||
+ | elif int(element2.findtext('State')) == 7: | ||
+ | print 'The status of %s on %s is: 7, Recording' \ | ||
+ | % (args.card, args.host) | ||
+ | else: | ||
+ | print 'The status of %s on %s is: %s' % \ | ||
+ | (args.card, args.host, \ | ||
+ | element2.findtext('State')) | ||
+ | sys.exit(int(element2.findtext('State'))) | ||
+ | break | ||
+ | break | ||
+ | if args.verbose: | ||
+ | print 'The capture device is not found in MythTV' | ||
+ | sys.exit(-1) | ||
</pre> | </pre> | ||
Revision as of 00:56, 16 October 2014
This article is to provide information on how to integrate FM radio into MythTV. This is based on Integrate Sirius but I wanted to post details on how to make it work for FM radio too.
I only have a Hauppage PVR-150 card. I cannot speak to other setups, but please feel free to edit this page to include information for others.
Note: The method used here will only work on a mythbox that has an FM Radio card (such as a PVR-150) installed locally. It does not matter if it is only a frontend box or a backend+frontend box, but the hardware must be in the box you are setting this up on.
Note: this is NOT a plug-in and is basically a hack but when completed it looks just like a plug-in.
Contents
Article from 10,000 feet
What this article is...
This article IS about:
- Setting up MythTV to play FM Radio from a Hauppage Wintv PVR-150
- How-To use programs that other people wrote (and are not affiliated with MythTV)
- How-To integrate everything with the default MythTV menu theme
What this article is not...
This article IS NOT:
- How-To perfectly integrate with your particular MythTV GUI (we only cover the default menu theme)
- An FM Radio Plug-in for MythTV
- An audio stream capture how-to
What is required
Only a working installation of MythTV is required with a working PVR-150. Also you must be able to receive and play an FM signal on your PVR-150. To verify this do the following:
# ivtv-radio -s
This will scan the FM band for channels. Next do the following:
# ivtv-radio -f <frequency of channel>
for example:
# ivtv-radio -f 103.3
if this does not work, please see the [web page] for detail on how to make this work and return here when you have this working.
Hacking it together
OK, now we are going to write a couple of über-simple shell scripts that we will use to make MythTV work with your FM tuner. You will notice that these are simple, novice scripts that are pretty crude. This hasn't been called it a "hack" for nothing.
Create files
We need to create a couple of files so find a nice place you can create and execute them from. Personally, I put them in /usr/bin
# vi mythfm
#!/bin/bash # Control PVR-150 FM in Myth if [ "$1" = "wbfo" ]; then # First, we'll kill off any other stream that may be playing /usr/bin/mythfm_kill echo "I'm about to play:" $1 /usr/local/bin/ivtv-radio -f 88.7 & elif [ "$1" = "wbuf" ]; then # First, we'll kill off any other stream that may be playing /usr/bin/mythfm_kill echo "I'm about to play:" $1 /usr/local/bin/ivtv-radio -f 92.9 & else exit 1 fi exit 0
You are going to want to change this for the stations you want. Add more "elif" statements to add more stations. Change the first line of each statement to include the callsign of the station and change the last line of each to add the station's FM frequency.
# vi mythfm_kill
#!/bin/bash # Kill mythfm pkill -f aplay
Now you will want to make them both executable:
# chmod a+x mythfm*
Test scripts
Now, pull up a command window and run one of the commands we just "made"
$ mythfm wbfo
Do you hear the stataion without having to enter a single thing in the command window? That's good, now use this to kill the stream
$ mythfm_kill
V4L-Based Radios
The following combined tune/kill script uses a more general approach that works for v4l-based radio devices. The basic idea here is that we first configure the tuner for the station we want, then capture from the radio device and forward to the output device. This method requires that you have fmtools and sox installed. For this to work you must also have alsa-oss support working. This can also be done with pure alsa (look at the sox manpage) but using oss was easier for me to get working. Save the following script to /usr/local/bin/mythfm then replace calls to "mythfm_kill" in the menus created below with "mythfm kill". It should be fairly obvious how to add stations to this script and add them to the menus.
-- work(dot)eric(at)gmail(dot)com
#!/bin/bash # tune radio function fmtune { fm -q -T- $1 on > /dev/null & sleep 1 sox -q -r 32000 -w -c 2 -t ossdsp /dev/audio1 \ -r 44100 -w -c 2 -t ossdsp /dev/audio & } # kill radio function fmkill { killall -q /usr/bin/sox sleep 1 killall -q /usr/bin/fm } # Station: Jack FM (93.1 MHz) if [ "$1" = "jack" ] ; then echo "Tuning to Jack FM" fmkill ; sleep 1 ; fmtune 93.1 # Station: Star (98.7 MHz) elif [ "$1" = "star" ] ; then echo "Tuning to Star" fmkill ; sleep 1 ; fmtune 98.7 # Station: Kill Radio elif [ "$1" = "kill" ] ; then echo "Turning Off Radio" fmkill ; sleep 1 ; fm -q off & else # print usage statement echo "Usage:" `basename $0` "[station]" echo " stations: jack star kill" exit 1 fi exit 0
Setting up the MythTV GUI
At this point, you should be able to listen to (and kill) streams from the command line with no user intervention... that's 1/2 the battle. Now, we are going to hack a couple of buttons onto the default menu theme.
Note: If you are currently running MythTV version 0.20 or higher chances are that you're using the default menu theme. No, not the actual MythTV theme, just the menu theme. To check out which one you're using do this in Myth: Utilities / Setup (or Setup) -> Setup -> Appearance -> and at the bottom of the first options page you will see the menu themes selection box, we will be hacking into "Default" so make sure it's set to that one. If you use classic or DVR you can change some of the commands below so that your work is being done on that particular theme (just add /themes/classic or /themes/DVR respectively to the "cd" commands below).
Backup the default theme
# cd /usr/share/mythtv # tar cfvz default_backup.tar.gz *.xml
I use the v option because it's an easy way to verify (VIA verbose) what files were put into the tar ball.
Hack the default theme
I'm only going to show you the 2 required changes to get this hack to work.
I added the following to my mainmenu.xml file.
# cd /usr/share/mythtv # vi mainmenu.xml
<button> <type>MUSIC</type> <text>Play Radio</text> <action>MENU fmmenu.xml</action> </button>
Then, I created the fmmenu.xml file (be sure to add all of the stations you want access to):
# vi fmmenu.xml
Warning: The following code is wrong. Instead of using EXEC
, the <action>
should use EXECTV
, which will pass as an argument to the script the video device that should be used. Then, the script mythfm
should be modified to use the argument to detect which card should be used and tune the radio on that card. By using EXECTV
, the <action>
tells MythTV that the tuner it provides is not available for any recordings.
<mythmenu name="FMMENU"> <button> <type>MUSIC</type> <text>88.7 - WBFO - NPR</text> <action>EXEC /usr/bin/mythfm wbfo</action> </button> <button> <type>MUSIC</type> <text>92.9 - WBUF - Jack FM</text> <action>EXEC /usr/bin/mythfm wbuf</action> </button> <button> <type>TV_DELETE</type> <text>Stop Listening</text> <action>EXEC /usr/bin/mythfm_kill</action> </button> </mythmenu>
Tag definitions
OK, now the tag definitions for the above xml file
- "button" tells the theme to paint a button on the screen
- "type" tells the theme what image to use for the button
- "text" tells MythTV what button text to put on the screen
- "action" tells MythTV what to do when you select the button
Why it works
You have to wrap mythfm around the stream because when MythTV runs the EXEC it waits for a response before it releases the button. mythfm simply kicks off ivtv-radio and tells MythTV that it's finished executing. You are going to have to modify this file if you want to add another language tag or if you want to add additional channels, it should be simple to see what needs done to make it work just be sure that you create the soft links before you try to add a button or it won't play the stream.
Additional Setup and Usage Notes
- The stream will play until you choose the "Stop Listening" button on the GUI (or the mythtv_kill script is executed)
- When you're listening to a station, it locks up the Video Card device for MythTV which. This means that you are using up one of your 'inputs' for video recording or watching TV. You must have more tuner cards in order to listen to FM on a PVR-150 and watch video at the same time.
- With MythDora 4.0 ivtv-radio is in /usr/bin. Modify scripts accordingly.
- If you have 2 PVR-150s then the radio may be on /dev/radio1. If so, add -d /dev/radio1 to the ivtv-radio lines. If the radio is at /dev/radio1 then the PCM device to use is /dev/video25. Add -i /dev/video25 to use this PCM device.
Screen shots
The FM station selection menu:
Alternative (Only for IVTV)
There are several issues with the method described above, like
- MythTV does not know that the tuner is busy and might try to use it
- Not being able to schedule radio recordings
The solution is to add the radio as a video device to MythTV. This allows you to control the radio as a normal channel in MythTV.
In mythtv-setup, add a new Video Source called radio.
Under Input Connections, set the Composite source (of the tuner card with the radio) to radio. Set all External Channel Commands for that tuner to "/usr/local/sbin/mythtv-fm.sh".
For each radio station/frequency that you want to be able to tune in to, you need to add a channel in the Channel Editor. Set the frequency to the 10 times the frequency. For example, if the FM frequency is 102.1, set it to 1021 in the Channel Editor.
And here is the script:
# vi /usr/local/sbin/mythtv-fm.sh
#!/bin/sh -x channel=${1:0} radio=/dev/radio0 video=/dev/video0 log=/var/log/mythtv/mythtv-fm.log #log=/dev/null echo Closing any ivtv-radio applications >> $log if [ "$channel" -lt 800 ]; then pkill -f ivtv-radio echo Not changing to channel $channel >> $log elif [ "$channel" -gt 1100 ]; then int=$(($channel / 1000)) echo Changing video freq to $int >> $log pkill -f ivtv-radio && sleep 1 && /usr/bin/ivtv-tune -d $video -f $int >> $log && sleep 1 || /usr/bin/ivtv-tune -d $video -f $int >> $log else int=$(($channel / 10)) frac=$(($channel - 10 * $int)) freq=`printf "%d.%d" $int $frac` echo Changing FM freq to $freq >> $log pkill -f ivtv-radio && sleep 1 ivtv-radio -d $radio -f $freq -j >> $log & fi exit 0
You will need to change /dev/radio0 and /dev/video0 to your radio and video devices. To disable logging, uncomment the #log line.
Basically what is happening now is that all your channel change requests for that tuner is handled by this script. It first kills any ivtv-radio processes. It then checks the frequency and if the frequency is too high for FM, it is assumed to be TV and the ivtv-tune is called to change the TV channel. If the frequency is too low, it is just ignored.
This is based on http://readlist.com/lists/mythtv.org/mythtv-users/3/15176.html.
Channel changing with a remote through lirc
I tried all the above, but got frustrated that I had all the time to turn on the TV set to play the radio. I simply wanted to turn on/off radio playing, change channels and volume with a remote. After a lot of thinking and trying I came up with the following set of scripts using ircat to receive the lirc commands which in turn pipes them to a fifo file. The main script consists of a loop that listens to this pipe and performs actions on the base of those received commands. Commands can also be 'echoed' in the pipe through other means. So can you quit the script with 'echo quit > /tmp/mythtv-fiforadio'. Also the commands are not restricted to playing and controlling the radio. It is mostly compatible with and has partially integrated the above solutions. Ones I got started I got carried away. It contains now a lot of extras, like logging, sanity checks etc. The lirc commands you want to sent to the script are defined in ~/.lircrc or where you have placed it. I myself have simlinked it to ~/lircrc, ~/.mythtv/.lircrc and ~/.mythtv/lircrc. So it will be found.
begin prog = mythradio button = Radio repeat = 0 config = start_stop_radio end
prog is the same string as defined in the 'LircProgID' variable. its what ircat listens to.
button is the buttonname in your /etc/lirc/lircd.conf file
config is the string send to the fifo pipe and should exist in the case/esac statement in remoteRadio.sh.
Be sure not to use the same buttons you are using in MythTV. They probably will be received by both, creating unexpected results. I use a separate remote for the radio.
Most of the rest is explained in the scripts themselves. If you have questions put them on the mythtv-users list. I'll probably see them.
If anybody can put an adapted runscript for other distributions, that would be nice
8 october 2014: Added support for non IVTV cards. ivtv-radio can tune and play them, but the audio setup is different. Mainly for cards cable connected to an audio-card. Also added comments to radioFunctions.conf and corrected some errors. 16 october 2014: Added a check whether the TV-tuner is known and in use by MythTV. If so the radio refuses to start. If it is unknown the TV refuses to tune.
The scripts
It exists out of the following files that should by default be placed in ~/.scripts:
- the main script: remoteRadio.sh - the script containing the functions: radioFunctions.sh - the config file: radioFunctions.conf
Placed in ~/.ivtv
- the file with on every line a channelname and its frequency separated by a ';': radioFrequencies.
Placed in the the run script directory (on gentoo /etc/init.d and /etc/conf.d)
- the gentoo style runscript: radiocontrol - and its accompanying config file - querytuner.py. Checks the TV tuner status in MythTV. Tested with 0.27.3
Further are the following files created as needed: in ~/.scripts:
- a fmmenu.xml file as described before based on the radioFrequencies file
in ~/.ivtv:
- the configfile for iradio: iradio.xml. also based on the radioFrequencies file - several small files to save lastvolume and channel
in /tmp:
- the fifo pipe: mythtv-fiforadio
remoteRadio.sh
This is the main script 'remoteRadio.sh' with explanation in between:
#!/bin/bash # Copyright 2014 Hika van den Hoven # Distributed under the terms of the GNU General Public License v2 # $Header: $ # Be sure only to place functions in the function file # Do not declare global variables as they get blocked on reloads! # Declare them here and put the values in the config file # # If you don't run this script through the radiocontrol service, # then set variable 2 through 5 here instead of through the service # by editing the default values below. Leave RADIO_UID untouched # For now, you have to do this if you want to use iradio # for on-screen display of the chosen channel. # When run as service it can't find the X-display. declare RADIO_UID=${1:-"$USER"} declare ScriptDir=${2:-"${HOME}/.scripts"} declare FiFo=${3:-"${RADIO_UID}-fiforadio"} declare LircProgID=${4:-"mythradio"} declare LogFile=${5:-"/var/log/mythradio/mythtest"} declare RADIO_FUNCTIONS_LOADED="no" declare Myth_ConfigFile declare RadioDir declare MainRadioFreqFile declare IVTVRadioFreqFile declare MythMenuDir declare MythMenuFile declare -i LogLevel=0 declare -i MaxLogSize=0 declare -i MaxOldLogs=0 declare -i LogErrors=0 declare -i LogStdOut=0 declare DBContactString="" declare Qtabel declare -i QFields=0 declare -a QFNames declare -a QFValues declare -ai QFTypes declare -i QAnswers=0 declare -a QANames declare -a QAValues declare -i QOrder=0 declare -a QONames declare -ai QODirection declare -i QRecCount=0 declare -a QRecords declare -i RadioCardType declare VideoDevice declare RadioDevice declare RadioOut declare -i UseIRadio=0 declare -i RadioStarted=0 declare aPlayPCM declare -i AudioCardNr=0 declare -i MainCardNr=0 declare -i MaxVolume=0 declare MasterMixerCtrl declare -i SavedMasterVolume=0 declare DefaultMixerCtrl declare -i SavedDefaultVolume=0 declare SourceSelectCtrl declare SourceSelect declare SourceVolumeCtrl declare CaptureVolumeCtrl declare MixerCommand declare PlayCommand declare RadioCommand declare iRadioCommand declare TuneCommand declare TVtuneCommand declare -i ChannelCount=0 declare -a ChannelFrequency declare -a ChannelName declare -i iRadioPID=0 declare -i RadioPID=0 declare -i aPlayPID=0 declare LircCmd declare PressTekst="" declare -i RETVAL=0 declare remoteRadio="yes" function LoadFunctions { [ -f "${ScriptDir}/radioFunctions.sh" ] || return 1 [ "$RADIO_FUNCTIONS_LOADED" == "yes" ] || . "${ScriptDir}/radioFunctions.sh" "daemon" RETVAL=$? [ ${RETVAL} -ne 0 ] && return $RETVAL . "${ScriptDir}/radioFunctions.conf" CheckFiles RETVAL=$? return $RETVAL } # Initiate Logging function RotateLog { [ -f ${LogFile}.log ] || return [ $MaxLogSize -gt 0 ] || return local -i i local -i LogSize=`ls -l ${LogFile}.log | cut -d' ' -f5` if [ $LogSize -gt $MaxLogSize ]; then WriteLog 1 "Rotating ${LogFile}.log" [ $MaxOldLogs -gt 0 ] || MaxOldLogs=1 [ -f ${LogFile}.${MaxOldLogs} ] && rm -f ${LogFile}.${MaxOldLogs} for i in `seq ${MaxOldLogs} -1 2`; do [ -f ${LogFile}.$((i-1)) ] && \ mv ${LogFile}.$((i-1)) ${LogFile}.${i} done [ -f ${LogFile}.log ] && mv ${LogFile}.log ${LogFile}.1 touch ${LogFile}.log chmod 644 ${LogFile}.log [ ! -f ${LogFile}.error.1 ] || rm ${LogFile}.error.1 [ ! -f ${LogFile}.error ] || mv ${LogFile}.error ${LogFile}.error.1 touch ${LogFile}.error chmod 644 ${LogFile}.error [ ! -f ${LogFile}.stdout.1 ] || rm ${LogFile}.stdout.1 [ ! -f ${LogFile}.stdout ] || mv ${LogFile}.stdout ${LogFile}.stdout.1 touch ${LogFile}.stdout chmod 644 ${LogFile}.stdout fi } function WriteLog { local -i ErrorLevel=$1 local LogText="$2" RotateLog LogText="`date`: $LogText" [ $((ErrorLevel & LogLevel)) -gt 0 ] && echo "$LogText" >> "$LogFile".log } [ -f "${ScriptDir}/radioFunctions.conf" ] || (WriteLog 1 "${ScriptDir}/radioFunctions.conf not found!" && exit 1) [ "$RADIO_CONFIG_LOADED" == "yes" ] || . "${ScriptDir}/radioFunctions.conf" [ $LogErrors -eq 1 ] && exec 4<> "${LogFile}.error" && exec 2>&4 [ $LogStdOut -eq 1 ] && exec 3<> "${LogFile}.stdout" && exec 1>&3 # Check for Errors in the functions WriteLog 1 "Starting RadioControl as user ${RADIO_UID} on $HOSTNAME" LoadFunctions if [ $? -ne 0 ]; then WriteLog 1 "Closing with Error $RETVAL" [ $LogStdOut -eq 1 ] && exec 3>&- [ $LogErrors -eq 1 ] && exec 4>&- exit $RETVAL fi # Kill a present ircat under this user # Create the FIFO if it doesn't exists # make it world writable but only user readable # And finally start ircat WriteLog 1 "Starting ircat for LircName '${LircProgID}' through '/tmp/${FiFo}'" [ "$(pgrep -u ${RADIO_UID} ircat)" ] && pkill -u ${RADIO_UID} ircat [ ! -p "/tmp/${FiFo}" ] && mkfifo "/tmp/${FiFo}" && chmod 622 "/tmp/${FiFo}" /usr/bin/ircat ${LircProgID} >"/tmp/${FiFo}" & WriteLog 1 "ircat Started" WriteLog 1 "RadioControl Started" while true; do # Load the functions. Placed here in the loop, # so they can be reloaded by echoing "reload" to the FIFO LoadFunctions [ $? -ne 0 ] && break ReadChannels # Start the listening loop while read LircCmd; do # This is so that every second equal command is ignored # One of my remotes gives a signal on press and on release # You can check if you need it this by typing ircat ${LircProgID} # on the commandline and pressing some buttons if [ "$PressTekst" == "$LircCmd" ]; then PressTekst="" else PressTekst="$LircCmd" # The actions to take on receiving a string through the FIFO buffer. # Either from ircat or by echoing it to the buffer. # Most are functions in "${ScriptDir}/radioFunctions.sh" case $PressTekst in "suspend") WriteLog 3 "'${PressTekst}' Command received and processed" PressTekst="" Stopradio sleep 1 ${ScriptDir}/Suspend.sh;; [1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) WriteLog 2 "'${PressTekst}' Command received and processed" SelectChannelNumber ${PressTekst} ;; "Ch+") WriteLog 2 "'${PressTekst}' Command received and processed" [ $RadioStarted -eq 0 ] || ChannelUp ;; "Ch-") WriteLog 2 "'${PressTekst}' Command received and processed" [ $RadioStarted -eq 0 ] || ChannelDown ;; "mute") WriteLog 2 "'${PressTekst}' Command received and processed" ToggleRadioMute;; "V+") WriteLog 2 "'${PressTekst}' Command received and processed" RadioVolumeUp;; "V-") WriteLog 2 "'${PressTekst}' Command received and processed" RadioVolumeDown;; "restart_radio"|"start_radio"|"play_radio") WriteLog 2 "'${PressTekst}' Command received and processed" StartRadio;; "stop_radio") WriteLog 2 "'${PressTekst}' Command received and processed" Stopradio;; "start_stop_radio") WriteLog 2 "'${PressTekst}' Command received and processed" StartStopRadio;; "create_mythfmmenu") CreateFMmenuFile;; "recreate_iradiomenu") CreateiRadioConfig;; "reload") # Reload the functions and config file WriteLog 3 "'${PressTekst}' Command received and processing" Stopradio RADIO_FUNCTIONS_LOADED="reload" RADIO_CONFIG_LOADED="reload" break;; "quit") # Make sure the radio is stopped # and then leave the Script after cleaning up WriteLog 3 "'${PressTekst}' Command received and processing" Stopradio RETVAL=0 break 2;; *) WriteLog 6 "Unknown '${PressTekst}' Command received" ;; esac fi done < "/tmp/$FiFo" done # Cleaning up WriteLog 1 "Stopping ircat" [ "$(pgrep -u ${RADIO_UID} ircat)" ] && pkill -u ${RADIO_UID} ircat [ -e "/tmp/${FiFo}" ] && rm "/tmp/${FiFo}" WriteLog 1 "RadioControl Closed" [ $LogStdOut -eq 1 ] && exec 3>&- [ $LogErrors -eq 1 ] && exec 4>&- exit $RETVAL
radioFunctions.sh
The functions file radioFunctions.sh
#!/bin/bash # Copyright 2014 Hika van den Hoven # Distributed under the terms of the GNU General Public License v2 # $Header: $ # Be sure only to place functions in the function file # Do not declare global variables as they get blocked on reloads! # Declare them in remoteRadio.sh and put the values in the config file Action=${1:-"0"} [ "$remoteRadio" != "yes" ] || \ ([ "$RADIO_FUNCTIONS_LOADED" != "reload" ] && \ WriteLog 1 "Loading FunctionsFile '${ScriptDir}/radioFunctions.sh'") || \ WriteLog 1 "Reloading FunctionsFile '${ScriptDir}/radioFunctions.sh'" RADIO_FUNCTIONS_LOADED="yes" [ "$RADIO_UID" == "" ] && RADIO_UID="$USER" [ "$ScriptDir" == "" ] && ScriptDir="${HOME}/.scripts" [ "$FiFo" == "" ] && FiFo="${RADIO_UID}-fiforadio" . "${ScriptDir}/radioFunctions.conf" RadioStarted=0 # Don't add a path to the commands. # On startup it will look for it in the $PATH and prepend the path MixerCommand="amixer" PlayCommand="aplay" RadioCommand="ivtv-radio" iRadioCommand="iradio" TuneCommand="v4l2-ctl" TVtuneCommand="ivtv-tune" function CheckFiles { RadioLog 32 "CheckFiles called" local -i CheckOK=0 [ -c "${VideoDevice}" ] || \ (RadioLog 1 "Characterdevice ${VideoDevice} does not exist" && \ CheckOK=$CheckOK+1) [ -c "${RadioDevice}" ] || \ (RadioLog 1 "Characterdevice ${RadioDevice} does not exist" && \ CheckOK=$CheckOK+1) [ -c "${RadioOut}" ] || \ (RadioLog 1 "Characterdevice ${RadioOut} does not exist" && \ CheckOK=$CheckOK+1) [ -d "${RadioDir}" ] || mkdir --parents "${RadioDir}" || \ (RadioLog 1 "${RadioDir} does not exist" && \ CheckOK=$CheckOK+1) [ -f "${MainRadioFreqFile}" ] || (RadioLog 1 "The Channel definition ${MainRadioFreqFile} does not exist" && \ CheckOK=$CheckOK+1) FindCommand "MixerCommand" "alsa-utils" || CheckOK=$CheckOK+1 FindCommand "PlayCommand" "alsa-utils" || CheckOK=$CheckOK+1 FindCommand "RadioCommand" "ivtv-utils" || CheckOK=$CheckOK+1 FindCommand "TuneCommand" "v4l-utils" || CheckOK=$CheckOK+1 FindCommand "TVtuneCommand" "v4l-utils" || CheckOK=$CheckOK+1 [ $UseIRadio -eq 0 ] || \ FindCommand "iRadioCommand" "ivtvplayer" || \ CheckOK=$CheckOK+1 [ $UseIRadio -eq 0 ] || [ -f "${IVTVRadioFreqFile}" ] || \ CreateiRadioConfig || \ (RadioLog 1 "${IVTVRadioFreqFile} can not be created" && \ CheckOK=$CheckOK+1) return $CheckOK } function FindCommand { eval local varName=$1 local Package="$2" RadioLog 32 "FindCommand called" eval local progName="\${$varName}" varValue=`which ${progName}` [ "$varValue" != "" ] || \ (RadioLog 1 "${progName} is not found." && \ RadioLog 1 "Install ${Package}!" && return 1) [ -x "${varValue}" ] || \ (RadioLog 1 "${varValue} is not executable." && \ RadioLog 1 "Check the permissions!" && return 1) eval ${varName}=$varValue } function get_stringPart { local TestString="$1" local -i Index=${2:-1} local Separator=${3:-" "} Separator="${Separator:0:1}" # Terminate with the separator to ensure an empty string at the end TestString="$TestString$Separator" if [ "$Separator" == " " ]; then echo "`echo "$TestString" | cut -d' ' -f$Index`" else echo "`echo "$TestString" | cut -d"$Separator" -f$Index`" fi } function strip_Spaces { local MainString="$1" local -i SpacePart=${2:-0} if [ $SpacePart -gt 2 -o $SpacePart -lt 0 ]; then SpacePart=0 fi local -i StringLength=${#MainString} local -i i if [ $SpacePart -eq 0 -o $SpacePart -eq 1 ]; then for i in `seq 1 $StringLength`; do if [ "${MainString:$((i-1)):1}" != " " ]; then MainString="${MainString:$((i-1))}" StringLength=${#MainString} break fi done fi if [ $SpacePart -eq 0 -o $SpacePart -eq 2 ]; then for i in `seq $StringLength -1 1`; do if [ "${MainString:$((i-1)):1}" != " " ]; then MainString="${MainString:0:$i}" StringLength=${#MainString} break fi done fi echo "$MainString" } function RadioLog { local -i ErrorLevel=${1:-32} local LogText="$2" if [ "$remoteRadio" == "yes" ]; then WriteLog $ErrorLevel "${LogText}" else echo "${LogText}" fi } # Database Functions function GetDBContactString { local tmpLine local -i Read=0 local -i Len local DBHost local DBUName local DBPword local DataBase while read tmpLine; do tmpLine=`strip_Spaces "$tmpLine"` if [ $Read -eq 1 ]; then Len=${#tmpLine} if [ "${tmpLine:0:6}" = "<Host>" ]; then Len=$Len-13 DBHost=${tmpLine:6:$Len} elif [ "${tmpLine:0:10}" = "<UserName>" ]; then Len=$Len-21 DBUName=${tmpLine:10:$Len} elif [ "${tmpLine:0:10}" = "<Password>" ]; then Len=$Len-21 DBPword=${tmpLine:10:$Len} elif [ "${tmpLine:0:14}" = "<DatabaseName>" ]; then Len=$Len-29 DataBase=${tmpLine:14:$Len} fi elif [ "$tmpLine" == "<Database>" ]; then Read=1 elif [ "$tmpLine" == "</Database>" ]; then Read=0 fi done < ${Myth_ConfigFile} DBContactString="-u${DBUName} -h${DBHost} -p${DBPword} ${DataBase} " } # Place the table to query in Qtabel # The number of fields in QAnswers and the Fields in the QANames array # The number of where clauses in QFields # with the fields and values in the QFNames and QFValues arrays # Set the corresponding QFTypes value to '1' to quote the value else to '0' # You can set sort fields by setting QOrder to the number of fields # and the QONames and QODirection arrays to the fields and the direction # 0 = ASc and 1 in DESC # The return value ($?) is the number of records with the QAValues array # containing the first record (if any) # Retrieve further records into the array with GetRecord <recordnr> function QueryDB { local -i i local tmpFile="$(mktemp)" local Record local -i RecLen local SQL="SELECT " for i in `seq 1 $QAnswers`; do SQL="${SQL}${QANames[$i]}" if [ $i -eq $QAnswers ]; then SQL="${SQL} " else SQL="${SQL}, " fi done SQL="${SQL}FROM ${Qtabel} " if [ $QFields -gt 0 ]; then SQL="${SQL}WHERE " for i in `seq 1 $QFields`; do case ${QFTypes[$i]} in 1) SQL="${SQL}${QFNames[$i]} = '${QFValues[$i]}'";; *) SQL="${SQL}${QFNames[$i]} = ${QFValues[$i]}";; esac if [ $i -eq $QFields ]; then SQL="${SQL}" else SQL="${SQL} AND " fi done fi if [ $QOrder -gt 0 ]; then SQL="${SQL} ORDER BY " for i in `seq 1 $QOrder`; do SQL="${SQL}${QONames[$i]}" case ${QODirection[$i]} in 1) SQL="${SQL} DESC";; *) SQL="${SQL} ASC";; esac if [ $i -eq $QOrder ]; then SQL="${SQL} " else SQL="${SQL}, " fi done fi echo "$SQL;" >> ${WorkDir}/SQL [ "$DBContactString" != "" ] || GetDBContactString mysql $DBContactString -N -t -e "$SQL;" > "$tmpFile" i=0 while read Record; do if [ "${Record:0:2}" != "+-" ]; then i=i+1 RecLen=${#Record}-2 QRecords[$i]=${Record:1:$RecLen} fi done < "$tmpFile" QRecCount=$i [ -f "$tmpFile" ] && rm -f "$tmpFile" GetRecord 1 return $QRecCount } function GetRecord { local -i RecID=${1:-1} local -i i if [ $QRecCount -eq 0 ]; then for i in `seq 1 $QAnswers`; do QAValues[$i]="" done return 1 fi if [ $RecID -gt $QRecCount ]; then RecID=$QRecCount elif [ $RecID -lt 1 ]; then RecID=1 fi for i in `seq 1 $QAnswers`; do QAValues[$i]=`echo ${QRecords[$RecID]} | cut -d'|' -f$i` QAValues[$i]="`strip_Spaces "${QAValues[$i]}"`" done } # amixer Commands function GetMute { RadioLog 32 "GetMute called" local -i CardNr=${1:-$AudioCardNr} local MuteVal=`${MixerCommand} --card $CardNr sget ${MasterMixerCtrl} | grep "Mono:" | cut -d ' ' -f8` [ "$MuteVal" == "[off]" -o "$MuteVal" == "0" ] && return 0 [ "$MuteVal" == "[on]" -o "$MuteVal" == "1" ] && return 1 return -1 } function SetMute { RadioLog 32 "SetMute called" local -i Mute=${1:-"0"} local -i CardNr=${2:-$AudioCardNr} if [ $Mute -eq 1 ]; then ${MixerCommand} --quiet --card $CardNr sset "${MasterMixerCtrl}" on RadioLog 16 "MasterVolume on Card $CardNr unMuted" else ${MixerCommand} --quiet --card $CardNr sset "${MasterMixerCtrl}" off RadioLog 16 "MasterVolume on Card $CardNr Muted" fi } function GetVolume { RadioLog 32 "GetVolume called" local vControl=${1:-$DefaultMixerCtrl} local -i FeedBack=${2:-0} local Volume=`${MixerCommand} --card $AudioCardNr sget "${vControl}" | grep "Mono:" | cut -d ' ' -f5` if [ "$Volume" == "" ]; then local -i lVolume=`${MixerCommand} --card $AudioCardNr sget "${vControl}" | grep "Front Left:" | cut -d ' ' -f6` local -i rVolume=`${MixerCommand} --card $AudioCardNr sget "${vControl}" | grep "Front Right:" | cut -d ' ' -f6` if [ $lVolume -gt $rVolume ]; then echo $lVolume return 1 else echo $rVolume return 2 fi else echo $Volume return 0 fi } function SetVolume { RadioLog 32 "SetVolume called" local vControl=${1:-$DefaultMixerCtrl} local -i Volume=$2 ${MixerCommand} --quiet --card $AudioCardNr sset "${vControl}" $Volume echo $Volume > ${RadioDir}/${vControl// /_}.volume RadioLog 16 "Volume for '${vControl}'on Card $AudioCardNr set to $Volume" } function SetSource { RadioLog 32 "SetSource called" local vControl=${1:-$SourceSelectCtrl} [ "${vControl}" != "" ] || return local Source="$2" ${MixerCommand} --quiet --card $AudioCardNr sset "${vControl}" $Source RadioLog 16 "Source for '${vControl}'on Card $AudioCardNr set to $Source" } function SaveVolume { # If the Mixercontrol variable is set then save the present volume # to disk and if SaveVar is given set it to the value in that variable RadioLog 32 "SaveVolume called" local vControl=${1:-$DefaultMixerCtrl} eval local SaveVar=$2 [ "${vControl}" != "" ] || return GetVolume "${vControl}" > "${RadioDir}/${vControl// /_}.volume" [ "$SaveVar" == "" ] || \ (eval local -i Volume=\${$varName} && \ SetVolume "${vControl}" $Volume) } function SetSavedVolume { # If the Mixercontrol variable is set and a saved value is found on disk # set the volume. Else set it to Max # If SaveVar is given set it to the old volume RadioLog 32 "SetSavedVolume called" local vControl=${1:-$DefaultMixerCtrl} eval local SaveVar=$2 [ "${vControl}" != "" ] || return local -i Volume=$MaxVolume [ "$SaveVar" == "" ] || \ eval ${SaveVar}=`GetVolume "${vControl}"` [ -f "${RadioDir}/${vControl// /_}.volume" ] && \ Volume=`cat "${RadioDir}/${vControl// /_}.volume"` SetVolume "${vControl}" $Volume } function ToggleRadioMute { RadioLog 32 "ToggleRadioMute called" GetMute if [ $? -eq 1 ]; then SetMute 0 else SetMute 1 fi } function RadioVolumeUp { RadioLog 32 "RadioVolumeUp called" local -i Volume=`GetVolume "$DefaultMixerCtrl"` Volume=$Volume+10 [ $Volume -gt $MaxVolume ] && Volume=$MaxVolume SetVolume "$DefaultMixerCtrl" $Volume } function RadioVolumeDown { RadioLog 32 "RadioVolumeDown called" local -i Volume=`GetVolume "$DefaultMixerCtrl"` Volume=$Volume-10 [ $Volume -lt 0 ] && Volume=0 SetVolume "$DefaultMixerCtrl" $Volume } # Radio Commands function GetRadioPID { RadioLog 32 "GetRadioPID called" RadioPID=`pgrep -u ${RADIO_UID} ivtv-radio` [ $RadioPID -eq 0 ] && return 0 return 1 } function GetiRadioPID { RadioLog 32 "GetiRadioPID called" iRadioPID=`pgrep -u ${RADIO_UID} iradio` [ $iRadioPID -eq 0 ] && return 0 return 1 } function GetaPlayPID { RadioLog 32 "GetaPlayPID called" aPlayPID=`pgrep -u ${RADIO_UID} aplay` [ $aPlayPID -eq 0 ] && return 0 return 1 } function KillRadio { RadioLog 32 "KillRadio called" GetiRadioPID [ $? -eq 1 ] && pkill iradio GetaPlayPID [ $? -eq 1 ] && pkill aplay GetRadioPID [ $? -eq 1 ] && pkill ivtv-radio RadioStarted=0 } function KilliRadio { RadioLog 32 "KilliRadio called" GetiRadioPID [ $? -eq 1 ] && pkill iradio } function StartRadio { RadioLog 32 "StartRadio called" local -i ChannelNr=1 [ $RadioStarted -eq 1 ] && RadioLog 1 "Radio already Started" && return getTVstatus [ $? -eq -2 ] && RadioLog 1 "Error retrieving TV status" [ $? -eq -1 ] && RadioLog 1 "TV card not found" [ $? -gt 0 ] && RadioLog 1 "TV card busy" && return [ $MainCardNr -ne $AudioCardNr ] && SetMute 0 $MainCardNr SetSavedVolume "${MasterMixerCtrl}" "SavedMasterVolume" SetSavedVolume "${DefaultMixerCtrl}" "SavedDefaultVolume" [ -f ${RadioDir}/LastChannel ] && \ ChannelNr=`cat ${RadioDir}/LastChannel` ${RadioCommand} -d ${RadioDevice} -j -f ${ChannelFrequency[$ChannelNr]} & case $RadioCardType in 2) [ "${SourceVolumeCtrl}" == "" ] || \ SetSavedVolume "${SourceVolumeCtrl}" [ "${CaptureVolumeCtrl}" == "" ] || \ SetSavedVolume "${CaptureVolumeCtrl}" [ "${SourceSelectCtrl}" == "" ] || \ SetSource "${SourceSelectCtrl}" "${SourceSelect}" ;; 3) ${PlayCommand} --device="${aPlayPCM}" --format=dat < $RadioOut & ;; *) ${PlayCommand} --device="${aPlayPCM}" --format=dat < $RadioOut & ;; esac ResetChannel SetMute 1 RadioStarted=1 RadioLog 1 "Radio Started" } function Stopradio { RadioLog 32 "Stopradio called" SetMute 0 if [ $RadioStarted -eq 1 ]; then SaveVolume "${MasterMixerCtrl}" "SavedMasterVolume" SaveVolume "${DefaultMixerCtrl}" "SavedDefaultVolume" if [ $RadioCardType -eq 2 ]; then SaveVolume "${SourceVolumeCtrl}" SaveVolume "${CaptureVolumeCtrl}" fi fi KillRadio SetMute 1 $MainCardNr RadioLog 1 "Radio Stopped" } function StartStopRadio { RadioLog 32 "StartStopRadio called" if [ $RadioStarted -eq 1 ]; then Stopradio else StartRadio fi } function getTVstatus { ${ScriptDir}/querytuner.py --card ${VideoDevice} return $? } # Channel Commands function ReadChannels { RadioLog 32 "ReadChannels called" local tmpVal local -i i=0 [ -f "${MainRadioFreqFile}" ] || return 1 while read tmpVal; do if [ "$tmpVal" != "" ]; then i=$i+1 ChannelName[$i]=`get_stringPart "$tmpVal" 1 ";"` ChannelFrequency[$i]=`get_stringPart "$tmpVal" 2 ";"` fi done < "${MainRadioFreqFile}" ChannelCount=$i RadioLog 1 "ChannelInfo Read" } function CreateFMmenuFile { RadioLog 32 "CreateFMmenuFile called" local -i i [ "$ChannelCount" != "" ] || ReadChannels || return 1 [ $ChannelCount -gt 0 ] || ReadChannels || return 1 [ -f "${ScriptDir}/${MythMenuFile}.bak" ] && rm "${ScriptDir}/${MythMenuFile}.bak" [ -f "${ScriptDir}/${MythMenuFile}" ] && mv "${ScriptDir}/${MythMenuFile}" "${ScriptDir}/${MythMenuFile}.bak" echo "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" > ${ScriptDir}/${MythMenuFile} echo "<mythmenu name=\"FMMENU\">" >> ${ScriptDir}/${MythMenuFile} echo "" >> ${ScriptDir}/${MythMenuFile} for i in `seq 1 $ChannelCount`; do echo " <button>" >> ${ScriptDir}/${MythMenuFile} echo " <type>MUSIC</type>" >> ${ScriptDir}/${MythMenuFile} echo " <text>${ChannelName[$i]}</text>" >> ${ScriptDir}/${MythMenuFile} echo " <action>EXEC echo \"${i}\" > \"/tmp/${FiFo}\"</action>" >> ${ScriptDir}/${MythMenuFile} echo " </button>" >> ${ScriptDir}/${MythMenuFile} echo "" >> ${ScriptDir}/${MythMenuFile} done echo " <button>" >> ${ScriptDir}/${MythMenuFile} echo " <type>MUSIC</type>" >> ${ScriptDir}/${MythMenuFile} echo " <text>Start/Stop de Radio</text>" >> ${ScriptDir}/${MythMenuFile} echo " <action>EXEC echo \"start_stop_radio\" > \"/tmp/${FiFo}\"</action>" >> ${ScriptDir}/${MythMenuFile} echo " </button>" >> ${ScriptDir}/${MythMenuFile} echo "" >> ${ScriptDir}/${MythMenuFile} echo "</mythmenu>" >> ${ScriptDir}/${MythMenuFile} echo "" >> ${ScriptDir}/${MythMenuFile} #sudo cp ${ScriptDir}/${MythMenuFile} ${MythMenuDir}/${MythMenuFile} #sudo chmod 644 ${MythMenuDir}/${MythMenuFile} } function CreateiRadioBaseConfig { RadioLog 32 "CreateiRadioBaseConfig called" [ "$ChannelCount" != "" ] || ReadChannels || return 1 [ $ChannelCount -gt 0 ] || ReadChannels || return 1 [ -f "${IVTVRadioFreqFile}.base.bak" ] && rm "${IVTVRadioFreqFile}.base.bak" [ -f "${IVTVRadioFreqFile}.base" ] && mv "${IVTVRadioFreqFile}.base" "${IVTVRadioFreqFile}.base.bak" echo "<?xml version="1.0" encoding="utf-8"?>" > ${IVTVRadioFreqFile}.base echo "" >> ${IVTVRadioFreqFile}.base echo "<!--" >> ${IVTVRadioFreqFile}.base echo " **********************************************************" >> ${IVTVRadioFreqFile}.base echo " ** Description: Configuration file for iradio" >> ${IVTVRadioFreqFile}.base echo " **" >> ${IVTVRadioFreqFile}.base echo " ** (c) Jiri Tyr 2008" >> ${IVTVRadioFreqFile}.base echo " **********************************************************" >> ${IVTVRadioFreqFile}.base echo " Look in the example coming with the package for explanation" >> ${IVTVRadioFreqFile}.base echo " -->" >> ${IVTVRadioFreqFile}.base echo "" >> ${IVTVRadioFreqFile}.base echo "<iradio>" >> ${IVTVRadioFreqFile}.base echo " <setting>" >> ${IVTVRadioFreqFile}.base echo " <device>${RadioOut}</device>" >> ${IVTVRadioFreqFile}.base echo " <default-channel>${ChannelName[1]}</default-channel>" >> ${IVTVRadioFreqFile}.base echo " <lirc>0</lirc>" >> ${IVTVRadioFreqFile}.base echo " <volume>65535</volume>" >> ${IVTVRadioFreqFile}.base echo " <xosd>1</xosd>" >> ${IVTVRadioFreqFile}.base echo " <xosd-font>-*-fixed-*-r-*-*-20-*-*-*-*-*-*-*</xosd-font>" >> ${IVTVRadioFreqFile}.base echo " <xosd-color>Red</xosd-color>" >> ${IVTVRadioFreqFile}.base echo " <xosd-timeout>-1</xosd-timeout>" >> ${IVTVRadioFreqFile}.base echo " <xosd-position>2</xosd-position>" >> ${IVTVRadioFreqFile}.base echo " <xosd-align>0</xosd-align>" >> ${IVTVRadioFreqFile}.base echo " <xosd-horizontal-offset>170</xosd-horizontal-offset>" >> ${IVTVRadioFreqFile}.base echo " <xosd-vertical-offset>260</xosd-vertical-offset>" >> ${IVTVRadioFreqFile}.base echo " <xosd-shadow-color>DimGray</xosd-shadow-color>" >> ${IVTVRadioFreqFile}.base echo " <xosd-shadow-offset>2</xosd-shadow-offset>" >> ${IVTVRadioFreqFile}.base echo " </setting>" >> ${IVTVRadioFreqFile}.base echo " <channel-list>" >> ${IVTVRadioFreqFile}.base echo "" >> ${IVTVRadioFreqFile}.base } function CreateiRadioConfig { RadioLog 32 "CreateiRadioConfig called" local -i i [ $UseIRadio -eq 1 ] || return 0 [ "$ChannelCount" != "" ] || ReadChannels || return 1 [ $ChannelCount -gt 0 ] || ReadChannels || return 1 [ -f "${IVTVRadioFreqFile}.base" ] || CreateiRadioBaseConfig || return 1 [ -f "${IVTVRadioFreqFile}.bak" ] && rm "${IVTVRadioFreqFile}.bak" [ -f "${IVTVRadioFreqFile}" ] && mv "${IVTVRadioFreqFile}" "${IVTVRadioFreqFile}.bak" cat "${IVTVRadioFreqFile}.base" > ${IVTVRadioFreqFile} for i in `seq 1 $ChannelCount`; do echo " <channel>" >> ${IVTVRadioFreqFile} echo " <name>${ChannelName[$i]}</name>>" >> ${IVTVRadioFreqFile} echo " <freq>${ChannelFrequency[$i]}</freq>>" >> ${IVTVRadioFreqFile} echo " </channel>" >> ${IVTVRadioFreqFile} done echo " </channel-list>" >> ${IVTVRadioFreqFile} echo "</iradio>" >> ${IVTVRadioFreqFile} echo "" >> ${IVTVRadioFreqFile} } function SelectChannelNumber { RadioLog 32 "SelectChannelNumber called" local -i ChannelNr=${1:-1} local Frequency if [ $ChannelNr -gt 0 -a $ChannelNr -le $ChannelCount ]; then [ $RadioStarted -eq 1 ] || StartRadio SetChannel $ChannelNr elif [ $ChannelNr -lt 800 ]; then [ $RadioStarted -eq 0 ] || StopRadio elif [ $ChannelNr -gt 1100 ]; then Frequency=$(($ChannelNr / 1000)) TuneTV $Frequency else GetChannel $ChannelNr ChannelNr=$? if [ $ChannelNr -gt 0 -a $ChannelNr -le $ChannelCount ]; then [ $RadioStarted -eq 1 ] || StartRadio SetChannel $ChannelNr fi fi } function TuneTV { local Frequency=$1 RadioLog 32 "TuneTV called" getTVstatus [ $? -eq -2 ] && RadioLog 1 "Error retrieving TV status" && return [ $? -eq -1 ] && RadioLog 1 "TV card not found" && return StopRadio ${TVtuneCommand} --device=$VideoDevice --frequency=$Frequency \ && sleep 1 || \ ${TVtuneCommand} --device=$VideoDevice --frequency=$Frequency RadioLog 8 "Changing video frequency to $Frequency" } function GetFrequency { RadioLog 32 "GetFrequency called" local Frequency=`${TuneCommand} --device=$RadioDevice --get-freq | cut -d "(" -f2` Frequency=${Frequency:0:6} echo $Frequency } function SearchChannel { RadioLog 32 "GetChannel called" local Frequency=${1:-""} local -i i local -i Len for i in `seq 1 $ChannelCount`; do Len=${#ChannelFrequency[$i]} if [ "${ChannelFrequency[$i]}" == "${Frequency:0:$Len}" ]; then return $i fi done return 0 } function GetChannel { RadioLog 32 "GetChannel called" local Frequency=${1:-""} local -i Int local -i Frac local -i RETVAL=0 if [ "$Frequency" == "" ]; then Frequency=`GetFrequency` SearchChannel "$Frequency" RETVAL=$? [ $RETVAL -eq 0 ] || return $RETVAL else SearchChannel "$Frequency" RETVAL=$? [ $RETVAL -eq 0 ] || return $RETVAL Frequency=`echo "$Frequency" | sed s/[^0-9]//g` Int=$(($Frequency / 10)) Frac=$(($Frequency - 10 * $Int)) Frequency=`printf "%d.%d" $Int $Frac` SearchChannel "$Frequency" RETVAL=$? return $RETVAL fi return 0 } function ResetChannel { RadioLog 32 "ResetChannel called" local -i ChannelNr=1 [ -f ${RadioDir}/LastChannel ] && ChannelNr=`cat ${RadioDir}/LastChannel` [ $ChannelNr -gt 0 -a $ChannelNr -le $ChannelCount ] && \ SetChannel $ChannelNr } function SetChannel { RadioLog 32 "SetChannel called" local -i ChannelNr=${1:-1} GetiRadioPID GetChannel [ $ChannelNr -eq $? -a $iRadioPID -gt 0 ] && return echo $ChannelNr > ${RadioDir}/LastChannel echo "${ChannelFrequency[$ChannelNr]}" > ${RadioDir}/LastFrequency echo "${ChannelName[$ChannelNr]}" > ${RadioDir}/LastName if [ $UseIRadio -eq 1 ]; then KilliRadio ${iRadioCommand} --channel="${ChannelName[$ChannelNr]}" > /dev/null & else ${TuneCommand} --device=$RadioDevice \ --set-freq=${ChannelFrequency[$ChannelNr]} > /dev/null fi RadioLog 8 "Channel set to ${ChannelNr}: ${ChannelName[$ChannelNr]} on ${ChannelFrequency[$ChannelNr]} MHz" } function ChannelUp { RadioLog 32 "ChannelUp called" GetChannel local -i RETVAL=$? local -i ChannelNr=$RETVAL+1 [ $ChannelNr -gt $ChannelCount ] && ChannelNr=1 SetChannel $ChannelNr } function ChannelDown { RadioLog 32 "ChannelDown called" GetChannel local -i RETVAL=$? local -i ChannelNr=$RETVAL-1 [ $ChannelNr -le 0 ] && ChannelNr=$ChannelCount SetChannel $ChannelNr } function DirectActions { local StartAction=$1 case $StartAction in "1") CreateFMmenuFile;; "2") UseIRadio=1 CreateiRadioBaseConfig;; "3") UseIRadio=1 CreateiRadioConfig;; "4") CheckFiles;; *) # Show Help text echo "This script is ment to be run through remoteRadio.sh" echo "However starting it with the following parameters" echo "you can use it to perform some maintenance actions" echo echo "1 (Re)create a Mythtv radiomenu file: ${MythMenuFile}" echo " in ${ScriptDir} based on the ${MainRadioFreqFile}" echo " saving an oldfile to ${MythMenuFile}.bak" echo echo "2 (Re)create a base iradio config file: iradio.xml.base in ${RadioDir}" echo " saving an oldfile to iradio.xml.base.bak" echo echo "3 (Re)create the iradio config: iradio.xml file in ${RadioDir}" echo " based on the ${MainRadioFreqFile} and above base file" echo " saving an oldfile to iradio.xml.bak" echo echo "4 Perform a test on needed programs, files and directories" echo;; esac } [ "$Action" == "daemon" ] || DirectActions "$Action"
radioFunctions.conf
The configfile 'radioFunctions.conf'
#!/bin/bash RADIO_CONFIG_LOADED="yes" Myth_ConfigFile="${HOME}/.mythtv/config.xml" RadioDir="${HOME}/.ivtv" MainRadioFreqFile="${RadioDir}/radioFrequencies" IVTVRadioFreqFile="${RadioDir}/iradio.xml" MythMenuDir="/usr/share/mythtv/themes/defaultmenu" MythMenuFile="fmmenu.xml" # This is often /dev/radio0 RadioDevice="/dev/v4l/IVTV0/radio" # This is for an IVTV device (PVR150/250/350/500) /dev/video24 RadioOut="/dev/v4l/IVTV0/raw-audio" # Set to 1 to use iradio as wraparound ivtv-radio for OSD display of the channel # This doesn't work if run as a service. It then can't find the X-screen UseIRadio=0 # This is often /dev/video0 VideoDevice="/dev/v4l/IVTV0/mpeg" # ivtv-radio also works with non-IVTV cards. # I can't guaranty it will work with yours. # Possible values are: # 1: IVTV device (PVR150/250/350/500) using the ivtv driver # 2: Other card with a wire connection to an audio-card # Set AudioCardNr to this audio-card. RadioOut and aplay are not used. # Instead set the Source and Capture values below. # To not set any of the controls leave the variable empty # The volumes will the first time be set to Max # 3: Other card with an Alsa device for pci passthrough (not tested) # Set RadioOut to this Alsa device and it will try streaming it # to the aPlayPCM. Possibly the format needs changing. # If this doesn't work, you have to set it to 2 and create a PCM RadioCardType=1 # PCM-device used by aplay aPlayPCM="front:CARD=CA0106" # Alsa number for the audiocard used by MythTV MainCardNr=0 # Alsa number for the audiocard used for the radio. They can be the same AudioCardNr=1 MaxVolume=255 # Mixer control used for muting. Normally always Master MasterMixerCtrl="Master" # Mixer control to set the volume DefaultMixerCtrl="Analog Front" # Settings for TV-cards wired to an audio-card SourceSelectCtrl="Analog Source" SourceSelect="Aux" SourceVolumeCtrl="Aux" CaptureVolumeCtrl="CAPTURE feedback" # 1=Log System Actions and errors # 2=Log all commands coming through the pipe, Mainly for debugging # 4=log unknown commands coming through the pipe # 8=log Channel changes # 16=log Volume changes # 32=log all radiofunction calls, Mainly for debugging LogLevel=29 LogErrors=1 LogStdOut=1 MaxLogSize=10240 MaxOldLogs=5
querytuner.py
This is a small python script to check the tv-tuner status run it with --help to see its options:
#!/usr/bin/env python2 # -*- coding: utf-8 -*- import argparse, socket, urllib2, sys from urllib2 import urlopen from xml.etree import cElementTree as ET parser = argparse.ArgumentParser(description='Get Status of Backend Encoders.') parser.add_argument('-c', '--card', type=str, required=False, metavar='<device>', default='/dev/video0', help='tv capture device, defaults to </dev/video0>') parser.add_argument('-m', '--host', type=str, required=False, metavar='<hostname>', default=socket.gethostname(), help='backend dns hostname, defaults to the local hostname') parser.add_argument('-v', '--verbose', action='store_true', required=False, help='print the result to the screen') args = parser.parse_args() URL0 = 'http://{}:6544//Myth/GetHostName'.format(args.host) try: response = ET.parse(urlopen(URL0)) root = response.getroot() except: if args.verbose: print 'GetHostName failed, is the backend running?' sys.exit(-2) URL1 = 'http://{}:6544/Capture/GetCaptureCardList?HostName={}' \ .format(args.host, root.text) try: response = ET.parse(urlopen(URL1)) except: if args.verbose: print 'GetCaptureCardList failed, is the backend running?' sys.exit(-2) for element1 in response.findall('CaptureCards/CaptureCard'): if element1.findtext('VideoDevice') == args.card: URL2 = 'http://{}:6544/Dvr/GetEncoderList'.format(args.host) try: response = ET.parse(urlopen(URL2)) except: if args.verbose: print'GetEncoderList failed, is the backend running?' sys.exit(-2) for element2 in response.findall('Encoders/Encoder'): if element2.findtext('Id') == element1.findtext('CardId'): if args.verbose: if int(element2.findtext('State')) == -1: print 'The status of %s on %s is: -1, not Connected' \ % (args.card, args.host) elif int(element2.findtext('State')) == 0: print 'The status of %s on %s is: 0, Inactive' \ % (args.card, args.host) elif int(element2.findtext('State')) == 1: print 'The status of %s on %s is: 1, watching Live TV' \ % (args.card, args.host) elif int(element2.findtext('State')) == 7: print 'The status of %s on %s is: 7, Recording' \ % (args.card, args.host) else: print 'The status of %s on %s is: %s' % \ (args.card, args.host, \ element2.findtext('State')) sys.exit(int(element2.findtext('State'))) break break if args.verbose: print 'The capture device is not found in MythTV' sys.exit(-1)
radiocontrol (gentoo runscript)
The Gentoo style runscript 'radiocontrol' to be placed in /etc/init.d
#!/sbin/runscript # Copyright 2014 Hika van den Hoven # Distributed under the terms of the GNU General Public License v2 # $Header: $ depend() { need lircd after lircd } start() { ebegin "Starting Radio Control" eindent einfo "Checking LogFiles and permissions" if [ "${LogDir}" != "" ]; then LogDir="/var/log/${LogDir}" checkpath -d -o ${RADIO_UID} -m 755 "${LogDir}" else LogDir="/var/log" fi LogFile="${LogDir}/${LogFile}" checkpath -q -f -o ${RADIO_UID} -m 644 "${LogFile}.log" checkpath -q -f -o ${RADIO_UID} -m 644 "${LogFile}.error" checkpath -q -f -o ${RADIO_UID} -m 644 "${LogFile}.stdout" [ ! -e "/tmp/${FiFo}" ] || rm "/tmp/${FiFo}" eend $? einfo "Starting Control Script" start-stop-daemon --start --quiet --background --wait 1000 \ --pidfile "/run/${FiFo}.pid" --make-pidfile \ --user ${RADIO_UID} --exec ${ScriptDir}/remoteRadio.sh \ "${RADIO_UID}" "${ScriptDir}" "${FiFo}" "${LircProgID}" "${LogFile}" & ewaitfile 1 "/tmp/${FiFo}" eend $? || return 1 eoutdent } stop() { ebegin "Stopping Radio Control" eindent if [ "$(pgrep -u ${RADIO_UID} remoteRadio.sh)" ]; then einfo "Stopping Control Script" echo "quit" > "/tmp/${FiFo}" sleep 1 [ ! "$(pgrep -u ${RADIO_UID} remoteRadio.sh)" ] || \ start-stop-daemon --stop --quiet \ --pidfile "/run/${FiFo}.pid" eend $? fi if [ "$(pgrep -u ${RADIO_UID} ircat)" ]; then einfo "Terminating ircat" start-stop-daemon --stop --quiet \ --user ${RADIO_UID} --name ircat eend $? fi [ ! -e "/tmp/${FiFo}" ] || rm "/tmp/${FiFo}" einfo "Terminating ivtv-radio if still running" if [ "$(pgrep -u ${RADIO_UID} iradio)" ]; then start-stop-daemon --stop --quiet \ --user ${RADIO_UID} --name iradio fi if [ "$(pgrep -u ${RADIO_UID} aplay)" ]; then start-stop-daemon --stop --quiet \ --user ${RADIO_UID} --name aplay fi if [ "$(pgrep -u ${RADIO_UID} ivtv-radio)" ]; then start-stop-daemon --stop --quiet \ --user ${RADIO_UID} --name ivtv-radio fi eend $? eoutdent }
The Gentoo style configfile 'radiocontrol' to be placed in /etc/conf.d
# User id that all the processes should run as. RADIO_UID="mythtv" # Location of the Scripts and configfiles ScriptDir="/home/${RADIO_UID}/.scripts" # The FIFO file for placing commands through ircat or otherwise FiFo="${RADIO_UID}-fiforadio" # Lirc ProgramName in .lircrc for ircat to listen to LircProgID="mythradio" # The directory and file in /var/log to log to # The extention .log .error .stdout are appended LogDir="mythradio" LogFile="mythradio"