2000-02-19 13:36:48 +01:00
/*
2000-04-24 09:46:05 +02:00
* vdr . c : Video Disk Recorder main program
2000-02-19 13:36:48 +01:00
*
2006-01-08 11:49:03 +01:00
* Copyright ( C ) 2000 , 2003 , 2006 Klaus Schmidinger
2001-08-03 14:18:08 +02:00
*
2000-02-19 13:36:48 +01:00
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version 2
* of the License , or ( at your option ) any later version .
2001-08-03 14:18:08 +02:00
*
2000-02-19 13:36:48 +01:00
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
2001-08-03 14:18:08 +02:00
*
2000-02-19 13:36:48 +01:00
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
2006-04-21 14:53:26 +02:00
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
2000-02-19 13:36:48 +01:00
* Or , point your browser to http : //www.gnu.org/copyleft/gpl.html
2001-08-03 14:18:08 +02:00
*
2000-02-19 13:36:48 +01:00
* The author can be reached at kls @ cadsoft . de
*
2003-05-29 12:44:06 +02:00
* The project ' s page is at http : //www.cadsoft.de/vdr
2000-02-19 13:36:48 +01:00
*
2007-02-25 11:39:40 +01:00
* $ Id : vdr . c 1.285 2007 / 02 / 25 11 : 27 : 36 kls Exp $
2000-02-19 13:36:48 +01:00
*/
2000-07-23 15:01:31 +02:00
# include <getopt.h>
2005-12-31 13:30:11 +01:00
# include <grp.h>
2001-10-07 11:00:35 +02:00
# include <locale.h>
2005-12-31 13:30:11 +01:00
# include <pwd.h>
2000-04-15 17:38:11 +02:00
# include <signal.h>
2000-07-23 15:01:31 +02:00
# include <stdlib.h>
2005-12-31 13:30:11 +01:00
# include <sys/capability.h>
# include <sys/prctl.h>
2002-12-08 14:30:32 +01:00
# include <termios.h>
2000-07-23 15:36:43 +02:00
# include <unistd.h>
2002-11-03 11:53:58 +01:00
# include "audio.h"
2002-10-06 10:25:42 +02:00
# include "channels.h"
2000-02-19 13:36:48 +01:00
# include "config.h"
2002-06-22 10:11:59 +02:00
# include "cutter.h"
2002-06-16 12:57:31 +02:00
# include "device.h"
2002-10-06 10:25:42 +02:00
# include "diseqc.h"
2002-08-04 14:57:29 +02:00
# include "dvbdevice.h"
2002-05-20 11:18:09 +02:00
# include "eitscan.h"
2003-12-22 13:29:24 +01:00
# include "epg.h"
2000-11-11 10:39:27 +01:00
# include "i18n.h"
2000-02-19 13:36:48 +01:00
# include "interface.h"
2002-09-29 13:40:45 +02:00
# include "keys.h"
2006-06-16 09:22:20 +02:00
# include "libsi/si.h"
2002-09-29 13:40:45 +02:00
# include "lirc.h"
2000-02-19 13:36:48 +01:00
# include "menu.h"
2004-05-16 10:35:36 +02:00
# include "osdbase.h"
2002-05-09 16:26:56 +02:00
# include "plugin.h"
2002-09-29 13:40:45 +02:00
# include "rcu.h"
2000-03-11 11:22:37 +01:00
# include "recording.h"
2007-02-25 10:56:29 +01:00
# include "shutdown.h"
2004-05-16 10:35:36 +02:00
# include "skinclassic.h"
# include "skinsttng.h"
2002-10-06 10:25:42 +02:00
# include "sources.h"
2004-05-16 10:35:36 +02:00
# include "themes.h"
2002-10-20 12:28:55 +02:00
# include "timers.h"
2000-02-19 13:36:48 +01:00
# include "tools.h"
2004-01-17 17:19:34 +01:00
# include "transfer.h"
2000-07-29 15:21:42 +02:00
# include "videodir.h"
2000-02-19 13:36:48 +01:00
2004-10-17 11:50:21 +02:00
# define MINCHANNELWAIT 10 // seconds to wait between failed channel switchings
# define ACTIVITYTIMEOUT 60 // seconds before starting housekeeping
# define SHUTDOWNWAIT 300 // seconds to wait in user prompt before automatic shutdown
2007-02-25 10:56:29 +01:00
# define SHUTDOWNRETRY 360 // seconds before trying again to shut down
# define SHUTDOWNFORCEPROMPT 5 // seconds to wait in user prompt to allow forcing shutdown
# define SHUTDOWNCANCELROMPT 5 // seconds to wait in user prompt to allow canceling shutdown
# define RESTARTCANCELPROMPT 5 // seconds to wait in user prompt before restarting on SIGHUP
2004-10-17 11:50:21 +02:00
# define MANUALSTART 600 // seconds the next timer must be in the future to assume manual start
# define CHANNELSAVEDELTA 600 // seconds before saving channels.conf after automatic modifications
2005-08-21 08:56:49 +02:00
# define DEVICEREADYTIMEOUT 30 // seconds to wait until all devices are ready
2005-09-03 11:51:54 +02:00
# define MENUTIMEOUT 120 // seconds of user inactivity after which an OSD display is closed
2006-06-04 09:10:59 +02:00
# define TIMERCHECKDELTA 10 // seconds between checks for timers that need to see their channel
# define TIMERDEVICETIMEOUT 8 // seconds before a device used for timer check may be reused
# define TIMERLOOKAHEADTIME 60 // seconds before a non-VPS timer starts and the channel is switched if possible
2006-05-07 09:13:36 +02:00
# define VPSLOOKAHEADTIME 24 // hours within which VPS timers will make sure their events are up to date
# define VPSUPTODATETIME 3600 // seconds before the event or schedule of a VPS timer needs to be refreshed
2001-02-11 14:53:44 +01:00
2007-02-25 10:56:29 +01:00
# define EXIT(v) { ShutdownHandler.Exit(v); goto Exit; }
2004-10-23 15:17:03 +02:00
2007-02-25 10:56:29 +01:00
static int LastSignal = 0 ;
2000-04-15 17:38:11 +02:00
2005-12-31 13:30:11 +01:00
static bool SetUser ( const char * UserName )
{
if ( UserName ) {
struct passwd * user = getpwnam ( UserName ) ;
if ( ! user ) {
fprintf ( stderr , " vdr: unknown user: '%s' \n " , UserName ) ;
return false ;
}
if ( setgid ( user - > pw_gid ) < 0 ) {
fprintf ( stderr , " vdr: cannot set group id %u: %s \n " , ( unsigned int ) user - > pw_gid , strerror ( errno ) ) ;
return false ;
}
if ( initgroups ( user - > pw_name , user - > pw_gid ) < 0 ) {
fprintf ( stderr , " vdr: cannot set supplemental group ids for user %s: %s \n " , user - > pw_name , strerror ( errno ) ) ;
return false ;
}
if ( setuid ( user - > pw_uid ) < 0 ) {
fprintf ( stderr , " vdr: cannot set user id %u: %s \n " , ( unsigned int ) user - > pw_uid , strerror ( errno ) ) ;
return false ;
}
2006-02-05 12:58:59 +01:00
if ( prctl ( PR_SET_DUMPABLE , 2 , 0 , 0 , 0 ) < 0 ) {
fprintf ( stderr , " vdr: warning - cannot set dumpable: %s \n " , strerror ( errno ) ) ;
// always non-fatal, and will not work with kernel < 2.6.13
}
2005-12-31 13:30:11 +01:00
}
return true ;
}
static bool SetCapSysTime ( void )
{
// drop all capabilities except cap_sys_time
cap_t caps = cap_from_text ( " = cap_sys_time=ep " ) ;
if ( ! caps ) {
fprintf ( stderr , " vdr: cap_from_text failed: %s \n " , strerror ( errno ) ) ;
return false ;
}
if ( cap_set_proc ( caps ) = = - 1 ) {
fprintf ( stderr , " vdr: cap_set_proc failed: %s \n " , strerror ( errno ) ) ;
cap_free ( caps ) ;
return false ;
}
cap_free ( caps ) ;
return true ;
}
static bool SetKeepCaps ( bool On )
{
// set keeping capabilities during setuid() on/off
if ( prctl ( PR_SET_KEEPCAPS , On ? 1 : 0 , 0 , 0 , 0 ) ! = 0 ) {
fprintf ( stderr , " vdr: prctl failed \n " ) ;
return false ;
}
return true ;
}
2000-09-15 13:58:36 +02:00
static void SignalHandler ( int signum )
2000-04-15 17:38:11 +02:00
{
2007-02-25 10:56:29 +01:00
isyslog ( " caught signal %d " , signum ) ;
switch ( signum ) {
case SIGPIPE :
break ;
case SIGHUP :
LastSignal = signum ;
break ;
default :
LastSignal = signum ;
Interface - > Interrupt ( ) ;
ShutdownHandler . Exit ( 0 ) ;
}
2000-09-15 13:58:36 +02:00
signal ( signum , SignalHandler ) ;
2000-04-15 17:38:11 +02:00
}
2001-02-24 16:18:43 +01:00
static void Watchdog ( int signum )
{
// Something terrible must have happened that prevented the 'alarm()' from
// being called in time, so let's get out of here:
2002-05-13 16:35:49 +02:00
esyslog ( " PANIC: watchdog timer expired - exiting! " ) ;
2001-02-24 16:18:43 +01:00
exit ( 1 ) ;
}
2000-02-19 13:36:48 +01:00
int main ( int argc , char * argv [ ] )
{
2002-12-08 14:30:32 +01:00
// Save terminal settings:
struct termios savedTm ;
2003-02-15 15:46:19 +01:00
bool HasStdin = ( tcgetpgrp ( STDIN_FILENO ) = = getpid ( ) | | getppid ( ) ! = ( pid_t ) 1 ) & & tcgetattr ( STDIN_FILENO , & savedTm ) = = 0 ;
2002-12-08 14:30:32 +01:00
2001-10-07 11:00:35 +02:00
// Initiate locale:
setlocale ( LC_ALL , " " ) ;
2000-07-23 15:01:31 +02:00
// Command line options:
# define DEFAULTSVDRPPORT 2001
2001-02-24 16:18:43 +01:00
# define DEFAULTWATCHDOG 0 // seconds
2003-08-02 14:32:53 +02:00
# define DEFAULTPLUGINDIR PLUGINDIR
2003-12-22 13:29:24 +01:00
# define DEFAULTEPGDATAFILENAME "epg.data"
2000-07-23 15:01:31 +02:00
2005-12-31 13:30:11 +01:00
bool StartedAsRoot = false ;
2006-01-13 16:16:32 +01:00
const char * VdrUser = NULL ;
2000-07-23 15:01:31 +02:00
int SVDRPport = DEFAULTSVDRPPORT ;
2002-11-03 11:53:58 +01:00
const char * AudioCommand = NULL ;
2000-09-15 15:09:15 +02:00
const char * ConfigDirectory = NULL ;
2003-12-22 13:29:24 +01:00
const char * EpgDataFileName = DEFAULTEPGDATAFILENAME ;
2002-05-09 16:26:56 +02:00
bool DisplayHelp = false ;
bool DisplayVersion = false ;
2000-07-23 15:36:43 +02:00
bool DaemonMode = false ;
2002-11-24 15:56:24 +01:00
int SysLogTarget = LOG_USER ;
2002-03-08 16:37:42 +01:00
bool MuteAudio = false ;
2001-02-24 16:18:43 +01:00
int WatchdogTimeout = DEFAULTWATCHDOG ;
2001-09-01 09:04:37 +02:00
const char * Terminal = NULL ;
2005-07-31 11:38:40 +02:00
bool UseKbd = true ;
const char * LircDevice = NULL ;
const char * RcuDevice = NULL ;
# if !defined(REMOTE_KBD)
UseKbd = false ;
# endif
# if defined(REMOTE_LIRC)
LircDevice = LIRC_DEVICE ;
# elif defined(REMOTE_RCU)
RcuDevice = RCU_DEVICE ;
# endif
2005-09-03 13:35:55 +02:00
# if defined(VFAT)
VfatFileSystem = true ;
# endif
2006-01-13 16:16:32 +01:00
# if defined(VDR_USER)
VdrUser = VDR_USER ;
# endif
2005-07-31 11:38:40 +02:00
2002-05-09 16:26:56 +02:00
cPluginManager PluginManager ( DEFAULTPLUGINDIR ) ;
2000-07-23 15:01:31 +02:00
static struct option long_options [ ] = {
2001-06-24 17:42:19 +02:00
{ " audio " , required_argument , NULL , ' a ' } ,
2001-02-24 16:18:43 +01:00
{ " config " , required_argument , NULL , ' c ' } ,
{ " daemon " , no_argument , NULL , ' d ' } ,
{ " device " , required_argument , NULL , ' D ' } ,
2001-08-11 09:38:12 +02:00
{ " epgfile " , required_argument , NULL , ' E ' } ,
2005-12-30 15:11:16 +01:00
{ " grab " , required_argument , NULL , ' g ' } ,
2001-02-24 16:18:43 +01:00
{ " help " , no_argument , NULL , ' h ' } ,
2002-05-09 16:26:56 +02:00
{ " lib " , required_argument , NULL , ' L ' } ,
2005-07-31 11:38:40 +02:00
{ " lirc " , optional_argument , NULL , ' l ' | 0x100 } ,
2001-02-24 16:18:43 +01:00
{ " log " , required_argument , NULL , ' l ' } ,
2002-03-08 16:37:42 +01:00
{ " mute " , no_argument , NULL , ' m ' } ,
2005-07-31 11:38:40 +02:00
{ " no-kbd " , no_argument , NULL , ' n ' | 0x100 } ,
2002-05-09 16:26:56 +02:00
{ " plugin " , required_argument , NULL , ' P ' } ,
2001-02-24 16:18:43 +01:00
{ " port " , required_argument , NULL , ' p ' } ,
2005-07-31 11:38:40 +02:00
{ " rcu " , optional_argument , NULL , ' r ' | 0x100 } ,
2001-09-22 14:23:55 +02:00
{ " record " , required_argument , NULL , ' r ' } ,
2001-09-01 09:04:37 +02:00
{ " shutdown " , required_argument , NULL , ' s ' } ,
{ " terminal " , required_argument , NULL , ' t ' } ,
2005-12-31 13:30:11 +01:00
{ " user " , required_argument , NULL , ' u ' } ,
2002-03-29 10:10:04 +01:00
{ " version " , no_argument , NULL , ' V ' } ,
2005-09-03 13:35:55 +02:00
{ " vfat " , no_argument , NULL , ' v ' | 0x100 } ,
2001-02-24 16:18:43 +01:00
{ " video " , required_argument , NULL , ' v ' } ,
{ " watchdog " , required_argument , NULL , ' w ' } ,
2001-08-11 09:38:12 +02:00
{ NULL }
2000-07-23 15:01:31 +02:00
} ;
2001-08-03 14:18:08 +02:00
2000-07-23 15:01:31 +02:00
int c ;
2005-12-31 13:30:11 +01:00
while ( ( c = getopt_long ( argc , argv , " a:c:dD:E:g:hl:L:mp:P:r:s:t:u:v:Vw: " , long_options , NULL ) ) ! = - 1 ) {
2000-07-23 15:01:31 +02:00
switch ( c ) {
2002-11-03 11:53:58 +01:00
case ' a ' : AudioCommand = optarg ;
2001-06-24 17:42:19 +02:00
break ;
2000-09-15 15:09:15 +02:00
case ' c ' : ConfigDirectory = optarg ;
break ;
2000-07-23 15:36:43 +02:00
case ' d ' : DaemonMode = true ; break ;
2001-02-02 15:49:46 +01:00
case ' D ' : if ( isnumber ( optarg ) ) {
int n = atoi ( optarg ) ;
2002-06-16 12:57:31 +02:00
if ( 0 < = n & & n < MAXDEVICES ) {
cDevice : : SetUseDevice ( n ) ;
2001-02-02 15:49:46 +01:00
break ;
}
}
fprintf ( stderr , " vdr: invalid DVB device number: %s \n " , optarg ) ;
2001-04-01 11:18:28 +02:00
return 2 ;
2001-02-02 15:49:46 +01:00
break ;
2003-12-22 13:29:24 +01:00
case ' E ' : EpgDataFileName = ( * optarg ! = ' - ' ? optarg : NULL ) ;
2001-08-11 09:38:12 +02:00
break ;
2005-12-30 15:11:16 +01:00
case ' g ' : cSVDRP : : SetGrabImageDir ( * optarg ! = ' - ' ? optarg : NULL ) ;
break ;
2002-05-09 16:26:56 +02:00
case ' h ' : DisplayHelp = true ;
2000-07-23 15:01:31 +02:00
break ;
2002-11-24 15:56:24 +01:00
case ' l ' : {
char * p = strchr ( optarg , ' . ' ) ;
if ( p )
* p = 0 ;
if ( isnumber ( optarg ) ) {
int l = atoi ( optarg ) ;
if ( 0 < = l & & l < = 3 ) {
SysLogLevel = l ;
if ( ! p )
break ;
if ( isnumber ( p + 1 ) ) {
2003-01-26 11:57:55 +01:00
int l = atoi ( p + 1 ) ;
2002-11-24 15:56:24 +01:00
if ( 0 < = l & & l < = 7 ) {
int targets [ ] = { LOG_LOCAL0 , LOG_LOCAL1 , LOG_LOCAL2 , LOG_LOCAL3 , LOG_LOCAL4 , LOG_LOCAL5 , LOG_LOCAL6 , LOG_LOCAL7 } ;
SysLogTarget = targets [ l ] ;
break ;
}
}
}
}
if ( p )
* p = ' . ' ;
2000-07-29 19:03:09 +02:00
fprintf ( stderr , " vdr: invalid log level: %s \n " , optarg ) ;
2001-04-01 11:18:28 +02:00
return 2 ;
2002-11-24 15:56:24 +01:00
}
2000-07-29 19:03:09 +02:00
break ;
2002-05-18 10:36:35 +02:00
case ' L ' : if ( access ( optarg , R_OK | X_OK ) = = 0 )
PluginManager . SetDirectory ( optarg ) ;
else {
fprintf ( stderr , " vdr: can't access plugin directory: %s \n " , optarg ) ;
return 2 ;
}
2002-05-09 16:26:56 +02:00
break ;
2005-07-31 11:38:40 +02:00
case ' l ' | 0x100 :
LircDevice = optarg ? : LIRC_DEVICE ;
break ;
2002-03-08 16:37:42 +01:00
case ' m ' : MuteAudio = true ;
break ;
2005-07-31 11:38:40 +02:00
case ' n ' | 0x100 :
UseKbd = false ;
break ;
2000-07-23 15:01:31 +02:00
case ' p ' : if ( isnumber ( optarg ) )
2000-07-29 19:03:09 +02:00
SVDRPport = atoi ( optarg ) ;
2000-07-23 15:01:31 +02:00
else {
fprintf ( stderr , " vdr: invalid port number: %s \n " , optarg ) ;
2001-04-01 11:18:28 +02:00
return 2 ;
2000-07-23 15:01:31 +02:00
}
break ;
2002-05-09 16:26:56 +02:00
case ' P ' : PluginManager . AddPlugin ( optarg ) ;
break ;
2005-07-31 11:38:40 +02:00
case ' r ' | 0x100 :
RcuDevice = optarg ? : RCU_DEVICE ;
break ;
2001-09-23 14:02:11 +02:00
case ' r ' : cRecordingUserCommand : : SetCommand ( optarg ) ;
2001-09-22 14:23:55 +02:00
break ;
2007-02-25 10:56:29 +01:00
case ' s ' : ShutdownHandler . SetShutdownCommand ( optarg ) ;
2001-09-01 09:04:37 +02:00
break ;
2001-03-31 10:32:58 +02:00
case ' t ' : Terminal = optarg ;
2003-09-05 13:02:15 +02:00
if ( access ( Terminal , R_OK | W_OK ) < 0 ) {
fprintf ( stderr , " vdr: can't access terminal: %s \n " , Terminal ) ;
return 2 ;
}
2001-03-31 10:32:58 +02:00
break ;
2005-12-31 13:30:11 +01:00
case ' u ' : if ( * optarg )
VdrUser = optarg ;
break ;
2002-05-09 16:26:56 +02:00
case ' V ' : DisplayVersion = true ;
2002-03-29 10:10:04 +01:00
break ;
2005-09-03 13:35:55 +02:00
case ' v ' | 0x100 :
VfatFileSystem = true ;
break ;
2000-07-28 13:44:31 +02:00
case ' v ' : VideoDirectory = optarg ;
2000-09-17 14:18:14 +02:00
while ( optarg & & * optarg & & optarg [ strlen ( optarg ) - 1 ] = = ' / ' )
optarg [ strlen ( optarg ) - 1 ] = 0 ;
2000-07-28 13:44:31 +02:00
break ;
2002-11-24 15:56:24 +01:00
case ' w ' : if ( isnumber ( optarg ) ) { int t = atoi ( optarg ) ;
2001-02-24 16:18:43 +01:00
if ( t > = 0 ) {
WatchdogTimeout = t ;
break ;
}
}
fprintf ( stderr , " vdr: invalid watchdog timeout: %s \n " , optarg ) ;
2001-04-01 11:18:28 +02:00
return 2 ;
2001-02-24 16:18:43 +01:00
break ;
2001-04-01 11:18:28 +02:00
default : return 2 ;
2000-07-23 15:01:31 +02:00
}
}
2005-12-31 13:30:11 +01:00
// Set user id in case we were started as root:
2006-04-14 11:04:20 +02:00
if ( VdrUser & & geteuid ( ) = = 0 ) {
2005-12-31 13:30:11 +01:00
StartedAsRoot = true ;
2006-01-09 16:54:35 +01:00
if ( strcmp ( VdrUser , " root " ) ) {
if ( ! SetKeepCaps ( true ) )
return 2 ;
if ( ! SetUser ( VdrUser ) )
return 2 ;
if ( ! SetKeepCaps ( false ) )
return 2 ;
if ( ! SetCapSysTime ( ) )
return 2 ;
}
2005-12-31 13:30:11 +01:00
}
2002-05-09 16:26:56 +02:00
// Help and version info:
if ( DisplayHelp | | DisplayVersion ) {
if ( ! PluginManager . HasPlugins ( ) )
PluginManager . AddPlugin ( " * " ) ; // adds all available plugins
PluginManager . LoadPlugins ( ) ;
if ( DisplayHelp ) {
printf ( " Usage: vdr [OPTIONS] \n \n " // for easier orientation, this is column 80|
" -a CMD, --audio=CMD send Dolby Digital audio to stdin of command CMD \n "
" -c DIR, --config=DIR read config files from DIR (default is to read them \n "
" from the video directory) \n "
" -d, --daemon run in daemon mode \n "
" -D NUM, --device=NUM use only the given DVB device (NUM = 0, 1, 2...) \n "
" there may be several -D options (default: all DVB \n "
" devices will be used) \n "
2005-12-31 13:30:11 +01:00
" -E FILE, --epgfile=FILE write the EPG data into the given FILE (default is \n "
2003-12-22 13:29:24 +01:00
" '%s' in the video directory) \n "
" '-E-' disables this \n "
2002-05-09 16:26:56 +02:00
" if FILE is a directory, the default EPG file will be \n "
" created in that directory \n "
2005-12-31 13:30:11 +01:00
" -g DIR, --grab=DIR write images from the SVDRP command GRAB into the \n "
2005-12-30 15:11:16 +01:00
" given DIR; DIR must be the full path name of an \n "
" existing directory, without any \" .. \" , double '/' \n "
" or symlinks (default: none, same as -g-) \n "
2002-05-09 16:26:56 +02:00
" -h, --help print this help and exit \n "
" -l LEVEL, --log=LEVEL set log level (default: 3) \n "
" 0 = no logging, 1 = errors only, \n "
" 2 = errors and info, 3 = errors, info and debug \n "
2002-11-24 15:56:24 +01:00
" if logging should be done to LOG_LOCALn instead of \n "
" LOG_USER, add '.n' to LEVEL, as in 3.7 (n=0..7) \n "
2002-05-09 16:26:56 +02:00
" -L DIR, --lib=DIR search for plugins in DIR (default is %s) \n "
2005-07-31 11:38:40 +02:00
" --lirc[=PATH] use a LIRC remote control device, attached to PATH \n "
" (default: %s) \n "
2002-05-09 16:26:56 +02:00
" -m, --mute mute audio of the primary DVB device at startup \n "
2005-07-31 11:38:40 +02:00
" --no-kbd don't use the keyboard as an input device \n "
2002-05-09 16:26:56 +02:00
" -p PORT, --port=PORT use PORT for SVDRP (default: %d) \n "
" 0 turns off SVDRP \n "
" -P OPT, --plugin=OPT load a plugin defined by the given options \n "
2005-07-31 11:38:40 +02:00
" --rcu[=PATH] use a remote control device, attached to PATH \n "
" (default: %s) \n "
2002-05-09 16:26:56 +02:00
" -r CMD, --record=CMD call CMD before and after a recording \n "
" -s CMD, --shutdown=CMD call CMD to shutdown the computer \n "
" -t TTY, --terminal=TTY controlling tty \n "
2006-01-13 16:16:32 +01:00
" -u USER, --user=USER run as user USER; only applicable if started as \n "
" root \n "
2002-05-09 16:26:56 +02:00
" -v DIR, --video=DIR use DIR as video directory (default: %s) \n "
" -V, --version print version information and exit \n "
2005-09-03 13:35:55 +02:00
" --vfat encode special characters in recording names to \n "
" avoid problems with VFAT file systems \n "
2002-05-09 16:26:56 +02:00
" -w SEC, --watchdog=SEC activate the watchdog timer with a timeout of SEC \n "
" seconds (default: %d); '0' disables the watchdog \n "
" \n " ,
2003-12-22 13:29:24 +01:00
DEFAULTEPGDATAFILENAME ,
2002-05-09 16:26:56 +02:00
DEFAULTPLUGINDIR ,
2005-07-31 11:38:40 +02:00
LIRC_DEVICE ,
2002-05-09 16:26:56 +02:00
DEFAULTSVDRPPORT ,
2005-07-31 11:38:40 +02:00
RCU_DEVICE ,
2002-05-09 16:26:56 +02:00
VideoDirectory ,
DEFAULTWATCHDOG
) ;
}
if ( DisplayVersion )
2006-04-22 11:28:37 +02:00
printf ( " vdr (%s/%s) - The Video Disk Recorder \n " , VDRVERSION , APIVERSION ) ;
2002-05-09 16:26:56 +02:00
if ( PluginManager . HasPlugins ( ) ) {
if ( DisplayHelp )
printf ( " Plugins: vdr -P \" name [OPTIONS] \" \n \n " ) ;
for ( int i = 0 ; ; i + + ) {
cPlugin * p = PluginManager . GetPlugin ( i ) ;
if ( p ) {
const char * help = p - > CommandLineHelp ( ) ;
printf ( " %s (%s) - %s \n " , p - > Name ( ) , p - > Version ( ) , p - > Description ( ) ) ;
if ( DisplayHelp & & help ) {
printf ( " \n " ) ;
puts ( help ) ;
}
}
else
break ;
}
}
return 0 ;
}
2005-05-26 10:47:49 +02:00
// Check for UTF-8 and exit if present - asprintf() will fail if it encounters 8 bit ASCII codes
char * LangEnv ;
if ( ( LangEnv = getenv ( " LANG " ) ) ! = NULL & & strcasestr ( LangEnv , " utf " ) | |
2006-09-01 12:59:35 +02:00
( LangEnv = getenv ( " LC_ALL " ) ) ! = NULL & & strcasestr ( LangEnv , " utf " ) | |
2005-05-26 10:47:49 +02:00
( LangEnv = getenv ( " LC_CTYPE " ) ) ! = NULL & & strcasestr ( LangEnv , " utf " ) ) {
fprintf ( stderr , " vdr: please turn off UTF-8 before starting VDR \n " ) ;
return 2 ;
}
2000-07-23 15:01:31 +02:00
// Log file:
2001-08-03 14:18:08 +02:00
2000-07-29 19:03:09 +02:00
if ( SysLogLevel > 0 )
2006-01-15 16:42:37 +01:00
openlog ( " vdr " , LOG_CONS , SysLogTarget ) ; // LOG_PID doesn't work as expected under NPTL
2000-07-23 15:36:43 +02:00
2000-07-28 13:44:31 +02:00
// Check the video directory:
2000-07-29 15:21:42 +02:00
if ( ! DirectoryOk ( VideoDirectory , true ) ) {
2000-07-28 13:44:31 +02:00
fprintf ( stderr , " vdr: can't access video directory %s \n " , VideoDirectory ) ;
2001-04-01 11:18:28 +02:00
return 2 ;
2000-07-28 13:44:31 +02:00
}
2000-07-23 15:36:43 +02:00
// Daemon mode:
if ( DaemonMode ) {
2005-10-09 10:05:21 +02:00
if ( daemon ( 1 , 0 ) = = - 1 ) {
2005-12-31 13:30:11 +01:00
fprintf ( stderr , " vdr: %m \n " ) ;
2002-05-13 16:35:49 +02:00
esyslog ( " ERROR: %m " ) ;
2001-04-01 11:18:28 +02:00
return 2 ;
2000-07-23 15:36:43 +02:00
}
}
2001-03-31 10:32:58 +02:00
else if ( Terminal ) {
// Claim new controlling terminal
stdin = freopen ( Terminal , " r " , stdin ) ;
stdout = freopen ( Terminal , " w " , stdout ) ;
stderr = freopen ( Terminal , " w " , stderr ) ;
2003-05-24 11:08:47 +02:00
HasStdin = true ;
2001-03-31 10:32:58 +02:00
}
2002-05-13 16:35:49 +02:00
isyslog ( " VDR version %s started " , VDRVERSION ) ;
2006-01-13 16:16:32 +01:00
if ( StartedAsRoot & & VdrUser )
2005-12-31 13:30:11 +01:00
isyslog ( " switched to user '%s' " , VdrUser ) ;
2006-01-03 10:20:41 +01:00
if ( DaemonMode )
dsyslog ( " running as daemon (tid=%d) " , cThread : : ThreadId ( ) ) ;
cThread : : SetMainThreadId ( ) ;
2000-02-19 13:36:48 +01:00
2004-10-31 09:37:56 +01:00
// Main program loop variables - need to be here to have them initialized before any EXIT():
cOsdObject * Menu = NULL ;
2006-01-05 13:54:04 +01:00
int LastChannel = 0 ;
2004-10-31 09:37:56 +01:00
int LastTimerChannel = - 1 ;
int PreviousChannel [ 2 ] = { 1 , 1 } ;
int PreviousChannelIndex = 0 ;
time_t LastChannelChanged = time ( NULL ) ;
int MaxLatencyTime = 0 ;
2006-06-04 09:10:59 +02:00
bool InhibitEpgScan = false ;
2006-01-06 12:53:28 +01:00
bool IsInfoMenu = false ;
2006-06-03 14:46:36 +02:00
cSkin * CurrentSkin = NULL ;
2004-10-31 09:37:56 +01:00
2002-05-09 16:26:56 +02:00
// Load plugins:
if ( ! PluginManager . LoadPlugins ( true ) )
2004-10-23 15:17:03 +02:00
EXIT ( 2 ) ;
2002-05-09 16:26:56 +02:00
2000-07-23 15:01:31 +02:00
// Configuration data:
2000-09-15 15:09:15 +02:00
if ( ! ConfigDirectory )
ConfigDirectory = VideoDirectory ;
2002-05-13 16:11:19 +02:00
cPlugin : : SetConfigDirectory ( ConfigDirectory ) ;
2004-12-26 12:45:22 +01:00
cThemes : : SetThemesDirectory ( AddDirectory ( ConfigDirectory , " themes " ) ) ;
Setup . Load ( AddDirectory ( ConfigDirectory , " setup.conf " ) ) ;
if ( ! ( Sources . Load ( AddDirectory ( ConfigDirectory , " sources.conf " ) , true , true ) & &
Diseqcs . Load ( AddDirectory ( ConfigDirectory , " diseqc.conf " ) , true , Setup . DiSEqC ) & &
Channels . Load ( AddDirectory ( ConfigDirectory , " channels.conf " ) , false , true ) & &
Timers . Load ( AddDirectory ( ConfigDirectory , " timers.conf " ) ) & &
Commands . Load ( AddDirectory ( ConfigDirectory , " commands.conf " ) , true ) & &
RecordingCommands . Load ( AddDirectory ( ConfigDirectory , " reccmds.conf " ) , true ) & &
SVDRPhosts . Load ( AddDirectory ( ConfigDirectory , " svdrphosts.conf " ) , true ) & &
Keys . Load ( AddDirectory ( ConfigDirectory , " remote.conf " ) ) & &
KeyMacros . Load ( AddDirectory ( ConfigDirectory , " keymacros.conf " ) , true )
2003-08-16 09:18:52 +02:00
) )
2004-10-23 15:17:03 +02:00
EXIT ( 2 ) ;
2000-02-19 13:36:48 +01:00
2003-10-24 12:53:12 +02:00
cFont : : SetCode ( I18nCharSets ( ) [ Setup . OSDLanguage ] ) ;
2005-09-25 11:00:57 +02:00
// Recordings:
Recordings . Update ( ) ;
2005-12-18 10:41:26 +01:00
DeletedRecordings . Update ( ) ;
2005-09-25 11:00:57 +02:00
2003-12-22 13:29:24 +01:00
// EPG data:
if ( EpgDataFileName ) {
2004-12-19 16:33:34 +01:00
const char * EpgDirectory = NULL ;
if ( DirectoryOk ( EpgDataFileName ) ) {
EpgDirectory = EpgDataFileName ;
EpgDataFileName = DEFAULTEPGDATAFILENAME ;
}
2003-12-22 13:29:24 +01:00
else if ( * EpgDataFileName ! = ' / ' & & * EpgDataFileName ! = ' . ' )
2004-12-19 16:33:34 +01:00
EpgDirectory = VideoDirectory ;
2005-01-14 16:55:28 +01:00
if ( EpgDirectory )
cSchedules : : SetEpgDataFileName ( AddDirectory ( EpgDirectory , EpgDataFileName ) ) ;
else
cSchedules : : SetEpgDataFileName ( EpgDataFileName ) ;
2004-12-19 16:33:34 +01:00
cSchedules : : Read ( ) ;
2003-12-22 13:29:24 +01:00
}
2000-11-03 15:31:03 +01:00
// DVB interfaces:
2002-08-16 09:57:10 +02:00
cDvbDevice : : Initialize ( ) ;
2000-11-03 15:31:03 +01:00
2003-05-09 15:27:46 +02:00
// Initialize plugins:
2002-05-09 16:26:56 +02:00
2003-05-09 15:27:46 +02:00
if ( ! PluginManager . InitializePlugins ( ) )
2004-10-23 15:17:03 +02:00
EXIT ( 2 ) ;
2002-05-09 16:26:56 +02:00
2002-08-04 14:57:29 +02:00
// Primary device:
cDevice : : SetPrimaryDevice ( Setup . PrimaryDVB ) ;
2003-04-12 12:20:07 +02:00
if ( ! cDevice : : PrimaryDevice ( ) | | ! cDevice : : PrimaryDevice ( ) - > HasDecoder ( ) ) {
if ( cDevice : : PrimaryDevice ( ) & & ! cDevice : : PrimaryDevice ( ) - > HasDecoder ( ) )
isyslog ( " device %d has no MPEG decoder " , cDevice : : PrimaryDevice ( ) - > DeviceNumber ( ) + 1 ) ;
2003-03-09 14:10:12 +01:00
for ( int i = 0 ; i < cDevice : : NumDevices ( ) ; i + + ) {
cDevice * d = cDevice : : GetDevice ( i ) ;
if ( d & & d - > HasDecoder ( ) ) {
isyslog ( " trying device number %d instead " , i + 1 ) ;
2003-04-12 12:20:07 +02:00
if ( cDevice : : SetPrimaryDevice ( i + 1 ) ) {
2003-03-09 14:10:12 +01:00
Setup . PrimaryDVB = i + 1 ;
2003-04-12 12:20:07 +02:00
break ;
}
2003-03-09 14:10:12 +01:00
}
}
2003-04-12 12:20:07 +02:00
if ( ! cDevice : : PrimaryDevice ( ) ) {
const char * msg = " no primary device found - using first device! " ;
fprintf ( stderr , " vdr: %s \n " , msg ) ;
esyslog ( " ERROR: %s " , msg ) ;
2003-09-05 13:15:51 +02:00
if ( ! cDevice : : SetPrimaryDevice ( 1 ) )
2004-10-23 15:17:03 +02:00
EXIT ( 2 ) ;
2003-04-12 12:20:07 +02:00
if ( ! cDevice : : PrimaryDevice ( ) ) {
const char * msg = " no primary device found - giving up! " ;
fprintf ( stderr , " vdr: %s \n " , msg ) ;
esyslog ( " ERROR: %s " , msg ) ;
2004-10-23 15:17:03 +02:00
EXIT ( 2 ) ;
2003-04-12 12:20:07 +02:00
}
}
2002-08-16 09:57:10 +02:00
}
2002-08-04 14:57:29 +02:00
2007-02-25 10:56:29 +01:00
// Check for timers in automatic start time window:
ShutdownHandler . CheckManualStart ( MANUALSTART ) ;
2002-09-29 13:40:45 +02:00
// User interface:
Interface = new cInterface ( SVDRPport ) ;
2005-01-14 13:10:32 +01:00
// Default skins:
new cSkinClassic ;
new cSkinSTTNG ;
Skins . SetCurrent ( Setup . OSDSkin ) ;
cThemes : : Load ( Skins . Current ( ) - > Name ( ) , Setup . OSDTheme , Skins . Current ( ) - > Theme ( ) ) ;
2006-06-03 14:46:36 +02:00
CurrentSkin = Skins . Current ( ) ;
2005-01-14 13:10:32 +01:00
2003-05-16 12:27:58 +02:00
// Start plugins:
if ( ! PluginManager . StartPlugins ( ) )
2004-10-23 15:17:03 +02:00
EXIT ( 2 ) ;
2003-05-16 12:27:58 +02:00
2005-01-14 13:10:32 +01:00
// Set skin and theme in case they're implemented by a plugin:
2004-05-16 10:35:36 +02:00
2006-06-03 14:46:36 +02:00
if ( ! CurrentSkin | | CurrentSkin = = Skins . Current ( ) & & strcmp ( Skins . Current ( ) - > Name ( ) , Setup . OSDSkin ) ! = 0 ) {
Skins . SetCurrent ( Setup . OSDSkin ) ;
cThemes : : Load ( Skins . Current ( ) - > Name ( ) , Setup . OSDTheme , Skins . Current ( ) - > Theme ( ) ) ;
}
2004-05-16 10:35:36 +02:00
2002-09-29 13:40:45 +02:00
// Remote Controls:
2005-07-31 11:38:40 +02:00
if ( RcuDevice )
new cRcuRemote ( RcuDevice ) ;
if ( LircDevice )
new cLircRemote ( LircDevice ) ;
if ( ! DaemonMode & & HasStdin & & UseKbd )
2002-12-08 14:30:32 +01:00
new cKbdRemote ;
2002-09-29 13:40:45 +02:00
Interface - > LearnKeys ( ) ;
2002-11-03 11:53:58 +01:00
// External audio:
if ( AudioCommand )
new cExternalAudio ( AudioCommand ) ;
2002-05-09 16:26:56 +02:00
// Channel:
2005-08-21 08:56:49 +02:00
if ( ! cDevice : : WaitForAllDevicesReady ( DEVICEREADYTIMEOUT ) )
dsyslog ( " not all devices ready after %d seconds " , DEVICEREADYTIMEOUT ) ;
2006-04-09 13:26:56 +02:00
if ( Setup . InitialChannel > 0 )
Setup . CurrentChannel = Setup . InitialChannel ;
if ( Setup . InitialVolume > = 0 )
Setup . CurrentVolume = Setup . InitialVolume ;
2001-01-14 15:29:51 +01:00
Channels . SwitchTo ( Setup . CurrentChannel ) ;
2002-03-08 16:37:42 +01:00
if ( MuteAudio )
2002-06-16 12:57:31 +02:00
cDevice : : PrimaryDevice ( ) - > ToggleMute ( ) ;
2002-03-08 16:37:42 +01:00
else
2002-06-16 12:57:31 +02:00
cDevice : : PrimaryDevice ( ) - > SetVolume ( Setup . CurrentVolume , true ) ;
2000-02-19 13:36:48 +01:00
2000-07-23 15:01:31 +02:00
// Signal handlers:
2000-04-15 17:38:11 +02:00
if ( signal ( SIGHUP , SignalHandler ) = = SIG_IGN ) signal ( SIGHUP , SIG_IGN ) ;
if ( signal ( SIGINT , SignalHandler ) = = SIG_IGN ) signal ( SIGINT , SIG_IGN ) ;
if ( signal ( SIGTERM , SignalHandler ) = = SIG_IGN ) signal ( SIGTERM , SIG_IGN ) ;
2000-09-15 13:58:36 +02:00
if ( signal ( SIGPIPE , SignalHandler ) = = SIG_IGN ) signal ( SIGPIPE , SIG_IGN ) ;
2001-02-24 16:18:43 +01:00
if ( WatchdogTimeout > 0 )
if ( signal ( SIGALRM , Watchdog ) = = SIG_IGN ) signal ( SIGALRM , SIG_IGN ) ;
2000-04-15 17:38:11 +02:00
2003-05-09 15:27:46 +02:00
// Watchdog:
if ( WatchdogTimeout > 0 ) {
dsyslog ( " setting watchdog timer to %d seconds " , WatchdogTimeout ) ;
alarm ( WatchdogTimeout ) ; // Initial watchdog timer start
}
2000-07-23 15:01:31 +02:00
// Main program loop:
2006-01-06 12:53:28 +01:00
# define DELETE_MENU ((IsInfoMenu &= (Menu == NULL)), delete Menu, Menu = NULL)
2007-02-25 10:56:29 +01:00
while ( ! ShutdownHandler . DoExit ( ) ) {
2004-10-16 09:36:28 +02:00
# ifdef DEBUGRINGBUFFERS
cRingBufferLinear : : PrintDebugRBL ( ) ;
# endif
2002-06-23 11:23:34 +02:00
// Attach launched player control:
cControl : : Attach ( ) ;
2003-05-03 13:42:37 +02:00
// Make sure we have a visible programme in case device usage has changed:
2003-05-24 13:38:28 +02:00
if ( ! EITScanner . Active ( ) & & cDevice : : PrimaryDevice ( ) - > HasDecoder ( ) & & ! cDevice : : PrimaryDevice ( ) - > HasProgramme ( ) ) {
2003-05-03 13:42:37 +02:00
static time_t lastTime = 0 ;
if ( time ( NULL ) - lastTime > MINCHANNELWAIT ) {
2004-02-13 13:15:12 +01:00
cChannel * Channel = Channels . GetByNumber ( cDevice : : CurrentChannel ( ) ) ;
2004-12-17 14:55:49 +01:00
if ( Channel & & ( Channel - > Vpid ( ) | | Channel - > Apid ( 0 ) ) ) {
2004-02-13 13:15:12 +01:00
if ( ! Channels . SwitchTo ( cDevice : : CurrentChannel ( ) ) // try to switch to the original channel...
& & ! ( LastTimerChannel > 0 & & Channels . SwitchTo ( LastTimerChannel ) ) // ...or the one used by the last timer...
& & ! cDevice : : SwitchChannel ( 1 ) // ...or the next higher available one...
& & ! cDevice : : SwitchChannel ( - 1 ) ) // ...or the next lower available one
2006-01-08 11:44:37 +01:00
;
}
2004-02-13 13:15:12 +01:00
lastTime = time ( NULL ) ; // don't do this too often
2003-05-24 15:34:30 +02:00
LastTimerChannel = - 1 ;
2003-05-03 13:42:37 +02:00
}
}
2001-02-24 16:18:43 +01:00
// Restart the Watchdog timer:
if ( WatchdogTimeout > 0 ) {
int LatencyTime = WatchdogTimeout - alarm ( WatchdogTimeout ) ;
if ( LatencyTime > MaxLatencyTime ) {
MaxLatencyTime = LatencyTime ;
2002-05-13 16:35:49 +02:00
dsyslog ( " max. latency time %d seconds " , MaxLatencyTime ) ;
2001-02-24 16:18:43 +01:00
}
}
2004-10-31 10:22:32 +01:00
// Handle channel and timer modifications:
if ( ! Channels . BeingEdited ( ) & & ! Timers . BeingEdited ( ) ) {
2004-10-17 11:50:21 +02:00
int modified = Channels . Modified ( ) ;
static time_t ChannelSaveTimeout = 0 ;
2006-01-15 13:44:55 +01:00
static int TimerState = 0 ;
2004-10-31 10:22:32 +01:00
// Channels and timers need to be stored in a consistent manner,
// therefore if one of them is changed, we save both.
2006-01-15 13:44:55 +01:00
if ( modified = = CHANNELSMOD_USER | | Timers . Modified ( TimerState ) )
2004-10-17 11:50:21 +02:00
ChannelSaveTimeout = 1 ; // triggers an immediate save
else if ( modified & & ! ChannelSaveTimeout )
ChannelSaveTimeout = time ( NULL ) + CHANNELSAVEDELTA ;
bool timeout = ChannelSaveTimeout = = 1 | | ChannelSaveTimeout & & time ( NULL ) > ChannelSaveTimeout & & ! cRecordControls : : Active ( ) ;
if ( ( modified | | timeout ) & & Channels . Lock ( false , 100 ) ) {
if ( timeout ) {
Channels . Save ( ) ;
Timers . Save ( ) ;
ChannelSaveTimeout = 0 ;
}
2004-01-04 12:30:00 +01:00
for ( cChannel * Channel = Channels . First ( ) ; Channel ; Channel = Channels . Next ( Channel ) ) {
2004-02-08 11:23:29 +01:00
if ( Channel - > Modification ( CHANNELMOD_RETUNE ) ) {
2004-01-04 12:30:00 +01:00
cRecordControls : : ChannelDataModified ( Channel ) ;
if ( Channel - > Number ( ) = = cDevice : : CurrentChannel ( ) ) {
2006-02-04 14:58:24 +01:00
if ( ! cDevice : : PrimaryDevice ( ) - > Replaying ( ) | | cDevice : : PrimaryDevice ( ) - > Transferring ( ) ) {
2004-02-15 14:31:53 +01:00
if ( cDevice : : ActualDevice ( ) - > ProvidesTransponder ( Channel ) ) { // avoids retune on devices that don't really access the transponder
isyslog ( " retuning due to modification of channel %d " , Channel - > Number ( ) ) ;
Channels . SwitchTo ( Channel - > Number ( ) ) ;
}
2004-01-04 12:30:00 +01:00
}
}
}
}
Channels . Unlock ( ) ;
}
}
2000-04-22 13:51:48 +02:00
// Channel display:
2002-06-16 12:57:31 +02:00
if ( ! EITScanner . Active ( ) & & cDevice : : CurrentChannel ( ) ! = LastChannel ) {
2000-09-09 14:57:43 +02:00
if ( ! Menu )
2006-01-05 13:54:04 +01:00
Menu = new cDisplayChannel ( cDevice : : CurrentChannel ( ) , LastChannel > = 0 ) ;
2002-06-16 12:57:31 +02:00
LastChannel = cDevice : : CurrentChannel ( ) ;
2003-06-19 10:06:07 +02:00
LastChannelChanged = time ( NULL ) ;
}
2006-01-22 16:10:35 +01:00
if ( time ( NULL ) - LastChannelChanged > = Setup . ZapTimeout & & LastChannel ! = PreviousChannel [ PreviousChannelIndex ] )
2003-08-16 15:27:26 +02:00
PreviousChannel [ PreviousChannelIndex ^ = 1 ] = LastChannel ;
2000-05-01 16:29:46 +02:00
// Timers and Recordings:
2003-02-09 13:14:44 +01:00
if ( ! Timers . BeingEdited ( ) ) {
2004-03-14 14:28:08 +01:00
// Assign events to timers:
2004-10-24 15:01:50 +02:00
Timers . SetEvents ( ) ;
// Must do all following calls with the exact same time!
time_t Now = time ( NULL ) ;
2004-02-29 14:21:22 +01:00
// Process ongoing recordings:
2001-09-01 15:04:14 +02:00
cRecordControls : : Process ( Now ) ;
2004-02-29 14:21:22 +01:00
// Start new recordings:
2001-09-01 15:04:14 +02:00
cTimer * Timer = Timers . GetMatch ( Now ) ;
2000-04-30 10:22:13 +02:00
if ( Timer ) {
2001-08-11 15:48:54 +02:00
if ( ! cRecordControls : : Start ( Timer ) )
Timer - > SetPending ( true ) ;
2003-05-24 15:34:30 +02:00
else
LastTimerChannel = Timer - > Channel ( ) - > Number ( ) ;
2000-04-15 17:38:11 +02:00
}
2006-06-04 09:10:59 +02:00
// Make sure timers "see" their channel early enough:
static time_t LastTimerCheck = 0 ;
if ( Now - LastTimerCheck > TIMERCHECKDELTA ) { // don't do this too often
InhibitEpgScan = false ;
2006-04-09 09:12:47 +02:00
static time_t DeviceUsed [ MAXDEVICES ] = { 0 } ;
for ( cTimer * Timer = Timers . First ( ) ; Timer ; Timer = Timers . Next ( Timer ) ) {
2006-05-07 09:13:36 +02:00
bool InVpsMargin = false ;
bool NeedsTransponder = false ;
2006-06-04 09:10:59 +02:00
if ( Timer - > HasFlags ( tfActive ) & & ! Timer - > Recording ( ) ) {
if ( Timer - > HasFlags ( tfVps ) ) {
2006-06-16 09:22:20 +02:00
if ( Timer - > Matches ( Now , true , Setup . VpsMargin ) ) {
2006-06-04 09:10:59 +02:00
InVpsMargin = true ;
2006-06-16 09:22:20 +02:00
Timer - > SetInVpsMargin ( InVpsMargin ) ;
}
else if ( Timer - > Event ( ) ) {
InVpsMargin = Timer - > Event ( ) - > StartTime ( ) < = Now & & Timer - > Event ( ) - > RunningStatus ( ) = = SI : : RunningStatusUndefined ;
2006-06-04 09:10:59 +02:00
NeedsTransponder = Timer - > Event ( ) - > StartTime ( ) - Now < VPSLOOKAHEADTIME * 3600 & & ! Timer - > Event ( ) - > SeenWithin ( VPSUPTODATETIME ) ;
2006-06-16 09:22:20 +02:00
}
2006-06-04 09:10:59 +02:00
else {
cSchedulesLock SchedulesLock ;
const cSchedules * Schedules = cSchedules : : Schedules ( SchedulesLock ) ;
if ( Schedules ) {
const cSchedule * Schedule = Schedules - > GetSchedule ( Timer - > Channel ( ) ) ;
2006-06-18 08:50:04 +02:00
InVpsMargin = ! Schedule ; // we must make sure we have the schedule
2006-06-04 09:10:59 +02:00
NeedsTransponder = Schedule & & ! Schedule - > PresentSeenWithin ( VPSUPTODATETIME ) ;
}
2006-05-07 09:13:36 +02:00
}
2006-06-04 09:10:59 +02:00
InhibitEpgScan | = InVpsMargin | NeedsTransponder ;
2006-05-07 09:13:36 +02:00
}
2006-06-04 09:10:59 +02:00
else
NeedsTransponder = Timer - > Matches ( Now , true , TIMERLOOKAHEADTIME ) ;
2006-05-07 09:13:36 +02:00
}
if ( NeedsTransponder | | InVpsMargin ) {
2006-04-09 09:12:47 +02:00
// Find a device that provides the required transponder:
cDevice * Device = NULL ;
2006-06-16 09:22:20 +02:00
bool DeviceAvailable = false ;
2006-04-09 09:12:47 +02:00
for ( int i = 0 ; i < cDevice : : NumDevices ( ) ; i + + ) {
cDevice * d = cDevice : : GetDevice ( i ) ;
if ( d & & d - > ProvidesTransponder ( Timer - > Channel ( ) ) ) {
if ( d - > IsTunedToTransponder ( Timer - > Channel ( ) ) ) {
// if any device is tuned to the transponder, we're done
Device = d ;
break ;
}
2006-06-16 09:22:20 +02:00
bool timeout = Now - DeviceUsed [ d - > DeviceNumber ( ) ] > TIMERDEVICETIMEOUT ; // only check other devices if they have been left alone for a while
if ( d - > MaySwitchTransponder ( ) ) {
DeviceAvailable = true ; // avoids using the actual device below
if ( timeout )
Device = d ; // only check other devices if they have been left alone for a while
2006-04-09 09:12:47 +02:00
}
2006-06-16 09:22:20 +02:00
else if ( timeout & & ! Device & & InVpsMargin & & ! d - > Receiving ( ) & & d - > ProvidesTransponderExclusively ( Timer - > Channel ( ) ) )
Device = d ; // use this one only if no other with less impact can be found
2006-04-09 09:12:47 +02:00
}
}
2006-06-16 09:22:20 +02:00
if ( ! Device & & InVpsMargin & & ! DeviceAvailable ) {
2006-04-09 09:12:47 +02:00
cDevice * d = cDevice : : ActualDevice ( ) ;
2006-06-04 09:10:59 +02:00
if ( ! d - > Receiving ( ) & & d - > ProvidesTransponder ( Timer - > Channel ( ) ) & & Now - DeviceUsed [ d - > DeviceNumber ( ) ] > TIMERDEVICETIMEOUT )
2006-04-09 09:12:47 +02:00
Device = d ; // use the actual device as a last resort
}
// Switch the device to the transponder:
if ( Device ) {
if ( ! Device - > IsTunedToTransponder ( Timer - > Channel ( ) ) ) {
2006-04-28 13:29:22 +02:00
if ( Device = = cDevice : : ActualDevice ( ) & & ! Device - > IsPrimaryDevice ( ) )
cDevice : : PrimaryDevice ( ) - > StopReplay ( ) ; // stop transfer mode
2006-04-09 09:12:47 +02:00
dsyslog ( " switching device %d to channel %d " , Device - > DeviceNumber ( ) + 1 , Timer - > Channel ( ) - > Number ( ) ) ;
Device - > SwitchChannel ( Timer - > Channel ( ) , false ) ;
DeviceUsed [ Device - > DeviceNumber ( ) ] = Now ;
}
if ( cDevice : : PrimaryDevice ( ) - > HasDecoder ( ) & & ! cDevice : : PrimaryDevice ( ) - > HasProgramme ( ) ) {
// the previous SwitchChannel() has switched away the current live channel
Channels . SwitchTo ( Timer - > Channel ( ) - > Number ( ) ) ; // avoids toggling between old channel and black screen
Skins . Message ( mtInfo , tr ( " Upcoming VPS recording! " ) ) ;
}
}
2004-02-29 14:21:22 +01:00
}
}
2006-06-04 09:10:59 +02:00
LastTimerCheck = time ( NULL ) ;
2006-04-09 09:12:47 +02:00
}
2006-04-01 13:27:14 +02:00
// Delete expired timers:
Timers . DeleteExpired ( ) ;
2000-04-15 17:38:11 +02:00
}
2005-12-18 10:41:26 +01:00
if ( ! Menu & & Recordings . NeedsUpdate ( ) ) {
2005-09-25 11:00:57 +02:00
Recordings . Update ( ) ;
2005-12-18 10:41:26 +01:00
DeletedRecordings . Update ( ) ;
}
2003-01-06 14:44:27 +01:00
// CAM control:
2007-01-07 14:46:14 +01:00
if ( ! Menu & & ! cOsd : : IsOpen ( ) )
2003-01-06 14:44:27 +01:00
Menu = CamControl ( ) ;
2005-11-27 15:57:03 +01:00
// Queued messages:
if ( ! Skins . IsOpen ( ) )
Skins . ProcessQueuedMessages ( ) ;
2000-04-16 15:50:21 +02:00
// User Input:
2002-06-23 11:23:34 +02:00
cOsdObject * Interact = Menu ? Menu : cControl : : Control ( ) ;
2007-01-07 14:46:14 +01:00
eKeys key = Interface - > GetKey ( ! Interact | | ! Interact - > NeedsFastResponse ( ) ) ;
2007-02-25 10:56:29 +01:00
if ( ISREALKEY ( key ) ) {
2000-11-18 13:57:32 +01:00
EITScanner . Activity ( ) ;
2007-02-25 10:56:29 +01:00
// Cancel shutdown countdown:
if ( ShutdownHandler . countdown )
ShutdownHandler . countdown . Cancel ( ) ;
// Set user active for MinUserInactivity time in the future:
ShutdownHandler . SetUserInactiveTimeout ( ) ;
2001-09-01 09:04:37 +02:00
}
2001-09-23 14:36:38 +02:00
// Keys that must work independent of any interactive mode:
switch ( key ) {
2002-06-23 09:44:00 +02:00
// Menu control:
2006-01-13 15:45:02 +01:00
case kMenu : {
2003-05-02 10:59:07 +02:00
key = kNone ; // nobody else needs to see this key
2006-01-13 15:45:02 +01:00
bool WasOpen = Interact ! = NULL ;
bool WasMenu = Interact & & Interact - > IsMenu ( ) ;
2006-01-04 13:22:53 +01:00
if ( Menu )
2006-01-06 12:53:28 +01:00
DELETE_MENU ;
2006-02-04 13:03:03 +01:00
else if ( cControl : : Control ( ) ) {
if ( cOsd : : IsOpen ( ) )
cControl : : Control ( ) - > Hide ( ) ;
else
WasOpen = false ;
}
2007-02-25 11:39:40 +01:00
if ( ! WasOpen | | ! WasMenu & & ! Setup . MenuKeyCloses )
2006-01-04 13:22:53 +01:00
Menu = new cMenuMain ;
2006-01-13 15:45:02 +01:00
}
2002-06-23 09:44:00 +02:00
break ;
2006-01-06 12:53:28 +01:00
// Info:
case kInfo : {
bool WasInfoMenu = IsInfoMenu ;
DELETE_MENU ;
if ( ! WasInfoMenu ) {
IsInfoMenu = true ;
if ( cControl : : Control ( ) ) {
cControl : : Control ( ) - > Hide ( ) ;
Menu = cControl : : Control ( ) - > GetInfo ( ) ;
if ( Menu )
Menu - > Show ( ) ;
else
IsInfoMenu = false ;
}
else {
cRemote : : Put ( kOk , true ) ;
cRemote : : Put ( kSchedule , true ) ;
}
}
}
break ;
2006-01-22 14:27:53 +01:00
// Direct main menu functions:
2005-09-03 11:33:43 +02:00
# define DirectMainFunction(function)\
2006-01-06 12:53:28 +01:00
DELETE_MENU ; \
2002-10-27 14:32:06 +01:00
if ( cControl : : Control ( ) ) \
cControl : : Control ( ) - > Hide ( ) ; \
2005-12-24 15:53:53 +01:00
Menu = new cMenuMain ( function ) ; \
2003-05-02 10:59:07 +02:00
key = kNone ; // nobody else needs to see this key
2002-10-27 14:32:06 +01:00
case kSchedule : DirectMainFunction ( osSchedule ) ; break ;
case kChannels : DirectMainFunction ( osChannels ) ; break ;
case kTimers : DirectMainFunction ( osTimers ) ; break ;
case kRecordings : DirectMainFunction ( osRecordings ) ; break ;
case kSetup : DirectMainFunction ( osSetup ) ; break ;
case kCommands : DirectMainFunction ( osCommands ) ; break ;
2003-05-02 10:59:07 +02:00
case kUser1 . . . kUser9 : cRemote : : PutMacro ( key ) ; key = kNone ; break ;
2005-09-03 11:33:43 +02:00
case k_Plugin : {
2006-10-14 10:06:16 +02:00
const char * PluginName = cRemote : : GetPlugin ( ) ;
if ( PluginName ) {
DELETE_MENU ;
if ( cControl : : Control ( ) )
cControl : : Control ( ) - > Hide ( ) ;
cPlugin * plugin = cPluginManager : : GetPlugin ( PluginName ) ;
if ( plugin ) {
Menu = plugin - > MainMenuAction ( ) ;
if ( Menu )
Menu - > Show ( ) ;
}
else
esyslog ( " ERROR: unknown plugin '%s' " , PluginName ) ;
2005-09-03 11:33:43 +02:00
}
key = kNone ; // nobody else needs to see these keys
}
break ;
2002-10-27 14:32:06 +01:00
// Channel up/down:
case kChanUp | k_Repeat :
case kChanUp :
case kChanDn | k_Repeat :
case kChanDn :
2006-01-22 14:27:53 +01:00
if ( ! Interact )
Menu = new cDisplayChannel ( NORMALKEY ( key ) ) ;
else if ( cDisplayChannel : : IsOpen ( ) ) {
Interact - > ProcessKey ( key ) ;
continue ;
}
else
cDevice : : SwitchChannel ( NORMALKEY ( key ) = = kChanUp ? 1 : - 1 ) ;
key = kNone ; // nobody else needs to see these keys
2002-10-27 14:32:06 +01:00
break ;
2005-01-02 15:11:44 +01:00
// Volume control:
2001-09-23 14:36:38 +02:00
case kVolUp | k_Repeat :
case kVolUp :
case kVolDn | k_Repeat :
case kVolDn :
case kMute :
2002-03-09 17:11:49 +01:00
if ( key = = kMute ) {
2003-03-30 10:53:22 +02:00
if ( ! cDevice : : PrimaryDevice ( ) - > ToggleMute ( ) & & ! Menu ) {
key = kNone ; // nobody else needs to see these keys
2002-03-09 17:11:49 +01:00
break ; // no need to display "mute off"
2003-03-30 10:53:22 +02:00
}
2002-03-09 17:11:49 +01:00
}
else
2002-06-16 12:57:31 +02:00
cDevice : : PrimaryDevice ( ) - > SetVolume ( NORMALKEY ( key ) = = kVolDn ? - VOLUMEDELTA : VOLUMEDELTA ) ;
2004-05-16 10:35:36 +02:00
if ( ! Menu & & ! cOsd : : IsOpen ( ) )
2006-01-04 13:22:53 +01:00
Menu = cDisplayVolume : : Create ( ) ;
2002-03-09 17:11:49 +01:00
cDisplayVolume : : Process ( key ) ;
2003-03-30 10:53:22 +02:00
key = kNone ; // nobody else needs to see these keys
2001-09-23 14:36:38 +02:00
break ;
2005-01-02 15:11:44 +01:00
// Audio track control:
case kAudio :
2005-01-06 14:36:40 +01:00
if ( cControl : : Control ( ) )
cControl : : Control ( ) - > Hide ( ) ;
2006-01-04 13:22:53 +01:00
if ( ! cDisplayTracks : : IsOpen ( ) ) {
2006-01-06 12:53:28 +01:00
DELETE_MENU ;
2006-01-04 13:22:53 +01:00
Menu = cDisplayTracks : : Create ( ) ;
2005-01-06 14:36:40 +01:00
}
2005-01-02 15:11:44 +01:00
else
cDisplayTracks : : Process ( key ) ;
key = kNone ;
break ;
2003-04-21 14:57:13 +02:00
// Pausing live video:
case kPause :
if ( ! cControl : : Control ( ) ) {
2006-01-06 12:53:28 +01:00
DELETE_MENU ;
2003-04-21 14:57:13 +02:00
if ( ! cRecordControls : : PauseLiveVideo ( ) )
2004-05-16 10:35:36 +02:00
Skins . Message ( mtError , tr ( " No free DVB device to record! " ) ) ;
2003-04-21 14:57:13 +02:00
key = kNone ; // nobody else needs to see this key
}
break ;
// Instant recording:
case kRecord :
if ( ! cControl : : Control ( ) ) {
if ( cRecordControls : : Start ( ) )
2006-01-15 16:04:05 +01:00
Skins . Message ( mtInfo , tr ( " Recording started " ) ) ;
2003-04-21 14:57:13 +02:00
key = kNone ; // nobody else needs to see this key
}
break ;
2001-09-23 14:36:38 +02:00
// Power off:
2007-02-25 10:56:29 +01:00
case kPower :
2006-04-29 09:24:07 +02:00
isyslog ( " Power button pressed " ) ;
DELETE_MENU ;
2007-02-25 10:56:29 +01:00
// Check for activity, request power button again if active:
if ( ! ShutdownHandler . ConfirmShutdown ( false ) & & Skins . Message ( mtWarning , tr ( " VDR will shut down later - press Power to force " ) , SHUTDOWNFORCEPROMPT ) ! = kPower ) {
// Not pressed power - set VDR to be non-interactive and power down later:
ShutdownHandler . SetUserInactive ( ) ;
2006-04-29 09:24:07 +02:00
break ;
}
2007-02-25 10:56:29 +01:00
// No activity or power button pressed twice - ask for confirmation:
if ( ! ShutdownHandler . ConfirmShutdown ( true ) ) {
// Non-confirmed background activity - set VDR to be non-interactive and power down later:
ShutdownHandler . SetUserInactive ( ) ;
2006-04-29 09:24:07 +02:00
break ;
2006-05-05 13:45:42 +02:00
}
2007-02-25 10:56:29 +01:00
// Ask the final question:
if ( ! Interface - > Confirm ( tr ( " Press any key to cancel shutdown " ) , SHUTDOWNCANCELROMPT , true ) )
// If final question was canceled, continue to be active:
break ;
// Ok, now call the shutdown script:
ShutdownHandler . DoShutdown ( true ) ;
// Set VDR to be non-interactive and power down again later:
ShutdownHandler . SetUserInactive ( ) ;
// Do not attempt to automatically shut down for a while:
ShutdownHandler . SetRetry ( SHUTDOWNRETRY ) ;
2006-04-29 09:24:07 +02:00
break ;
2002-10-27 14:32:06 +01:00
default : break ;
2001-09-23 14:36:38 +02:00
}
2002-10-27 14:32:06 +01:00
Interact = Menu ? Menu : cControl : : Control ( ) ; // might have been closed in the mean time
if ( Interact ) {
eOSState state = Interact - > ProcessKey ( key ) ;
2005-09-04 08:57:15 +02:00
if ( state = = osUnknown & & Interact ! = cControl : : Control ( ) ) {
2005-11-04 13:52:31 +01:00
if ( ISMODELESSKEY ( key ) & & cControl : : Control ( ) ) {
2005-09-03 11:51:54 +02:00
state = cControl : : Control ( ) - > ProcessKey ( key ) ;
2005-11-04 13:52:31 +01:00
if ( state = = osEnd ) {
// let's not close a menu when replay ends:
cControl : : Shutdown ( ) ;
continue ;
}
}
2007-02-25 10:56:29 +01:00
else if ( time ( NULL ) - cRemote : : LastActivity ( ) > MENUTIMEOUT )
2005-09-03 11:51:54 +02:00
state = osEnd ;
}
2002-10-27 14:32:06 +01:00
switch ( state ) {
2006-01-06 12:53:28 +01:00
case osPause : DELETE_MENU ;
2003-04-21 14:57:13 +02:00
cControl : : Shutdown ( ) ; // just in case
if ( ! cRecordControls : : PauseLiveVideo ( ) )
2004-05-16 10:35:36 +02:00
Skins . Message ( mtError , tr ( " No free DVB device to record! " ) ) ;
2003-04-21 14:57:13 +02:00
break ;
2006-01-06 12:53:28 +01:00
case osRecord : DELETE_MENU ;
2002-10-27 14:32:06 +01:00
if ( cRecordControls : : Start ( ) )
2006-01-04 15:21:55 +01:00
Skins . Message ( mtInfo , tr ( " Recording started " ) ) ;
2002-10-27 14:32:06 +01:00
break ;
case osRecordings :
2006-01-06 12:53:28 +01:00
DELETE_MENU ;
2002-10-27 14:32:06 +01:00
cControl : : Shutdown ( ) ;
2005-12-24 15:53:53 +01:00
Menu = new cMenuMain ( osRecordings ) ;
2002-10-27 14:32:06 +01:00
break ;
2006-01-06 12:53:28 +01:00
case osReplay : DELETE_MENU ;
2002-10-27 14:32:06 +01:00
cControl : : Shutdown ( ) ;
cControl : : Launch ( new cReplayControl ) ;
break ;
case osStopReplay :
2006-01-06 12:53:28 +01:00
DELETE_MENU ;
2002-10-27 14:32:06 +01:00
cControl : : Shutdown ( ) ;
break ;
case osSwitchDvb :
2006-01-06 12:53:28 +01:00
DELETE_MENU ;
2002-10-27 14:32:06 +01:00
cControl : : Shutdown ( ) ;
2004-05-16 10:35:36 +02:00
Skins . Message ( mtInfo , tr ( " Switching primary DVB... " ) ) ;
2002-10-27 14:32:06 +01:00
cDevice : : SetPrimaryDevice ( Setup . PrimaryDVB ) ;
break ;
2006-01-06 12:53:28 +01:00
case osPlugin : DELETE_MENU ;
2006-01-04 13:22:53 +01:00
Menu = cMenuMain : : PluginOsdObject ( ) ;
2002-11-24 10:45:39 +01:00
if ( Menu )
Menu - > Show ( ) ;
break ;
2002-10-27 14:32:06 +01:00
case osBack :
case osEnd : if ( Interact = = Menu )
2006-01-06 12:53:28 +01:00
DELETE_MENU ;
2002-10-27 14:32:06 +01:00
else
cControl : : Shutdown ( ) ;
break ;
default : ;
}
}
else {
// Key functions in "normal" viewing mode:
2006-01-20 13:19:35 +01:00
if ( key ! = kNone & & KeyMacros . Get ( key ) ) {
2006-01-14 10:54:13 +01:00
cRemote : : PutMacro ( key ) ;
key = kNone ;
}
2002-10-27 14:32:06 +01:00
switch ( key ) {
// Toggle channels:
2006-04-15 13:56:03 +02:00
case kChanPrev :
2002-10-27 14:32:06 +01:00
case k0 : {
2003-08-16 15:27:26 +02:00
if ( PreviousChannel [ PreviousChannelIndex ^ 1 ] = = LastChannel | | LastChannel ! = PreviousChannel [ 0 ] & & LastChannel ! = PreviousChannel [ 1 ] )
PreviousChannelIndex ^ = 1 ;
Channels . SwitchTo ( PreviousChannel [ PreviousChannelIndex ^ = 1 ] ) ;
2002-10-27 14:32:06 +01:00
break ;
}
// Direct Channel Select:
case k1 . . . k9 :
2006-04-15 13:46:55 +02:00
// Left/Right rotates through channel groups:
2002-10-27 14:32:06 +01:00
case kLeft | k_Repeat :
case kLeft :
case kRight | k_Repeat :
case kRight :
2006-04-15 13:46:55 +02:00
// Previous/Next rotates through channel groups:
case kPrev | k_Repeat :
case kPrev :
case kNext | k_Repeat :
case kNext :
2002-10-27 14:32:06 +01:00
// Up/Down Channel Select:
case kUp | k_Repeat :
case kUp :
case kDown | k_Repeat :
case kDown :
2006-01-22 14:27:53 +01:00
Menu = new cDisplayChannel ( NORMALKEY ( key ) ) ;
2002-10-27 14:32:06 +01:00
break ;
// Viewing Control:
case kOk : LastChannel = - 1 ; break ; // forces channel display
2005-05-26 10:20:31 +02:00
// Instant resume of the last viewed recording:
case kPlay :
if ( cReplayControl : : LastReplayed ( ) ) {
cControl : : Shutdown ( ) ;
cControl : : Launch ( new cReplayControl ) ;
}
break ;
2002-10-27 14:32:06 +01:00
default : break ;
}
}
2000-12-28 12:57:16 +01:00
if ( ! Menu ) {
2006-06-04 09:10:59 +02:00
if ( ! InhibitEpgScan )
2004-02-29 14:21:22 +01:00
EITScanner . Process ( ) ;
2002-06-22 10:11:59 +02:00
if ( ! cCutter : : Active ( ) & & cCutter : : Ended ( ) ) {
if ( cCutter : : Error ( ) )
2004-05-16 10:35:36 +02:00
Skins . Message ( mtError , tr ( " Editing process failed! " ) ) ;
2002-01-26 13:42:15 +01:00
else
2004-05-16 10:35:36 +02:00
Skins . Message ( mtInfo , tr ( " Editing process finished " ) ) ;
2002-01-26 13:42:15 +01:00
}
2000-12-28 12:57:16 +01:00
}
2007-02-25 10:56:29 +01:00
// SIGHUP shall cause a restart:
if ( LastSignal = = SIGHUP ) {
if ( ShutdownHandler . ConfirmRestart ( true ) & & Interface - > Confirm ( tr ( " Press any key to cancel restart " ) , RESTARTCANCELPROMPT , true ) )
EXIT ( 1 ) ;
LastSignal = 0 ;
}
// Update the shutdown countdown:
if ( ShutdownHandler . countdown & & ShutdownHandler . countdown . Update ( ) ) {
if ( ! ShutdownHandler . ConfirmShutdown ( false ) )
ShutdownHandler . countdown . Cancel ( ) ;
}
if ( ! Interact & & ! cRecordControls : : Active ( ) & & ! cCutter : : Active ( ) & & ! Interface - > HasSVDRPConnection ( ) & & cRemote : : LastActivity ( ) > ACTIVITYTIMEOUT ) {
// Handle housekeeping tasks
// Shutdown:
// Check whether VDR will be ready for shutdown in SHUTDOWNWAIT seconds:
time_t Soon = time ( NULL ) + SHUTDOWNWAIT ;
if ( ShutdownHandler . IsUserInactive ( Soon ) & & ShutdownHandler . Retry ( Soon ) & & ! ShutdownHandler . countdown ) {
if ( ShutdownHandler . ConfirmShutdown ( false ) )
// Time to shut down - start final countdown:
ShutdownHandler . countdown . Start ( tr ( " VDR will shut down in %s minutes " ) , SHUTDOWNWAIT ) ; // the placeholder is really %s!
// Dont try to shut down again for a while:
ShutdownHandler . SetRetry ( SHUTDOWNRETRY ) ;
2001-02-11 14:53:44 +01:00
}
2007-02-25 10:56:29 +01:00
// Countdown run down to 0?
if ( ShutdownHandler . countdown . Done ( ) ) {
// Timed out, now do a final check:
if ( ShutdownHandler . IsUserInactive ( ) & & ShutdownHandler . ConfirmShutdown ( false ) )
ShutdownHandler . DoShutdown ( false ) ;
// Do this again a bit later:
ShutdownHandler . SetRetry ( SHUTDOWNRETRY ) ;
}
// Disk housekeeping:
RemoveDeletedRecordings ( ) ;
cSchedules : : Cleanup ( ) ;
// Plugins housekeeping:
PluginManager . Housekeeping ( ) ;
2001-02-11 14:53:44 +01:00
}
2007-02-25 10:56:29 +01:00
2006-04-17 10:30:00 +02:00
// Main thread hooks of plugins:
PluginManager . MainThreadHook ( ) ;
2000-04-15 17:38:11 +02:00
}
2007-02-25 10:56:29 +01:00
if ( ShutdownHandler . EmergencyExitRequested ( ) )
esyslog ( " emergency exit requested - shutting down " ) ;
2004-10-23 15:17:03 +02:00
Exit :
2005-01-30 14:23:01 +01:00
PluginManager . StopPlugins ( ) ;
2002-06-16 12:57:31 +02:00
cRecordControls : : Shutdown ( ) ;
2002-06-22 10:11:59 +02:00
cCutter : : Stop ( ) ;
2000-04-30 10:22:13 +02:00
delete Menu ;
2002-06-23 11:23:34 +02:00
cControl : : Shutdown ( ) ;
2000-10-08 12:24:30 +02:00
delete Interface ;
2004-05-16 10:35:36 +02:00
cOsdProvider : : Shutdown ( ) ;
2002-10-12 15:22:29 +02:00
Remotes . Clear ( ) ;
2002-11-03 11:53:58 +01:00
Audios . Clear ( ) ;
2004-05-16 10:35:36 +02:00
Skins . Clear ( ) ;
2007-02-25 10:56:29 +01:00
if ( ShutdownHandler . GetExitCode ( ) ! = 2 ) {
2005-05-22 11:23:22 +02:00
Setup . CurrentChannel = cDevice : : CurrentChannel ( ) ;
Setup . CurrentVolume = cDevice : : CurrentVolume ( ) ;
Setup . Save ( ) ;
}
2002-06-16 12:57:31 +02:00
cDevice : : Shutdown ( ) ;
2006-04-14 11:51:13 +02:00
PluginManager . Shutdown ( true ) ;
2006-01-28 14:44:32 +01:00
cSchedules : : Cleanup ( true ) ;
2003-12-22 13:29:24 +01:00
ReportEpgBugFixStats ( ) ;
2001-02-24 16:18:43 +01:00
if ( WatchdogTimeout > 0 )
2002-05-13 16:35:49 +02:00
dsyslog ( " max. latency time %d seconds " , MaxLatencyTime ) ;
2007-02-25 10:56:29 +01:00
isyslog ( " exiting, exit code %d " , ShutdownHandler . GetExitCode ( ) ) ;
if ( ShutdownHandler . EmergencyExitRequested ( ) )
esyslog ( " emergency exit! " ) ;
2000-07-29 19:03:09 +02:00
if ( SysLogLevel > 0 )
closelog ( ) ;
2002-12-13 13:41:55 +01:00
if ( HasStdin )
tcsetattr ( STDIN_FILENO , TCSANOW , & savedTm ) ;
2007-02-25 10:56:29 +01:00
return ShutdownHandler . GetExitCode ( ) ;
2000-02-19 13:36:48 +01:00
}