Fm radio

From MythTV Official Wiki
Jump to: navigation, search

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.


Important.png 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.


Important.png Note: this is NOT a plug-in and is basically a hack but when completed it looks just like a plug-in.


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.


Important.png 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.png 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

  1. The stream will play until you choose the "Stop Listening" button on the GUI (or the mythtv_kill script is executed)
  2. 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.
  3. With MythDora 4.0 ivtv-radio is in /usr/bin. Modify scripts accordingly.
  4. 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 new default main menu: Main Menu

The FM station selection menu: FM 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
   Stand-alone you can use it among others to create the mythtv menufile "fmmenu.xml" described above, based on the radioFrequencies file in ~/.ivtv.
 - the config file: radioFunctions.conf
 - querytuner.py. Checks the TV tuner status in MythTV. Tested with 0.27.3

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 

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)
	[ -f "${ScriptDir}/querytuner.py" ] && \
		([ -x "${ScriptDir}/querytuner.py" ] || \
		chmod +x "${ScriptDir}/querytuner.py")|| 
		(RadioLog 1 "The ${ScriptDir}/querytuner.py script 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
	[ $? -gt 0 -a $? -lt 254 ] && RadioLog 1 "TV card busy" && return
	[ $? -eq 254 ] && RadioLog 1 "Error retrieving TV status"
	[ $? -eq 255 ] && RadioLog 1 "TV card not found"
	
	[ $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 254 ] && RadioLog 1 "Error retrieving TV status" && return
	[ $? -eq 255 ] && 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"