Home

Dokumentation

Impressum

Dokumentation VDR
 

Main Page   Class Hierarchy   Alphabetical List   Data Structures   File List   Data Fields   Globals  

vdr.c

Go to the documentation of this file.
00001 /*
00002  * vdr.c: Video Disk Recorder main program
00003  *
00004  * Copyright (C) 2000 Klaus Schmidinger
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00019  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
00020  *
00021  * The author can be reached at kls@cadsoft.de
00022  *
00023  * The project's page is at http://www.cadsoft.de/people/kls/vdr
00024  *
00025  * $Id: vdr.c 1.139 2002/12/13 16:01:09 kls Exp $
00026  */
00027 
00028 #include <getopt.h>
00029 #include <locale.h>
00030 #include <signal.h>
00031 #include <stdlib.h>
00032 #include <termios.h>
00033 #include <unistd.h>
00034 #include "audio.h"
00035 #include "channels.h"
00036 #include "config.h"
00037 #include "cutter.h"
00038 #include "device.h"
00039 #include "diseqc.h"
00040 #include "dvbdevice.h"
00041 #include "eitscan.h"
00042 #include "i18n.h"
00043 #include "interface.h"
00044 #include "keys.h"
00045 #include "lirc.h"
00046 #include "menu.h"
00047 #include "osd.h"
00048 #include "plugin.h"
00049 #include "rcu.h"
00050 #include "recording.h"
00051 #include "sources.h"
00052 #include "timers.h"
00053 #include "tools.h"
00054 #include "videodir.h"
00055 
00056 #define ACTIVITYTIMEOUT 60 // seconds before starting housekeeping
00057 #define SHUTDOWNWAIT   300 // seconds to wait in user prompt before automatic shutdown
00058 #define MANUALSTART    600 // seconds the next timer must be in the future to assume manual start
00059 
00060 static int Interrupted = 0;
00061 
00062 static void SignalHandler(int signum)
00063 {
00064   if (signum != SIGPIPE) {
00065      Interrupted = signum;
00066      Interface->Interrupt();
00067      }
00068   signal(signum, SignalHandler);
00069 }
00070 
00071 static void Watchdog(int signum)
00072 {
00073   // Something terrible must have happened that prevented the 'alarm()' from
00074   // being called in time, so let's get out of here:
00075   esyslog("PANIC: watchdog timer expired - exiting!");
00076   exit(1);
00077 }
00078 
00079 int main(int argc, char *argv[])
00080 {
00081   // Save terminal settings:
00082 
00083   struct termios savedTm;
00084   bool HasStdin = tcgetpgrp(STDIN_FILENO) == getpid() && tcgetattr(STDIN_FILENO, &savedTm) == 0;
00085 
00086   // Initiate locale:
00087 
00088   setlocale(LC_ALL, "");
00089 
00090   // Command line options:
00091 
00092 #define DEFAULTSVDRPPORT 2001
00093 #define DEFAULTWATCHDOG     0 // seconds
00094 #define DEFAULTPLUGINDIR "./PLUGINS/lib"
00095 
00096   int SVDRPport = DEFAULTSVDRPPORT;
00097   const char *AudioCommand = NULL;
00098   const char *ConfigDirectory = NULL;
00099   bool DisplayHelp = false;
00100   bool DisplayVersion = false;
00101   bool DaemonMode = false;
00102   int SysLogTarget = LOG_USER;
00103   bool MuteAudio = false;
00104   int WatchdogTimeout = DEFAULTWATCHDOG;
00105   const char *Terminal = NULL;
00106   const char *Shutdown = NULL;
00107   cPluginManager PluginManager(DEFAULTPLUGINDIR);
00108 
00109   static struct option long_options[] = {
00110       { "audio",    required_argument, NULL, 'a' },
00111       { "config",   required_argument, NULL, 'c' },
00112       { "daemon",   no_argument,       NULL, 'd' },
00113       { "device",   required_argument, NULL, 'D' },
00114       { "epgfile",  required_argument, NULL, 'E' },
00115       { "help",     no_argument,       NULL, 'h' },
00116       { "lib",      required_argument, NULL, 'L' },
00117       { "log",      required_argument, NULL, 'l' },
00118       { "mute",     no_argument,       NULL, 'm' },
00119       { "plugin",   required_argument, NULL, 'P' },
00120       { "port",     required_argument, NULL, 'p' },
00121       { "record",   required_argument, NULL, 'r' },
00122       { "shutdown", required_argument, NULL, 's' },
00123       { "terminal", required_argument, NULL, 't' },
00124       { "version",  no_argument,       NULL, 'V' },
00125       { "video",    required_argument, NULL, 'v' },
00126       { "watchdog", required_argument, NULL, 'w' },
00127       { NULL }
00128     };
00129 
00130   int c;
00131   while ((c = getopt_long(argc, argv, "a:c:dD:E:hl:L:mp:P:r:s:t:v:Vw:", long_options, NULL)) != -1) {
00132         switch (c) {
00133           case 'a': AudioCommand = optarg;
00134                     break;
00135           case 'c': ConfigDirectory = optarg;
00136                     break;
00137           case 'd': DaemonMode = true; break;
00138           case 'D': if (isnumber(optarg)) {
00139                        int n = atoi(optarg);
00140                        if (0 <= n && n < MAXDEVICES) {
00141                           cDevice::SetUseDevice(n);
00142                           break;
00143                           }
00144                        }
00145                     fprintf(stderr, "vdr: invalid DVB device number: %s\n", optarg);
00146                     return 2;
00147                     break;
00148           case 'E': cSIProcessor::SetEpgDataFileName(*optarg != '-' ? optarg : NULL);
00149                     break;
00150           case 'h': DisplayHelp = true;
00151                     break;
00152           case 'l': {
00153                       char *p = strchr(optarg, '.');
00154                       if (p)
00155                          *p = 0;
00156                       if (isnumber(optarg)) {
00157                          int l = atoi(optarg);
00158                          if (0 <= l && l <= 3) {
00159                             SysLogLevel = l;
00160                             if (!p)
00161                                break;
00162                             if (isnumber(p + 1)) {
00163                                int l = atoi(optarg);
00164                                if (0 <= l && l <= 7) {
00165                                   int targets[] = { LOG_LOCAL0, LOG_LOCAL1, LOG_LOCAL2, LOG_LOCAL3, LOG_LOCAL4, LOG_LOCAL5, LOG_LOCAL6, LOG_LOCAL7 };
00166                                   SysLogTarget = targets[l];
00167                                   break;
00168                                   }
00169                                }
00170                             }
00171                          }
00172                     if (p)
00173                        *p = '.';
00174                     fprintf(stderr, "vdr: invalid log level: %s\n", optarg);
00175                     return 2;
00176                     }
00177                     break;
00178           case 'L': if (access(optarg, R_OK | X_OK) == 0)
00179                        PluginManager.SetDirectory(optarg);
00180                     else {
00181                        fprintf(stderr, "vdr: can't access plugin directory: %s\n", optarg);
00182                        return 2;
00183                        }
00184                     break;
00185           case 'm': MuteAudio = true;
00186                     break;
00187           case 'p': if (isnumber(optarg))
00188                        SVDRPport = atoi(optarg);
00189                     else {
00190                        fprintf(stderr, "vdr: invalid port number: %s\n", optarg);
00191                        return 2;
00192                        }
00193                     break;
00194           case 'P': PluginManager.AddPlugin(optarg);
00195                     break;
00196           case 'r': cRecordingUserCommand::SetCommand(optarg);
00197                     break;
00198           case 's': Shutdown = optarg;
00199                     break;
00200           case 't': Terminal = optarg;
00201                     break;
00202           case 'V': DisplayVersion = true;
00203                     break;
00204           case 'v': VideoDirectory = optarg;
00205                     while (optarg && *optarg && optarg[strlen(optarg) - 1] == '/')
00206                           optarg[strlen(optarg) - 1] = 0;
00207                     break;
00208           case 'w': if (isnumber(optarg)) { int t = atoi(optarg);
00209                        if (t >= 0) {
00210                           WatchdogTimeout = t;
00211                           break;
00212                           }
00213                        }
00214                     fprintf(stderr, "vdr: invalid watchdog timeout: %s\n", optarg);
00215                     return 2;
00216                     break;
00217           default:  return 2;
00218           }
00219         }
00220 
00221   // Help and version info:
00222 
00223   if (DisplayHelp || DisplayVersion) {
00224      if (!PluginManager.HasPlugins())
00225         PluginManager.AddPlugin("*"); // adds all available plugins
00226      PluginManager.LoadPlugins();
00227      if (DisplayHelp) {
00228         printf("Usage: vdr [OPTIONS]\n\n"          // for easier orientation, this is column 80|
00229                "  -a CMD,   --audio=CMD    send Dolby Digital audio to stdin of command CMD\n"
00230                "  -c DIR,   --config=DIR   read config files from DIR (default is to read them\n"
00231                "                           from the video directory)\n"
00232                "  -d,       --daemon       run in daemon mode\n"
00233                "  -D NUM,   --device=NUM   use only the given DVB device (NUM = 0, 1, 2...)\n"
00234                "                           there may be several -D options (default: all DVB\n"
00235                "                           devices will be used)\n"
00236                "  -E FILE   --epgfile=FILE write the EPG data into the given FILE (default is\n"
00237                "                           %s); use '-E-' to disable this\n"
00238                "                           if FILE is a directory, the default EPG file will be\n"
00239                "                           created in that directory\n"
00240                "  -h,       --help         print this help and exit\n"
00241                "  -l LEVEL, --log=LEVEL    set log level (default: 3)\n"
00242                "                           0 = no logging, 1 = errors only,\n"
00243                "                           2 = errors and info, 3 = errors, info and debug\n"
00244                "                           if logging should be done to LOG_LOCALn instead of\n"
00245                "                           LOG_USER, add '.n' to LEVEL, as in 3.7 (n=0..7)\n"
00246                "  -L DIR,   --lib=DIR      search for plugins in DIR (default is %s)\n"
00247                "  -m,       --mute         mute audio of the primary DVB device at startup\n"
00248                "  -p PORT,  --port=PORT    use PORT for SVDRP (default: %d)\n"
00249                "                           0 turns off SVDRP\n"
00250                "  -P OPT,   --plugin=OPT   load a plugin defined by the given options\n"
00251                "  -r CMD,   --record=CMD   call CMD before and after a recording\n"
00252                "  -s CMD,   --shutdown=CMD call CMD to shutdown the computer\n"
00253                "  -t TTY,   --terminal=TTY controlling tty\n"
00254                "  -v DIR,   --video=DIR    use DIR as video directory (default: %s)\n"
00255                "  -V,       --version      print version information and exit\n"
00256                "  -w SEC,   --watchdog=SEC activate the watchdog timer with a timeout of SEC\n"
00257                "                           seconds (default: %d); '0' disables the watchdog\n"
00258                "\n",
00259                cSIProcessor::GetEpgDataFileName() ? cSIProcessor::GetEpgDataFileName() : "'-'",
00260                DEFAULTPLUGINDIR,
00261                DEFAULTSVDRPPORT,
00262                VideoDirectory,
00263                DEFAULTWATCHDOG
00264                );
00265         }
00266      if (DisplayVersion)
00267         printf("vdr (%s) - The Video Disk Recorder\n", VDRVERSION);
00268      if (PluginManager.HasPlugins()) {
00269         if (DisplayHelp)
00270            printf("Plugins: vdr -P\"name [OPTIONS]\"\n\n");
00271         for (int i = 0; ; i++) {
00272             cPlugin *p = PluginManager.GetPlugin(i);
00273             if (p) {
00274                const char *help = p->CommandLineHelp();
00275                printf("%s (%s) - %s\n", p->Name(), p->Version(), p->Description());
00276                if (DisplayHelp && help) {
00277                   printf("\n");
00278                   puts(help);
00279                   }
00280                }
00281             else
00282                break;
00283             }
00284         }
00285      return 0;
00286      }
00287 
00288   // Log file:
00289 
00290   if (SysLogLevel > 0)
00291      openlog("vdr", LOG_PID | LOG_CONS, SysLogTarget);
00292 
00293   // Check the video directory:
00294 
00295   if (!DirectoryOk(VideoDirectory, true)) {
00296      fprintf(stderr, "vdr: can't access video directory %s\n", VideoDirectory);
00297      return 2;
00298      }
00299 
00300   // Daemon mode:
00301 
00302   if (DaemonMode) {
00303 #if !defined(DEBUG_OSD)
00304      pid_t pid = fork();
00305      if (pid < 0) {
00306         fprintf(stderr, "%m\n");
00307         esyslog("ERROR: %m");
00308         return 2;
00309         }
00310      if (pid != 0)
00311         return 0; // initial program immediately returns
00312      fclose(stdin);
00313      fclose(stdout);
00314      fclose(stderr);
00315 #else
00316      fprintf(stderr, "vdr: can't run in daemon mode with DEBUG_OSD on!\n");
00317      return 2;
00318 #endif
00319      }
00320   else if (Terminal) {
00321      // Claim new controlling terminal
00322      stdin  = freopen(Terminal, "r", stdin);
00323      stdout = freopen(Terminal, "w", stdout);
00324      stderr = freopen(Terminal, "w", stderr);
00325      }
00326 
00327   isyslog("VDR version %s started", VDRVERSION);
00328 
00329   // Load plugins:
00330 
00331   if (!PluginManager.LoadPlugins(true))
00332      return 2;
00333 
00334   // Configuration data:
00335 
00336   if (!ConfigDirectory)
00337      ConfigDirectory = VideoDirectory;
00338 
00339   cPlugin::SetConfigDirectory(ConfigDirectory);
00340 
00341   Setup.Load(AddDirectory(ConfigDirectory, "setup.conf"));
00342   Sources.Load(AddDirectory(ConfigDirectory, "sources.conf"), true);
00343   Diseqcs.Load(AddDirectory(ConfigDirectory, "diseqc.conf"), true);
00344   Channels.Load(AddDirectory(ConfigDirectory, "channels.conf"));
00345   Timers.Load(AddDirectory(ConfigDirectory, "timers.conf"));
00346   Commands.Load(AddDirectory(ConfigDirectory, "commands.conf"), true);
00347   RecordingCommands.Load(AddDirectory(ConfigDirectory, "reccmds.conf"), true);
00348   SVDRPhosts.Load(AddDirectory(ConfigDirectory, "svdrphosts.conf"), true);
00349   CaDefinitions.Load(AddDirectory(ConfigDirectory, "ca.conf"), true);
00350   Keys.Load(AddDirectory(ConfigDirectory, "remote.conf"));
00351   KeyMacros.Load(AddDirectory(ConfigDirectory, "keymacros.conf"), true);
00352 
00353   // DVB interfaces:
00354 
00355   cDvbDevice::Initialize();
00356 
00357   cSIProcessor::Read();
00358 
00359   // Start plugins:
00360 
00361   if (!PluginManager.StartPlugins())
00362      return 2;
00363 
00364   // Primary device:
00365 
00366   cDevice::SetPrimaryDevice(Setup.PrimaryDVB);
00367   if (!cDevice::PrimaryDevice()) {
00368      const char *msg = "no primary device found - giving up!";
00369      fprintf(stderr, "vdr: %s\n", msg);
00370      esyslog("ERROR: %s", msg);
00371      return 2;
00372      }
00373 
00374   // OSD:
00375 
00376   cOsd::Initialize();
00377 
00378   // User interface:
00379 
00380   Interface = new cInterface(SVDRPport);
00381 
00382   // Remote Controls:
00383 #if defined(REMOTE_RCU)
00384   new cRcuRemote("/dev/ttyS1");
00385 #elif defined(REMOTE_LIRC)
00386   new cLircRemote("/dev/lircd");
00387 #endif
00388 #if defined(REMOTE_KBD)
00389   if (!DaemonMode && HasStdin)
00390      new cKbdRemote;
00391 #endif
00392   Interface->LearnKeys();
00393 
00394   // External audio:
00395 
00396   if (AudioCommand)
00397      new cExternalAudio(AudioCommand);
00398 
00399   // Channel:
00400 
00401   Channels.SwitchTo(Setup.CurrentChannel);
00402   if (MuteAudio)
00403      cDevice::PrimaryDevice()->ToggleMute();
00404   else
00405      cDevice::PrimaryDevice()->SetVolume(Setup.CurrentVolume, true);
00406 
00407   cEITScanner EITScanner;
00408 
00409   // Signal handlers:
00410 
00411   if (signal(SIGHUP,  SignalHandler) == SIG_IGN) signal(SIGHUP,  SIG_IGN);
00412   if (signal(SIGINT,  SignalHandler) == SIG_IGN) signal(SIGINT,  SIG_IGN);
00413   if (signal(SIGTERM, SignalHandler) == SIG_IGN) signal(SIGTERM, SIG_IGN);
00414   if (signal(SIGPIPE, SignalHandler) == SIG_IGN) signal(SIGPIPE, SIG_IGN);
00415   if (WatchdogTimeout > 0)
00416      if (signal(SIGALRM, Watchdog)   == SIG_IGN) signal(SIGALRM, SIG_IGN);
00417 
00418   // Main program loop:
00419 
00420   cOsdObject *Menu = NULL;
00421   cOsdObject *Temp = NULL;
00422   int LastChannel = -1;
00423   int PreviousChannel = cDevice::CurrentChannel();
00424   time_t LastActivity = 0;
00425   int MaxLatencyTime = 0;
00426   bool ForceShutdown = false;
00427   bool UserShutdown = false;
00428 
00429   if (WatchdogTimeout > 0) {
00430      dsyslog("setting watchdog timer to %d seconds", WatchdogTimeout);
00431      alarm(WatchdogTimeout); // Initial watchdog timer start
00432      }
00433 
00434   while (!Interrupted) {
00435         // Handle emergency exits:
00436         if (cThread::EmergencyExit()) {
00437            esyslog("emergency exit requested - shutting down");
00438            break;
00439            }
00440         // Attach launched player control:
00441         cControl::Attach();
00442         // Make sure Transfer-Mode is re-started after detaching a player:
00443         if (cDevice::PrimaryDevice()->PlayerDetached() && !cDevice::PrimaryDevice()->Replaying())
00444            Channels.SwitchTo(cDevice::CurrentChannel());
00445         // Restart the Watchdog timer:
00446         if (WatchdogTimeout > 0) {
00447            int LatencyTime = WatchdogTimeout - alarm(WatchdogTimeout);
00448            if (LatencyTime > MaxLatencyTime) {
00449               MaxLatencyTime = LatencyTime;
00450               dsyslog("max. latency time %d seconds", MaxLatencyTime);
00451               }
00452            }
00453         // Channel display:
00454         if (!EITScanner.Active() && cDevice::CurrentChannel() != LastChannel) {
00455            if (!Menu)
00456               Menu = Temp = new cDisplayChannel(cDevice::CurrentChannel(), LastChannel > 0);
00457            if (LastChannel > 0)
00458               PreviousChannel = LastChannel;
00459            LastChannel = cDevice::CurrentChannel();
00460            }
00461         // Timers and Recordings:
00462         if (!Menu) {
00463            time_t Now = time(NULL); // must do both following calls with the exact same time!
00464            cRecordControls::Process(Now);
00465            cTimer *Timer = Timers.GetMatch(Now);
00466            if (Timer) {
00467               if (!cRecordControls::Start(Timer))
00468                  Timer->SetPending(true);
00469               }
00470            }
00471         // User Input:
00472         cOsdObject *Interact = Menu ? Menu : cControl::Control();
00473         eKeys key = Interface->GetKey(!Interact || !Interact->NeedsFastResponse());
00474         if (NORMALKEY(key) != kNone) {
00475            EITScanner.Activity();
00476            LastActivity = time(NULL);
00477            }
00478         // Keys that must work independent of any interactive mode:
00479         switch (key) {
00480           // Menu control:
00481           case kMenu:
00482                if (Menu) {
00483                   DELETENULL(Menu);
00484                   if (!Temp)
00485                      break;
00486                   }
00487                if (cControl::Control())
00488                   cControl::Control()->Hide();
00489                Menu = new cMenuMain(cControl::Control());
00490                Temp = NULL;
00491                break;
00492           #define DirectMainFunction(function...)\
00493             DELETENULL(Menu);\
00494             if (cControl::Control())\
00495                cControl::Control()->Hide();\
00496             Menu = new cMenuMain(cControl::Control(), function);\
00497             Temp = NULL;
00498           case kSchedule:   DirectMainFunction(osSchedule); break;
00499           case kChannels:   DirectMainFunction(osChannels); break;
00500           case kTimers:     DirectMainFunction(osTimers); break;
00501           case kRecordings: DirectMainFunction(osRecordings); break;
00502           case kSetup:      DirectMainFunction(osSetup); break;
00503           case kCommands:   DirectMainFunction(osCommands); break;
00504           case kUser1 ... kUser9: cRemote::PutMacro(key); break;
00505           case k_Plugin:    DirectMainFunction(osPlugin, cRemote::GetPlugin()); break;
00506           // Channel up/down:
00507           case kChanUp|k_Repeat:
00508           case kChanUp:
00509           case kChanDn|k_Repeat:
00510           case kChanDn:
00511                cDevice::SwitchChannel(NORMALKEY(key) == kChanUp ? 1 : -1);
00512                break;
00513           // Volume Control:
00514           case kVolUp|k_Repeat:
00515           case kVolUp:
00516           case kVolDn|k_Repeat:
00517           case kVolDn:
00518           case kMute:
00519                if (key == kMute) {
00520                   if (!cDevice::PrimaryDevice()->ToggleMute() && !Menu)
00521                      break; // no need to display "mute off"
00522                   }
00523                else
00524                   cDevice::PrimaryDevice()->SetVolume(NORMALKEY(key) == kVolDn ? -VOLUMEDELTA : VOLUMEDELTA);
00525                if (!Interface->IsOpen())
00526                   Menu = Temp = cDisplayVolume::Create();
00527                cDisplayVolume::Process(key);
00528                break;
00529           // Power off:
00530           case kPower: isyslog("Power button pressed");
00531                        DELETENULL(Menu);
00532                        cControl::Shutdown();
00533                        Temp = NULL;
00534                        if (!Shutdown) {
00535                           Interface->Error(tr("Can't shutdown - option '-s' not given!"));
00536                           break;
00537                           }
00538                        if (cRecordControls::Active()) {
00539                           if (Interface->Confirm(tr("Recording - shut down anyway?")))
00540                              ForceShutdown = true;
00541                           }
00542                        LastActivity = 1; // not 0, see below!
00543                        UserShutdown = true;
00544                        break;
00545           default: break;
00546           }
00547         Interact = Menu ? Menu : cControl::Control(); // might have been closed in the mean time
00548         if (Interact) {
00549            eOSState state = Interact->ProcessKey(key);
00550            if (state == osUnknown && ISMODELESSKEY(key) && cControl::Control() && Interact != cControl::Control())
00551               state = cControl::Control()->ProcessKey(key);
00552            switch (state) {
00553              case osRecord: DELETENULL(Menu);
00554                             Temp = NULL;
00555                             if (cRecordControls::Start())
00556                                ;//XXX Interface->Info(tr("Recording"));
00557                             else
00558                                Interface->Error(tr("No free DVB device to record!"));
00559                             break;
00560              case osRecordings:
00561                             DELETENULL(Menu);
00562                             cControl::Shutdown();
00563                             Temp = NULL;
00564                             Menu = new cMenuMain(false, osRecordings);
00565                             break;
00566              case osReplay: DELETENULL(Menu);
00567                             cControl::Shutdown();
00568                             Temp = NULL;
00569                             cControl::Launch(new cReplayControl);
00570                             break;
00571              case osStopReplay:
00572                             DELETENULL(Menu);
00573                             cControl::Shutdown();
00574                             Temp = NULL;
00575                             break;
00576              case osSwitchDvb:
00577                             DELETENULL(Menu);
00578                             cControl::Shutdown();
00579                             Temp = NULL;
00580                             Interface->Info(tr("Switching primary DVB..."));
00581                             cDevice::SetPrimaryDevice(Setup.PrimaryDVB);
00582                             break;
00583              case osPlugin: DELETENULL(Menu);
00584                             Menu = Temp = cMenuMain::PluginOsdObject();
00585                             if (Menu)
00586                                Menu->Show();
00587                             break;
00588              case osBack:
00589              case osEnd:    if (Interact == Menu)
00590                                DELETENULL(Menu);
00591                             else
00592                                cControl::Shutdown();
00593                             Temp = NULL;
00594                             break;
00595              default:       ;
00596              }
00597            }
00598         else {
00599            // Key functions in "normal" viewing mode:
00600            switch (key) {
00601              // Toggle channels:
00602              case k0: {
00603                   int CurrentChannel = cDevice::CurrentChannel();
00604                   Channels.SwitchTo(PreviousChannel);
00605                   PreviousChannel = CurrentChannel;
00606                   break;
00607                   }
00608              // Direct Channel Select:
00609              case k1 ... k9:
00610                   Menu = new cDisplayChannel(key);
00611                   break;
00612              // Left/Right rotates trough channel groups:
00613              case kLeft|k_Repeat:
00614              case kLeft:
00615              case kRight|k_Repeat:
00616              case kRight:
00617                   Menu = new cDisplayChannel(NORMALKEY(key));
00618                   break;
00619              // Up/Down Channel Select:
00620              case kUp|k_Repeat:
00621              case kUp:
00622              case kDown|k_Repeat:
00623              case kDown:
00624                   cDevice::SwitchChannel(NORMALKEY(key) == kUp ? 1 : -1);
00625                   break;
00626              // Viewing Control:
00627              case kOk:   LastChannel = -1; break; // forces channel display
00628              // Instant recording:
00629              case kRecord:
00630                   if (cRecordControls::Start())
00631                      ;//XXX Interface->Info(tr("Recording"));
00632                   else
00633                      Interface->Error(tr("No free DVB device to record!"));
00634                   break;
00635              // Key macros:
00636              case kRed:
00637              case kGreen:
00638              case kYellow:
00639              case kBlue: cRemote::PutMacro(key); break;
00640              default:    break;
00641              }
00642            }
00643         if (!Menu) {
00644            EITScanner.Process();
00645            if (!cCutter::Active() && cCutter::Ended()) {
00646               if (cCutter::Error())
00647                  Interface->Error(tr("Editing process failed!"));
00648               else
00649                  Interface->Info(tr("Editing process finished"));
00650               }
00651            }
00652         if (!Interact && ((!cRecordControls::Active() && !cCutter::Active() && (!Interface->HasSVDRPConnection() || UserShutdown)) || ForceShutdown)) {
00653            time_t Now = time(NULL);
00654            if (Now - LastActivity > ACTIVITYTIMEOUT) {
00655               // Shutdown:
00656               if (Shutdown && (Setup.MinUserInactivity || LastActivity == 1) && Now - LastActivity > Setup.MinUserInactivity * 60) {
00657                  cTimer *timer = Timers.GetNextActiveTimer();
00658                  time_t Next  = timer ? timer->StartTime() : 0;
00659                  time_t Delta = timer ? Next - Now : 0;
00660                  if (!LastActivity) {
00661                     if (!timer || Delta > MANUALSTART) {
00662                        // Apparently the user started VDR manually
00663                        dsyslog("assuming manual start of VDR");
00664                        LastActivity = Now;
00665                        continue; // don't run into the actual shutdown procedure below
00666                        }
00667                     else
00668                        LastActivity = 1;
00669                     }
00670                  if (UserShutdown && Next && Delta <= Setup.MinEventTimeout * 60 && !ForceShutdown) {
00671                     char *buf;
00672                     asprintf(&buf, tr("Recording in %d minutes, shut down anyway?"), Delta / 60);
00673                     if (Interface->Confirm(buf))
00674                        ForceShutdown = true;
00675                     else
00676                        UserShutdown = false;
00677                     free(buf);
00678                     }
00679                  if (!Next || Delta > Setup.MinEventTimeout * 60 || ForceShutdown) {
00680                     ForceShutdown = false;
00681                     if (timer)
00682                        dsyslog("next timer event at %s", ctime(&Next));
00683                     if (WatchdogTimeout > 0)
00684                        signal(SIGALRM, SIG_IGN);
00685                     if (Interface->Confirm(tr("Press any key to cancel shutdown"), UserShutdown ? 5 : SHUTDOWNWAIT, true)) {
00686                        int Channel = timer ? timer->Channel()->Number() : 0;
00687                        const char *File = timer ? timer->File() : "";
00688                        char *cmd;
00689                        asprintf(&cmd, "%s %ld %ld %d \"%s\" %d", Shutdown, Next, Delta, Channel, strescape(File, "\"$"), UserShutdown);
00690                        isyslog("executing '%s'", cmd);
00691                        SystemExec(cmd);
00692                        free(cmd);
00693                        }
00694                     else if (WatchdogTimeout > 0) {
00695                        alarm(WatchdogTimeout);
00696                        if (signal(SIGALRM, Watchdog) == SIG_IGN)
00697                           signal(SIGALRM, SIG_IGN);
00698                        }
00699                     LastActivity = time(NULL); // don't try again too soon
00700                     UserShutdown = false;
00701                     continue; // skip the rest of the housekeeping for now
00702                     }
00703                  }
00704               // Disk housekeeping:
00705               RemoveDeletedRecordings();
00706               // Plugins housekeeping:
00707               PluginManager.Housekeeping();
00708               }
00709            }
00710         }
00711   if (Interrupted)
00712      isyslog("caught signal %d", Interrupted);
00713   cRecordControls::Shutdown();
00714   cCutter::Stop();
00715   delete Menu;
00716   cControl::Shutdown();
00717   delete Interface;
00718   cOsd::Shutdown();
00719   Remotes.Clear();
00720   Audios.Clear();
00721   Setup.CurrentChannel = cDevice::CurrentChannel();
00722   Setup.CurrentVolume  = cDevice::CurrentVolume();
00723   Setup.Save();
00724   cDevice::Shutdown();
00725   PluginManager.Shutdown(true);
00726   if (WatchdogTimeout > 0)
00727      dsyslog("max. latency time %d seconds", MaxLatencyTime);
00728   isyslog("exiting");
00729   if (SysLogLevel > 0)
00730      closelog();
00731   if (HasStdin)
00732      tcsetattr(STDIN_FILENO, TCSANOW, &savedTm);
00733   if (cThread::EmergencyExit()) {
00734      esyslog("emergency exit!");
00735      return 1;
00736      }
00737   return 0;
00738 }

Generated on Wed Feb 5 23:30:12 2003 for VDR by doxygen1.3-rc2