vdr 2.8.3
vdr.c
Go to the documentation of this file.
1/*
2 * vdr.c: Video Disk Recorder main program
3 *
4 * Copyright (C) 2000-2026 Klaus Schmidinger
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 * Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 *
21 * The author can be reached at vdr@tvdr.de
22 *
23 * The project's page is at https://www.tvdr.de
24 *
25 * $Id: vdr.c 5.32 2026/08/20 19:51:41 kls Exp $
26 */
27
28#include <getopt.h>
29#include <grp.h>
30#include <langinfo.h>
31#include <locale.h>
32#include <malloc.h>
33#include <pwd.h>
34#include <signal.h>
35#include <stdlib.h>
36#include <sys/capability.h>
37#include <sys/prctl.h>
38#ifdef SDNOTIFY
39#include <systemd/sd-daemon.h>
40#endif
41#include <termios.h>
42#include <unistd.h>
43#include "args.h"
44#include "audio.h"
45#include "channels.h"
46#include "config.h"
47#include "cutter.h"
48#include "device.h"
49#include "diseqc.h"
50#include "dvbdevice.h"
51#include "eitscan.h"
52#include "epg.h"
53#include "i18n.h"
54#include "interface.h"
55#include "keys.h"
56#include "libsi/si.h"
57#include "lirc.h"
58#include "menu.h"
59#include "osdbase.h"
60#include "pes2ts.h"
61#include "plugin.h"
62#include "recording.h"
63#include "shutdown.h"
64#include "skinclassic.h"
65#include "skinlcars.h"
66#include "skinsttng.h"
67#include "sourceparams.h"
68#include "sources.h"
69#include "status.h"
70#include "svdrp.h"
71#include "themes.h"
72#include "timers.h"
73#include "tools.h"
74#include "transfer.h"
75#include "videodir.h"
76
77#define MINCHANNELWAIT 10 // seconds to wait between failed channel switchings
78#define ACTIVITYTIMEOUT 60 // seconds before starting housekeeping
79#define MEMCLEANUPDELTA 3600 // seconds between memory cleanups
80#define SHUTDOWNWAIT 300 // seconds to wait in user prompt before automatic shutdown
81#define SHUTDOWNRETRY 360 // seconds before trying again to shut down
82#define SHUTDOWNFORCEPROMPT 5 // seconds to wait in user prompt to allow forcing shutdown
83#define SHUTDOWNCANCELPROMPT 5 // seconds to wait in user prompt to allow canceling shutdown
84#define RESTARTCANCELPROMPT 5 // seconds to wait in user prompt before restarting on SIGHUP
85#define MANUALSTART 600 // seconds the next timer must be in the future to assume manual start
86#define CHANNELSAVEDELTA 600 // seconds before saving channels.conf after automatic modifications
87#define DEVICEREADYTIMEOUT 30 // seconds to wait until all devices are ready
88#define MENUTIMEOUT 120 // seconds of user inactivity after which an OSD display is closed
89#define TIMERCHECKDELTA 5 // seconds between checks for timers that need to see their channel
90#define TIMERDEVICETIMEOUT 8 // seconds before a device used for timer check may be reused
91#define TIMERLOOKAHEADTIME 60 // seconds before a non-VPS timer starts and the channel is switched if possible
92#define VPSLOOKAHEADTIME 24 // hours within which VPS timers will make sure their events are up to date
93#define VPSUPTODATETIME 3600 // seconds before the event or schedule of a VPS timer needs to be refreshed
94
95#define EXIT(v) { ShutdownHandler.Exit(v); goto Exit; }
96
97static volatile sig_atomic_t LastSignal = 0;
98
99static bool SetUser(const char *User, bool UserDump)
100{
101 if (User) {
102 struct passwd *user = isnumber(User) ? getpwuid(atoi(User)) : getpwnam(User);
103 if (!user) {
104 fprintf(stderr, "vdr: unknown user: '%s'\n", User);
105 return false;
106 }
107 if (setgid(user->pw_gid) < 0) {
108 fprintf(stderr, "vdr: cannot set group id %u: %s\n", (unsigned int)user->pw_gid, strerror(errno));
109 return false;
110 }
111 if (initgroups(user->pw_name, user->pw_gid) < 0) {
112 fprintf(stderr, "vdr: cannot set supplemental group ids for user %s: %s\n", user->pw_name, strerror(errno));
113 return false;
114 }
115 if (setuid(user->pw_uid) < 0) {
116 fprintf(stderr, "vdr: cannot set user id %u: %s\n", (unsigned int)user->pw_uid, strerror(errno));
117 return false;
118 }
119 if (UserDump && prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0)
120 fprintf(stderr, "vdr: warning - cannot set dumpable: %s\n", strerror(errno));
121 setenv("HOME", user->pw_dir, 1);
122 setenv("USER", user->pw_name, 1);
123 setenv("LOGNAME", user->pw_name, 1);
124 setenv("SHELL", user->pw_shell, 1);
125 }
126 return true;
127}
128
129static bool DropCaps(void)
130{
131 // drop all capabilities except selected ones
132 cap_t caps_all = cap_get_proc();
133 if (!caps_all) {
134 fprintf(stderr, "vdr: cap_get_proc failed: %s\n", strerror(errno));
135 return false;
136 }
137 cap_flag_value_t cap_flag_value;
138 if (cap_get_flag(caps_all, CAP_SYS_TIME, CAP_PERMITTED , &cap_flag_value)) {
139 fprintf(stderr, "vdr: cap_get_flag failed: %s\n", strerror(errno));
140 return false;
141 }
142 cap_t caps;
143 if (cap_flag_value == CAP_SET)
144 caps = cap_from_text("= cap_sys_nice,cap_sys_time,cap_net_raw=ep");
145 else {
146 fprintf(stdout,"vdr: OS does not support cap_sys_time\n");
147 caps = cap_from_text("= cap_sys_nice,cap_net_raw=ep");
148 }
149 if (!caps) {
150 fprintf(stderr, "vdr: cap_from_text failed: %s\n", strerror(errno));
151 return false;
152 }
153 if (cap_set_proc(caps) == -1) {
154 fprintf(stderr, "vdr: cap_set_proc failed: %s\n", strerror(errno));
155 cap_free(caps);
156 return false;
157 }
158 cap_free(caps);
159 return true;
160}
161
162static bool SetKeepCaps(bool On)
163{
164 // set keeping capabilities during setuid() on/off
165 if (prctl(PR_SET_KEEPCAPS, On ? 1 : 0, 0, 0, 0) != 0) {
166 fprintf(stderr, "vdr: prctl failed\n");
167 return false;
168 }
169 return true;
170}
171
172static void SignalHandler(int signum)
173{
174 switch (signum) {
175 case SIGPIPE:
176 break;
177 case SIGHUP:
178 LastSignal = signum;
179 break;
180 default:
181 LastSignal = signum;
184 }
185 signal(signum, SignalHandler);
186}
187
188#define EXITWATCHDOG 40 // seconds
189
190static void Watchdog(int signum)
191{
192 // Something terrible must have happened that prevented the 'alarm()' from
193 // being called in time, so let's get out of here:
194 static volatile sig_atomic_t PanicLevel = 0;
195 switch (PanicLevel) { // can't use '++' here - deprecated in C++20 (P1152R4)
196 case 0: PanicLevel = 1;
197 signal(SIGALRM, Watchdog);
198 alarm(EXITWATCHDOG);
199 esyslog("PANIC: watchdog timer expired - exit()!");
200#ifdef SDNOTIFY
201 sd_notify(0, "STOPPING=1\nSTATUS=PANIC");
202#endif
203 exit(1); // let's try this nicely
204 break;
205 case 1: PanicLevel = 2;
206 signal(SIGALRM, Watchdog);
207 alarm(EXITWATCHDOG / 4);
208 esyslog("PANIC: watchdog timer expired - _exit()!");
209 // fall through
210 default: _exit(1); // no more mister nice guy
211 }
212}
213
214// --- cSpinUpDisk -----------------------------------------------------------
215
216class cSpinUpDisk : public cThread {
217private:
218 static time_t lastSpinUpDiskCheck;
220 virtual void Action(void) override { SpinUpDisk(cVideoDirectory::Name()); }
221 cSpinUpDisk(void): cThread("spin up disk") {}
222public:
223 static void Check(time_t Now);
224 };
225
228
229#define SPINUPDISK_TIME 60 // seconds between checks
230
231void cSpinUpDisk::Check(time_t Now)
232{
235 if (!spinUpDisk.Active()) {
236 int Delta = -1;
237 {
239 if (const cTimer *Timer = Timers->GetNextActiveTimer())
240 Delta = Timer->StartTime() - Now;
241 }
242 if (Delta > 0 && Delta <= 2 * SPINUPDISK_TIME) { // 2* to make sure we check at least SPINUPDISK_TIME before timer start
244 lastSpinUpDiskCheck += Delta; // to avoid double checks for the same timer start
245 }
246 }
247 }
248}
249
250// ---
251
252int main(int argc, char *argv[])
253{
254 // Save terminal settings:
255
256 struct termios savedTm;
257 bool HasStdin = (tcgetpgrp(STDIN_FILENO) == getpid() || getppid() != (pid_t)1) && tcgetattr(STDIN_FILENO, &savedTm) == 0;
258
259 // Initiate locale:
260
261 setlocale(LC_ALL, "");
262
263 // Command line options:
264
265#define dd(a, b) (*a ? a : b)
266#define DEFAULTSVDRPPORT 6419
267#define DEFAULTWATCHDOG 0 // seconds
268#define DEFAULTVIDEODIR VIDEODIR
269#define DEFAULTCONFDIR dd(CONFDIR, VideoDirectory)
270#define DEFAULTARGSDIR dd(ARGSDIR, "/etc/vdr/conf.d")
271#define DEFAULTCACHEDIR dd(CACHEDIR, VideoDirectory)
272#define DEFAULTRESDIR dd(RESDIR, ConfigDirectory)
273#define DEFAULTPLUGINDIR PLUGINDIR
274#define DEFAULTLOCDIR LOCDIR
275#define DEFAULTEPGDATAFILENAME "epg.data"
276
277 bool StartedAsRoot = false;
278 const char *VdrUser = NULL;
279 bool UserDump = false;
280 int SVDRPport = DEFAULTSVDRPPORT;
281 const char *AudioCommand = NULL;
282 const char *VideoDirectory = DEFAULTVIDEODIR;
283 const char *ConfigDirectory = NULL;
284 const char *CacheDirectory = NULL;
285 const char *ResourceDirectory = NULL;
286 const char *LocaleDirectory = DEFAULTLOCDIR;
287 const char *EpgDataFileName = DEFAULTEPGDATAFILENAME;
288 bool DisplayHelp = false;
289 bool DisplayVersion = false;
290 bool DaemonMode = false;
291 int SysLogTarget = LOG_USER;
292 bool MuteAudio = false;
293 int WatchdogTimeout = DEFAULTWATCHDOG;
294 const char *Terminal = NULL;
295 const char *OverrideCharacterTable = NULL;
296
297 bool UseKbd = true;
298 const char *LircDevice = NULL;
299#if !defined(REMOTE_KBD)
300 UseKbd = false;
301#endif
302#if defined(REMOTE_LIRC)
303 LircDevice = LIRC_DEVICE;
304#endif
305#if defined(VDR_USER)
306 VdrUser = VDR_USER;
307#endif
308#ifdef SDNOTIFY
309 time_t SdWatchdog = 0;
310 int SdWatchdogTimeout = 0;
311#endif
312
313 cArgs *Args = NULL;
314 if (argc == 1) {
315 Args = new cArgs(argv[0]);
316 if (Args->ReadDirectory(DEFAULTARGSDIR)) {
317 argc = Args->GetArgc();
318 argv = Args->GetArgv();
319 }
320 }
321
322 cVideoDirectory::SetName(VideoDirectory);
323 cPluginManager PluginManager(DEFAULTPLUGINDIR);
324
325 static struct option long_options[] = {
326 { "audio", required_argument, NULL, 'a' },
327 { "cachedir", required_argument, NULL, 'c' | 0x100 },
328 { "chartab", required_argument, NULL, 'c' | 0x200 },
329 { "config", required_argument, NULL, 'c' },
330 { "daemon", no_argument, NULL, 'd' },
331 { "device", required_argument, NULL, 'D' },
332 { "dirnames", required_argument, NULL, 'd' | 0x100 },
333 { "edit", required_argument, NULL, 'e' | 0x100 },
334 { "epgfile", required_argument, NULL, 'E' },
335 { "filesize", required_argument, NULL, 'f' | 0x100 },
336 { "genindex", required_argument, NULL, 'g' | 0x100 },
337 { "grab", required_argument, NULL, 'g' },
338 { "help", no_argument, NULL, 'h' },
339 { "instance", required_argument, NULL, 'i' },
340 { "lib", required_argument, NULL, 'L' },
341 { "lirc", optional_argument, NULL, 'l' | 0x100 },
342 { "localedir",required_argument, NULL, 'l' | 0x200 },
343 { "log", required_argument, NULL, 'l' },
344 { "mute", no_argument, NULL, 'm' },
345 { "no-kbd", no_argument, NULL, 'n' | 0x100 },
346 { "pes2ts", no_argument, NULL, 'p' | 0x100 },
347 { "plugin", required_argument, NULL, 'P' },
348 { "port", required_argument, NULL, 'p' },
349 { "record", required_argument, NULL, 'r' },
350 { "resdir", required_argument, NULL, 'r' | 0x100 },
351 { "showargs", optional_argument, NULL, 's' | 0x200 },
352 { "shutdown", required_argument, NULL, 's' },
353 { "split", no_argument, NULL, 's' | 0x100 },
354 { "terminal", required_argument, NULL, 't' },
355 { "updindex", required_argument, NULL, 'u' | 0x200 },
356 { "user", required_argument, NULL, 'u' },
357 { "userdump", no_argument, NULL, 'u' | 0x100 },
358 { "version", no_argument, NULL, 'V' },
359 { "vfat", no_argument, NULL, 'v' | 0x100 },
360 { "video", required_argument, NULL, 'v' },
361 { "watchdog", required_argument, NULL, 'w' },
362 { NULL, no_argument, NULL, 0 }
363 };
364
365 int c;
366 while ((c = getopt_long(argc, argv, "a:c:dD:e:E:g:hi:l:L:mp:P:r:s:t:u:v:Vw:", long_options, NULL)) != -1) {
367 switch (c) {
368 case 'a': AudioCommand = optarg;
369 break;
370 case 'c' | 0x100:
371 CacheDirectory = optarg;
372 break;
373 case 'c' | 0x200:
374 OverrideCharacterTable = optarg;
375 break;
376 case 'c': ConfigDirectory = optarg;
377 break;
378 case 'd': DaemonMode = true;
379 break;
380 case 'D': if (*optarg == '-') {
382 break;
383 }
384 if (isnumber(optarg)) {
385 int n = atoi(optarg);
386 if (0 <= n && n < MAXDEVICES) {
388 break;
389 }
390 }
391 fprintf(stderr, "vdr: invalid DVB device number: %s\n", optarg);
392 return 2;
393 case 'd' | 0x100: {
394 char *s = optarg;
395 if (*s != ',') {
396 int n = strtol(s, &s, 10);
397 if (n <= 0 || n >= PATH_MAX) { // PATH_MAX includes the terminating 0
398 fprintf(stderr, "vdr: invalid directory path length: %s\n", optarg);
399 return 2;
400 }
402 if (!*s)
403 break;
404 if (*s != ',') {
405 fprintf(stderr, "vdr: invalid delimiter: %s\n", optarg);
406 return 2;
407 }
408 }
409 s++;
410 if (!*s)
411 break;
412 if (*s != ',') {
413 int n = strtol(s, &s, 10);
414 if (n <= 0 || n > NAME_MAX) { // NAME_MAX excludes the terminating 0
415 fprintf(stderr, "vdr: invalid directory name length: %s\n", optarg);
416 return 2;
417 }
419 if (!*s)
420 break;
421 if (*s != ',') {
422 fprintf(stderr, "vdr: invalid delimiter: %s\n", optarg);
423 return 2;
424 }
425 }
426 s++;
427 if (!*s)
428 break;
429 int n = strtol(s, &s, 10);
430 if (n != 0 && n != 1) {
431 fprintf(stderr, "vdr: invalid directory encoding: %s\n", optarg);
432 return 2;
433 }
435 if (*s) {
436 fprintf(stderr, "vdr: unexpected data: %s\n", optarg);
437 return 2;
438 }
439 }
440 break;
441 case 'e' | 0x100:
442 return CutRecording(optarg) ? 0 : 2;
443 case 'E': EpgDataFileName = (*optarg != '-' ? optarg : NULL);
444 break;
445 case 'f' | 0x100:
451 break;
452 case 'g' | 0x100:
453 return GenerateIndex(optarg) ? 0 : 2;
454 case 'g': SetSVDRPGrabImageDir(*optarg != '-' ? optarg : NULL);
455 break;
456 case 'h': DisplayHelp = true;
457 break;
458 case 'i': if (isnumber(optarg)) {
459 InstanceId = atoi(optarg);
460 if (InstanceId >= 0)
461 break;
462 }
463 fprintf(stderr, "vdr: invalid instance id: %s\n", optarg);
464 return 2;
465 case 'l': {
466 char *p = strchr(optarg, '.');
467 if (p)
468 *p = 0;
469 if (isnumber(optarg)) {
470 int l = atoi(optarg);
471 if (0 <= l && l <= 3) {
472 SysLogLevel = l;
473 if (!p)
474 break;
475 *p = '.';
476 if (isnumber(p + 1)) {
477 int l = atoi(p + 1);
478 if (0 <= l && l <= 7) {
479 int targets[] = { LOG_LOCAL0, LOG_LOCAL1, LOG_LOCAL2, LOG_LOCAL3, LOG_LOCAL4, LOG_LOCAL5, LOG_LOCAL6, LOG_LOCAL7 };
480 SysLogTarget = targets[l];
481 break;
482 }
483 }
484 }
485 }
486 if (p)
487 *p = '.';
488 fprintf(stderr, "vdr: invalid log level: %s\n", optarg);
489 return 2;
490 }
491 case 'L': if (access(optarg, R_OK | X_OK) == 0)
492 PluginManager.SetDirectory(optarg);
493 else {
494 fprintf(stderr, "vdr: can't access plugin directory: %s\n", optarg);
495 return 2;
496 }
497 break;
498 case 'l' | 0x100:
499 LircDevice = optarg ? optarg : LIRC_DEVICE;
500 break;
501 case 'l' | 0x200:
502 if (access(optarg, R_OK | X_OK) == 0)
503 LocaleDirectory = optarg;
504 else {
505 fprintf(stderr, "vdr: can't access locale directory: %s\n", optarg);
506 return 2;
507 }
508 break;
509 case 'm': MuteAudio = true;
510 break;
511 case 'n' | 0x100:
512 UseKbd = false;
513 break;
514 case 'p': if (isnumber(optarg))
515 SVDRPport = atoi(optarg);
516 else {
517 fprintf(stderr, "vdr: invalid port number: %s\n", optarg);
518 return 2;
519 }
520 break;
521 case 'p' | 0x100:
522 if (argc - optind >= 2)
523 return Pes2Ts(argv[optind], argv[optind + 1]) ? 0 : 2;
524 else {
525 fprintf(stderr, "vdr: --pes2ts requires two arguments\n");
526 return 2;
527 }
528 break;
529 case 'P': PluginManager.AddPlugin(optarg);
530 break;
531 case 'r': cRecordingUserCommand::SetCommand(optarg);
532 break;
533 case 'r' | 0x100:
534 ResourceDirectory = optarg;
535 break;
536 case 's': ShutdownHandler.SetShutdownCommand(optarg);
537 break;
538 case 's' | 0x100:
540 break;
541 case 's' | 0x200: {
542 const char *ArgsDir = optarg ? optarg : DEFAULTARGSDIR;
543 cArgs Args(argv[0]);
544 if (!Args.ReadDirectory(ArgsDir)) {
545 fprintf(stderr, "vdr: can't read arguments from directory: %s\n", ArgsDir);
546 return 2;
547 }
548 int c = Args.GetArgc();
549 char **v = Args.GetArgv();
550 for (int i = 1; i < c; i++)
551 printf("%s\n", v[i]);
552 return 0;
553 }
554 case 't': Terminal = optarg;
555 if (access(Terminal, R_OK | W_OK) < 0) {
556 fprintf(stderr, "vdr: can't access terminal: %s\n", Terminal);
557 return 2;
558 }
559 break;
560 case 'u': if (*optarg)
561 VdrUser = optarg;
562 break;
563 case 'u' | 0x100:
564 UserDump = true;
565 break;
566 case 'u' | 0x200:
567 fprintf(stderr, "vdr: option '--updindex' is deprecated, using '--genindex' instead\n");
568 return GenerateIndex(optarg) ? 0 : 2;
569 case 'V': DisplayVersion = true;
570 break;
571 case 'v' | 0x100:
572 DirectoryPathMax = 250;
573 DirectoryNameMax = 40;
574 DirectoryEncoding = true;
575 break;
576 case 'v': VideoDirectory = optarg;
577 while (optarg && *optarg && optarg[strlen(optarg) - 1] == '/')
578 optarg[strlen(optarg) - 1] = 0;
579 cVideoDirectory::SetName(VideoDirectory);
580 break;
581 case 'w': if (isnumber(optarg)) {
582 int t = atoi(optarg);
583 if (t >= 0) {
584 WatchdogTimeout = t;
585 break;
586 }
587 }
588 fprintf(stderr, "vdr: invalid watchdog timeout: %s\n", optarg);
589 return 2;
590 default: return 2;
591 }
592 }
593
594 // Help and version info:
595
596 if (DisplayHelp || DisplayVersion) {
597 if (!PluginManager.HasPlugins())
598 PluginManager.AddPlugin("*"); // adds all available plugins
599 PluginManager.LoadPlugins();
600 if (DisplayHelp) {
601 printf("Usage: vdr [OPTIONS]\n\n" // for easier orientation, this is column 80|
602 " -a CMD, --audio=CMD send Dolby Digital audio to stdin of command CMD\n"
603 " --cachedir=DIR save cache files in DIR (default: %s)\n"
604 " --chartab=CHARACTER_TABLE\n"
605 " set the character table to use for strings in the\n"
606 " DVB data stream that don't begin with a character\n"
607 " table indicator, but don't use the standard default\n"
608 " character table (for instance ISO-8859-9)\n"
609 " -c DIR, --config=DIR read config files from DIR (default: %s)\n"
610 " -d, --daemon run in daemon mode\n"
611 " -D NUM, --device=NUM use only the given DVB device (NUM = 0, 1, 2...)\n"
612 " there may be several -D options (default: all DVB\n"
613 " devices will be used); if -D- is given, no DVB\n"
614 " devices will be used at all, independent of any\n"
615 " other -D options\n"
616 " --dirnames=PATH[,NAME[,ENC]]\n"
617 " set the maximum directory path length to PATH\n"
618 " (default: %d); if NAME is also given, it defines\n"
619 " the maximum directory name length (default: %d);\n"
620 " the optional ENC can be 0 or 1, and controls whether\n"
621 " special characters in directory names are encoded as\n"
622 " hex values (default: 0); if PATH or NAME are left\n"
623 " empty (as in \",,1\" to only set ENC), the defaults\n"
624 " apply\n"
625 " --edit=REC cut recording REC and exit\n"
626 " -E FILE, --epgfile=FILE write the EPG data into the given FILE (default is\n"
627 " '%s' in the cache directory)\n"
628 " '-E-' disables this\n"
629 " if FILE is a directory, the default EPG file will be\n"
630 " created in that directory\n"
631 " --filesize=SIZE limit video files to SIZE bytes (default is %dM)\n"
632 " only useful in conjunction with --edit\n"
633 " --genindex=REC generate index for recording REC and exit\n"
634 " -g DIR, --grab=DIR write images from the SVDRP command GRAB into the\n"
635 " given DIR; DIR must be the full path name of an\n"
636 " existing directory, without any \"..\", double '/'\n"
637 " or symlinks (default: none, same as -g-)\n"
638 " -h, --help print this help and exit\n"
639 " -i ID, --instance=ID use ID as the id of this VDR instance (default: 0)\n"
640 " -l LEVEL, --log=LEVEL set log level (default: 3)\n"
641 " 0 = no logging, 1 = errors only,\n"
642 " 2 = errors and info, 3 = errors, info and debug\n"
643 " if logging should be done to LOG_LOCALn instead of\n"
644 " LOG_USER, add '.n' to LEVEL, as in 3.7 (n=0..7)\n"
645 " -L DIR, --lib=DIR search for plugins in DIR (default is %s)\n"
646 " --lirc[=PATH] use a LIRC remote control device, attached to PATH\n"
647 " (default: %s)\n"
648 " --localedir=DIR search for locale files in DIR (default is\n"
649 " %s)\n"
650 " -m, --mute mute audio of the primary DVB device at startup\n"
651 " --no-kbd don't use the keyboard as an input device\n"
652 " --pes2ts convert a PES recording to TS\n"
653 " -p PORT, --port=PORT use PORT for SVDRP (default: %d)\n"
654 " 0 turns off SVDRP\n"
655 " -P OPT, --plugin=OPT load a plugin defined by the given options\n"
656 " -r CMD, --record=CMD call CMD before and after a recording, and after\n"
657 " a recording has been edited or deleted\n"
658 " --resdir=DIR read resource files from DIR (default: %s)\n"
659 " -s CMD, --shutdown=CMD call CMD to shutdown the computer\n"
660 " --split split edited files at the editing marks (only\n"
661 " useful in conjunction with --edit)\n"
662 " --showargs[=DIR] print the arguments read from DIR and exit\n"
663 " (default: %s)\n"
664 " -t TTY, --terminal=TTY controlling tty\n"
665 " -u USER, --user=USER run as user USER; only applicable if started as\n"
666 " root; USER can be a user name or a numerical id\n"
667 " --userdump allow coredumps if -u is given (debugging)\n"
668 " -v DIR, --video=DIR use DIR as video directory (default: %s)\n"
669 " -V, --version print version information and exit\n"
670 " --vfat for backwards compatibility (same as\n"
671 " --dirnames=250,40,1)\n"
672 " -w SEC, --watchdog=SEC activate the watchdog timer with a timeout of SEC\n"
673 " seconds (default: %d); '0' disables the watchdog\n"
674 "\n",
677 PATH_MAX - 1,
678 NAME_MAX,
682 LIRC_DEVICE,
689 );
690 }
691 if (DisplayVersion)
692 printf("vdr (%s/%s) - The Video Disk Recorder\n", VDRVERSION, APIVERSION);
693 if (PluginManager.HasPlugins()) {
694 if (DisplayHelp)
695 printf("Plugins: vdr -P\"name [OPTIONS]\"\n\n");
696 for (int i = 0; ; i++) {
697 cPlugin *p = PluginManager.GetPlugin(i);
698 if (p) {
699 const char *help = p->CommandLineHelp();
700 printf("%s (%s) - %s\n", p->Name(), p->Version(), p->Description());
701 if (DisplayHelp && help) {
702 printf("\n");
703 puts(help);
704 }
705 }
706 else
707 break;
708 }
709 }
710 return 0;
711 }
712
713 // Log file:
714
715 if (SysLogLevel > 0)
716 openlog("vdr", LOG_CONS, SysLogTarget); // LOG_PID doesn't work as expected under NPTL
717
718 // Daemon mode:
719
720 if (DaemonMode) {
721 if (daemon(1, 0) == -1) {
722 fprintf(stderr, "vdr: %m\n");
723 esyslog("ERROR: %m");
724 return 2;
725 }
726 }
727 else if (Terminal) {
728 // Claim new controlling terminal
729 stdin = freopen(Terminal, "r", stdin);
730 stdout = freopen(Terminal, "w", stdout);
731 stderr = freopen(Terminal, "w", stderr);
732 HasStdin = true;
733 tcgetattr(STDIN_FILENO, &savedTm);
734 }
735
736 // Set user id in case we were started as root:
737
738 if (VdrUser && geteuid() == 0) {
739 StartedAsRoot = true;
740 if (strcmp(VdrUser, "root") && strcmp(VdrUser, "0")) {
741 if (!SetKeepCaps(true))
742 return 2;
743 if (!SetUser(VdrUser, UserDump))
744 return 2;
745 if (!SetKeepCaps(false))
746 return 2;
747 if (!DropCaps())
748 return 2;
749 }
750 }
751
752 // Check the video directory:
753
754 if (!DirectoryOk(VideoDirectory, true)) {
755 fprintf(stderr, "vdr: can't access video directory %s\n", VideoDirectory);
756 return 2;
757 }
758
759 isyslog("VDR version %s started", VDRVERSION);
760 if (StartedAsRoot && VdrUser)
761 isyslog("switched to user '%s'", VdrUser);
762 if (DaemonMode)
763 dsyslog("running as daemon (tid=%d)", cThread::ThreadId());
765
766 // Set the system character table:
767
768 char *CodeSet = NULL;
769 if (setlocale(LC_CTYPE, ""))
770 CodeSet = nl_langinfo(CODESET);
771 else {
772 char *LangEnv = getenv("LANG"); // last resort in case locale stuff isn't installed
773 if (LangEnv) {
774 CodeSet = strchr(LangEnv, '.');
775 if (CodeSet)
776 CodeSet++; // skip the dot
777 }
778 }
779 if (CodeSet) {
780 bool known = SI::SetSystemCharacterTable(CodeSet);
781 isyslog("codeset is '%s' - %s", CodeSet, known ? "known" : "unknown");
783 }
784 if (OverrideCharacterTable) {
785 bool known = SI::SetOverrideCharacterTable(OverrideCharacterTable);
786 isyslog("override character table is '%s' - %s", OverrideCharacterTable, known ? "known" : "unknown");
787 }
788
789 // Initialize internationalization:
790
791 I18nInitialize(LocaleDirectory);
792
793 // Main program loop variables - need to be here to have them initialized before any EXIT():
794
795 cEpgDataReader EpgDataReader;
796 cOsdObject *Menu = NULL;
797 int LastChannel = 0;
798 int LastTimerChannel = -1;
799 int PreviousChannel[2] = { 1, 1 };
800 int PreviousChannelIndex = 0;
801 time_t LastChannelChanged = time(NULL);
802 time_t LastInteract = 0;
803 int MaxLatencyTime = 0;
804 bool IsInfoMenu = false;
805 cSkin *CurrentSkin = NULL;
806 int OldPrimaryDVB = 0;
807
808 // Load plugins:
809
810 if (!PluginManager.LoadPlugins(true))
811 EXIT(2);
812
813 // Directories:
814
815 if (!ConfigDirectory)
816 ConfigDirectory = DEFAULTCONFDIR;
817 cPlugin::SetConfigDirectory(ConfigDirectory);
818 if (!CacheDirectory)
819 CacheDirectory = DEFAULTCACHEDIR;
820 cPlugin::SetCacheDirectory(CacheDirectory);
821 if (!ResourceDirectory)
822 ResourceDirectory = DEFAULTRESDIR;
823 cPlugin::SetResourceDirectory(ResourceDirectory);
824 cThemes::SetThemesDirectory(AddDirectory(ConfigDirectory, "themes"));
825
826 // Configuration data:
827
828 Setup.Load(AddDirectory(ConfigDirectory, "setup.conf"));
829 Sources.Load(AddDirectory(ConfigDirectory, "sources.conf"), true, true);
830 Diseqcs.Load(AddDirectory(ConfigDirectory, "diseqc.conf"), true, Setup.DiSEqC);
831 Scrs.Load(AddDirectory(ConfigDirectory, "scr.conf"), true);
832 cChannels::Load(AddDirectory(ConfigDirectory, "channels.conf"), false, true);
833 cTimers::Load(AddDirectory(ConfigDirectory, "timers.conf"));
834 Commands.Load(AddDirectory(ConfigDirectory, "commands.conf"));
835 RecordingCommands.Load(AddDirectory(ConfigDirectory, "reccmds.conf"));
836 SVDRPhosts.Load(AddDirectory(ConfigDirectory, "svdrphosts.conf"), true);
837 Keys.Load(AddDirectory(ConfigDirectory, "remote.conf"));
838 KeyMacros.Load(AddDirectory(ConfigDirectory, "keymacros.conf"), true);
839 Folders.Load(AddDirectory(ConfigDirectory, "folders.conf"));
840 CamResponsesLoad(AddDirectory(ConfigDirectory, "camresponses.conf"), true);
841 DoneRecordingsPattern.Load(AddDirectory(CacheDirectory, "donerecs.data"));
842
844 const char *msg = "no fonts available - OSD will not show any text!";
845 fprintf(stderr, "vdr: %s\n", msg);
846 esyslog("ERROR: %s", msg);
847 }
848
849 // Recordings:
850
852
853 // EPG data:
854
855 if (EpgDataFileName) {
856 const char *EpgDirectory = NULL;
857 if (DirectoryOk(EpgDataFileName)) {
858 EpgDirectory = EpgDataFileName;
859 EpgDataFileName = DEFAULTEPGDATAFILENAME;
860 }
861 else if (*EpgDataFileName != '/' && *EpgDataFileName != '.')
862 EpgDirectory = CacheDirectory;
863 if (EpgDirectory)
864 cSchedules::SetEpgDataFileName(AddDirectory(EpgDirectory, EpgDataFileName));
865 else
866 cSchedules::SetEpgDataFileName(EpgDataFileName);
867 EpgDataReader.Start();
868 }
869
870 // DVB interfaces:
871
874
875 // Initialize plugins:
876
877 if (!PluginManager.InitializePlugins())
878 EXIT(2);
879
880 // Primary device:
881
883 if (!cDevice::PrimaryDevice() || !cDevice::PrimaryDevice()->HasDecoder()) {
884 if (cDevice::PrimaryDevice() && !cDevice::PrimaryDevice()->HasDecoder())
885 isyslog("device %d has no MPEG decoder", cDevice::PrimaryDevice()->DeviceNumber() + 1);
886 for (int i = 0; i < cDevice::NumDevices(); i++) {
888 if (d && d->HasDecoder()) {
889 isyslog("trying device number %d instead", i + 1);
890 if (cDevice::SetPrimaryDevice(i + 1)) {
891 Setup.PrimaryDVB = i + 1;
892 break;
893 }
894 }
895 }
896 if (!cDevice::PrimaryDevice()) {
897 const char *msg = "no primary device found - using first device!";
898 fprintf(stderr, "vdr: %s\n", msg);
899 esyslog("ERROR: %s", msg);
901 EXIT(2);
902 if (!cDevice::PrimaryDevice()) {
903 const char *msg = "no primary device found - giving up!";
904 fprintf(stderr, "vdr: %s\n", msg);
905 esyslog("ERROR: %s", msg);
906 EXIT(2);
907 }
908 }
909 }
910 OldPrimaryDVB = Setup.PrimaryDVB;
911
912 // Check for timers in automatic start time window:
913
915
916 // User interface:
917
918 Interface = new cInterface;
919
920 // Default skins:
921
922 new cSkinLCARS;
923 new cSkinSTTNG;
924 new cSkinClassic;
927 CurrentSkin = Skins.Current();
928
929 // Start plugins:
930
931 if (!PluginManager.StartPlugins())
932 EXIT(2);
933
934 // Set skin and theme in case they're implemented by a plugin:
935
936 if (!CurrentSkin || CurrentSkin == Skins.Current() && strcmp(Skins.Current()->Name(), Setup.OSDSkin) != 0) {
939 }
940
941 // Remote Controls:
942 if (LircDevice)
943 cLircRemote::NewLircRemote(LircDevice);
944 if (!DaemonMode && HasStdin && UseKbd)
945 new cKbdRemote;
947
948 // External audio:
949
950 if (AudioCommand)
951 new cExternalAudio(AudioCommand);
952
953 // Positioner:
954
955 if (!cPositioner::GetPositioner()) // no plugin has created a positioner
957
958 // CAM data:
959
960 ChannelCamRelations.Load(AddDirectory(CacheDirectory, "cam.data"));
961
962 // Channel:
963
965 dsyslog("not all devices ready after %d seconds", DEVICEREADYTIMEOUT);
967 dsyslog("not all CAM slots ready after %d seconds", DEVICEREADYTIMEOUT);
968 if (*Setup.InitialChannel) {
970 if (isnumber(Setup.InitialChannel)) { // for compatibility with old setup.conf files
971 if (const cChannel *Channel = Channels->GetByNumber(atoi(Setup.InitialChannel)))
972 Setup.InitialChannel = Channel->GetChannelID().ToString();
973 }
974 if (const cChannel *Channel = Channels->GetByChannelID(tChannelID::FromString(Setup.InitialChannel)))
975 Setup.CurrentChannel = Channel->Number();
976 }
977 if (Setup.InitialVolume >= 0)
979 {
981 Channels->SwitchTo(Setup.CurrentChannel);
982 }
983
984 // Restore volume:
985
987 if (MuteAudio)
989
990 // Signal handlers:
991
992 if (signal(SIGHUP, SignalHandler) == SIG_IGN) signal(SIGHUP, SIG_IGN);
993 if (signal(SIGINT, SignalHandler) == SIG_IGN) signal(SIGINT, SIG_IGN);
994 if (signal(SIGTERM, SignalHandler) == SIG_IGN) signal(SIGTERM, SIG_IGN);
995 if (signal(SIGPIPE, SignalHandler) == SIG_IGN) signal(SIGPIPE, SIG_IGN);
996 if (WatchdogTimeout > 0)
997 if (signal(SIGALRM, Watchdog) == SIG_IGN) signal(SIGALRM, SIG_IGN);
998
999 // Watchdog:
1000
1001 if (WatchdogTimeout > 0) {
1002 dsyslog("setting watchdog timer to %d seconds", WatchdogTimeout);
1003 alarm(WatchdogTimeout); // Initial watchdog timer start
1004 }
1005
1006#ifdef SDNOTIFY
1007 if (sd_watchdog_enabled(0, NULL) > 0) {
1008 uint64_t timeout;
1009 SdWatchdog = time(NULL);
1010 sd_watchdog_enabled(0, &timeout);
1011 SdWatchdogTimeout = (int)timeout/1000000;
1012 dsyslog("SD_WATCHDOG enabled with timeout set to %d seconds", SdWatchdogTimeout);
1013 }
1014
1015 // Startup notification:
1016
1017 sd_notify(0, "READY=1\nSTATUS=Ready");
1018#endif
1019
1020 // SVDRP:
1021
1022 SetSVDRPPorts(SVDRPport, DEFAULTSVDRPPORT);
1024
1025 // Main program loop:
1026
1027#define DELETE_MENU ((IsInfoMenu &= (Menu == NULL)), delete Menu, Menu = NULL)
1028
1029 while (!ShutdownHandler.DoExit()) {
1030#ifdef DEBUGRINGBUFFERS
1031 cRingBufferLinear::PrintDebugRBL();
1032#endif
1033 // Attach launched player control:
1035
1036 time_t Now = time(NULL);
1037
1038 // Make sure we have a visible programme in case device usage has changed:
1040 static time_t lastTime = 0;
1041 if (!cDevice::PrimaryDevice()->HasProgramme()) {
1042 if (!CamMenuActive() && Now - lastTime > MINCHANNELWAIT) { // !CamMenuActive() to avoid interfering with the CAM if a CAM menu is open
1044 const cChannel *Channel = Channels->GetByNumber(cDevice::CurrentChannel());
1045 if (Channel && (Channel->Vpid() || Channel->Apid(0) || Channel->Dpid(0))) {
1046 if (cDevice::GetDeviceForTransponder(Channel, LIVEPRIORITY) && Channels->SwitchTo(Channel->Number())) // try to switch to the original channel...
1047 ;
1048 else if (LastTimerChannel > 0) {
1049 Channel = Channels->GetByNumber(LastTimerChannel);
1050 if (Channel && cDevice::GetDeviceForTransponder(Channel, LIVEPRIORITY) && Channels->SwitchTo(LastTimerChannel)) // ...or the one used by the last timer
1051 ;
1052 }
1053 }
1054 lastTime = Now; // don't do this too often
1055 LastTimerChannel = -1;
1056 }
1057 }
1058 else
1059 lastTime = 0; // makes sure we immediately try again next time
1060 }
1061 // Update the OSD size:
1062 {
1063 static time_t lastOsdSizeUpdate = 0;
1064 if (Now != lastOsdSizeUpdate) { // once per second
1066 static int OsdState = 0;
1067 if (cOsdProvider::OsdSizeChanged(OsdState)) {
1068 if (cOsdMenu *OsdMenu = dynamic_cast<cOsdMenu *>(Menu))
1069 OsdMenu->Display();
1070 }
1071 lastOsdSizeUpdate = Now;
1072 }
1073 }
1074 // Restart the Watchdog timer:
1075 if (WatchdogTimeout > 0) {
1076 int LatencyTime = WatchdogTimeout - alarm(WatchdogTimeout);
1077 if (LatencyTime > MaxLatencyTime) {
1078 MaxLatencyTime = LatencyTime;
1079 dsyslog("max. latency time %d seconds", MaxLatencyTime);
1080 }
1081 }
1082#ifdef SDNOTIFY
1083 // Ping systemd watchdog when half the timeout is elapsed:
1084 if (SdWatchdogTimeout && (Now - SdWatchdog) * 2 > SdWatchdogTimeout) {
1085 sd_notify(0, "WATCHDOG=1");
1086 SdWatchdog = Now;
1087 dsyslog("SD_WATCHDOG ping");
1088 }
1089#endif
1090 // Handle channel and timer modifications:
1091 {
1092 // Channels and timers need to be stored in a consistent manner,
1093 // therefore if one of them is changed, we save both.
1094 static time_t ChannelSaveTimeout = 0;
1095 static cStateKey TimersStateKey(true);
1096 static cStateKey ChannelsStateKey(true);
1097 static int ChannelsModifiedByUser = 0;
1098 const cTimers *Timers = cTimers::GetTimersRead(TimersStateKey);
1099 const cChannels *Channels = cChannels::GetChannelsRead(ChannelsStateKey);
1100 if (ChannelSaveTimeout != 1) {
1101 if (Channels) {
1102 if (Channels->ModifiedByUser(ChannelsModifiedByUser))
1103 ChannelSaveTimeout = 1; // triggers an immediate save
1104 else if (!ChannelSaveTimeout)
1105 ChannelSaveTimeout = Now + CHANNELSAVEDELTA;
1106 }
1107 if (Timers)
1108 ChannelSaveTimeout = 1; // triggers an immediate save
1109 }
1110 if (ChannelSaveTimeout && Now > ChannelSaveTimeout && !cRecordControls::Active())
1111 ChannelSaveTimeout = 1; // triggers an immediate save
1112 if (Timers && Channels) {
1113 Channels->Save();
1114 Timers->Save();
1115 ChannelSaveTimeout = 0;
1116 }
1117 if (Channels) {
1118 for (const cChannel *Channel = Channels->First(); Channel; Channel = Channels->Next(Channel)) {
1119 if (Channel->Modification(CHANNELMOD_RETUNE)) {
1121 if (Channel->Number() == cDevice::CurrentChannel() && cDevice::PrimaryDevice()->HasDecoder()) {
1122 if (!cDevice::PrimaryDevice()->Replaying() || cDevice::PrimaryDevice()->Transferring()) {
1123 if (cDevice::ActualDevice()->ProvidesTransponder(Channel)) { // avoids retune on devices that don't really access the transponder
1124 isyslog("retuning due to modification of channel %d (%s)", Channel->Number(), Channel->Name());
1125 Channels->SwitchTo(Channel->Number());
1126 }
1127 }
1128 }
1130 }
1131 }
1132 }
1133 // State keys are removed in reverse order!
1134 if (Channels)
1135 ChannelsStateKey.Remove();
1136 if (Timers)
1137 TimersStateKey.Remove();
1138 if (ChannelSaveTimeout == 1) {
1139 // Only one of them was modified, so we reset the state keys to handle them both in the next turn:
1140 ChannelsStateKey.Reset();
1141 TimersStateKey.Reset();
1142 }
1143 }
1144 // Channel display:
1145 if (!EITScanner.Active() && cDevice::CurrentChannel() != LastChannel) {
1146 if (!Menu)
1147 Menu = new cDisplayChannel(cDevice::CurrentChannel(), LastChannel >= 0);
1148 LastChannel = cDevice::CurrentChannel();
1149 LastChannelChanged = Now;
1150 }
1151 if (Now - LastChannelChanged >= Setup.ZapTimeout && LastChannel != PreviousChannel[PreviousChannelIndex])
1152 PreviousChannel[PreviousChannelIndex ^= 1] = LastChannel;
1153 // Spin up disk:
1154 cSpinUpDisk::Check(Now);
1155 {
1156 // Timers and Recordings:
1157 static cStateKey TimersStateKey;
1158 cTimers *Timers = cTimers::GetTimersWrite(TimersStateKey);
1159 {
1160 LOCK_CHANNELS_READ; // Channels are needed for spawning pattern timers!
1161 // Assign events to timers:
1162 static cStateKey SchedulesStateKey;
1163 if (TimersStateKey.StateChanged())
1164 SchedulesStateKey.Reset(); // we assign events if either the Timers or the Schedules have changed
1165 bool TimersModified = false;
1166 if (const cSchedules *Schedules = cSchedules::GetSchedulesRead(SchedulesStateKey)) {
1167 Timers->SetSyncStateKey(StateKeySVDRPRemoteTimersPoll); // setting events shall not trigger a remote timer poll...
1168 if (Timers->AdjustSpawnedTimers()) { // must do this *before* SetEvents()!
1169 StateKeySVDRPRemoteTimersPoll.Reset(); // ...but adjusting spawned timers...
1170 TimersModified = true;
1171 }
1172 if (Timers->SetEvents(Schedules))
1173 TimersModified = true;
1174 if (Timers->SpawnPatternTimers(Schedules)) {
1175 StateKeySVDRPRemoteTimersPoll.Reset(); // ...or spawning new timers must!
1176 TimersModified = true;
1177 }
1178 SchedulesStateKey.Remove();
1179 }
1180 TimersStateKey.Remove(TimersModified); // we need to remove the key here, so that syncing StateKeySVDRPRemoteTimersPoll takes effect!
1181 }
1182 // Must do all following calls with the exact same time!
1183 // Process ongoing recordings:
1184 Timers = cTimers::GetTimersWrite(TimersStateKey);
1185 bool TimersModified = false;
1186 if (cRecordControls::Process(Timers, Now))
1187 TimersModified = true;
1188 // Start new recordings:
1189 if (cTimer *Timer = Timers->GetMatch(Now)) {
1190 if (!cRecordControls::Start(Timers, Timer))
1191 Timer->SetPending(true);
1192 else
1193 LastTimerChannel = Timer->Channel()->Number();
1194 TimersModified = true;
1195 }
1196 // Make sure timers "see" their channel early enough:
1197 static time_t LastTimerCheck = 0;
1198 if (Now - LastTimerCheck > TIMERCHECKDELTA) { // don't do this too often
1199 for (cTimer *Timer = Timers->First(); Timer; Timer = Timers->Next(Timer)) {
1200 if (Timer->Remote() || Timer->IsPatternTimer())
1201 continue;
1202 bool InVpsMargin = false;
1203 bool NeedsTransponder = false;
1204 if (Timer->HasFlags(tfActive) && !Timer->Recording()) {
1205 if (Timer->HasFlags(tfVps)) {
1206 if (Timer->Matches(Now, Setup.VpsMargin))
1207 InVpsMargin = true;
1208 else if (Timer->Event()) {
1210 InVpsMargin = Timer->Event()->StartTime() <= Now && Now < Timer->Event()->EndTime();
1211 NeedsTransponder = Timer->Event()->StartTime() - Now < VPSLOOKAHEADTIME * 3600 && !Timer->Event()->SeenWithin(VPSUPTODATETIME);
1212 }
1213 else {
1215 const cSchedule *Schedule = Schedules->GetSchedule(Timer->Channel());
1216 InVpsMargin = !Schedule; // we must make sure we have the schedule
1217 NeedsTransponder = Schedule && !Schedule->PresentSeenWithin(VPSUPTODATETIME);
1218 }
1219 }
1220 else
1221 NeedsTransponder = Timer->Matches(Now, TIMERLOOKAHEADTIME);
1222 }
1223 if (!Timer->Recording())
1224 Timer->SetInVpsMargin(InVpsMargin);
1225 if (NeedsTransponder || InVpsMargin) {
1226 // Find a device that provides the required transponder:
1227 cDevice *Device = cDevice::GetDeviceForTransponder(Timer->Channel(), MINPRIORITY);
1228 if (InVpsMargin) {
1229 if (!Device)
1230 Device = cDevice::GetDeviceForTransponder(Timer->Channel(), Timer->Priority() );
1231 if (!Device)
1232 Device = cDevice::GetDevice(Timer->Channel(), Timer->Priority(), false, false);
1233 }
1234 // Switch the device to the transponder:
1235 if (Device) {
1236 bool HadProgramme = cDevice::PrimaryDevice()->HasProgramme();
1237 if (!Device->IsTunedToTransponder(Timer->Channel())) {
1238 if (Device == cDevice::ActualDevice() && !Device->IsPrimaryDevice())
1239 cDevice::PrimaryDevice()->StopReplay(); // stop transfer mode
1240 dsyslog("switching device %d to channel %d %s (%s)", Device->DeviceNumber() + 1, Timer->Channel()->Number(), *Timer->Channel()->GetChannelID().ToString(), Timer->Channel()->Name());
1241 Device->SwitchChannel(Timer->Channel(), false);
1242 }
1243 Device->SetOccupied(TIMERDEVICETIMEOUT, InVpsMargin ? Timer->Priority() : MINPRIORITY, Now);
1244 if (cDevice::PrimaryDevice()->HasDecoder() && HadProgramme && !cDevice::PrimaryDevice()->HasProgramme()) {
1245 LastTimerChannel = Timer->Channel()->Number();
1246 Skins.QueueMessage(mtInfo, tr("Upcoming recording!")); // the previous SwitchChannel() has switched away the current live channel
1247 }
1248 }
1249 }
1250 }
1251 LastTimerCheck = Now;
1252 }
1253 // Delete expired timers:
1254 if (Timers->DeleteExpired(TimersModified))
1255 TimersModified = true;
1256 // Make sure there is enough free disk space for ongoing recordings:
1257 int MaxPriority = Timers->GetMaxPriority();
1258 if (MaxPriority >= 0)
1259 AssertFreeDiskSpace(MaxPriority);
1260 TimersStateKey.Remove(TimersModified);
1261 }
1262 // Recordings:
1263 if (!Menu) {
1266 }
1267 // CAM control:
1268 if (!Menu && !cOsd::IsOpen())
1269 Menu = CamControl();
1270 // Queued messages:
1272 // User Input:
1273 bool NeedsFastResponse = Menu && Menu->NeedsFastResponse();
1274 if (!NeedsFastResponse) {
1275 // Must limit the scope of ControlMutexLock here to not hold the lock during the call to Interface->GetKey().
1276 cMutexLock ControlMutexLock;
1277 cControl *Control = cControl::Control(ControlMutexLock);
1278 NeedsFastResponse = Control && Control->NeedsFastResponse();
1279 }
1280 eKeys key = Interface->GetKey(!NeedsFastResponse);
1281 cOsdObject *Interact = Menu;
1282 cMutexLock ControlMutexLock;
1283 cControl *Control = NULL;
1284 if (!Menu)
1285 Interact = Control = cControl::Control(ControlMutexLock);
1286 if (ISREALKEY(key)) {
1288 // Cancel shutdown countdown:
1291 // Set user active for MinUserInactivity time in the future:
1293 }
1294 // Keys that must work independent of any interactive mode:
1295 switch (int(key)) {
1296 // Menu control:
1297 case kMenu: {
1298 key = kNone; // nobody else needs to see this key
1299 bool WasOpen = Interact != NULL;
1300 bool WasMenu = Interact && Interact->IsMenu();
1301 if (Menu)
1303 else if (Control) {
1304 if (cOsd::IsOpen())
1305 Control->Hide();
1306 else
1307 WasOpen = false;
1308 }
1309 if (!WasOpen || !WasMenu && !Setup.MenuKeyCloses)
1310 Menu = new cMenuMain;
1311 }
1312 break;
1313 // Info:
1314 case kInfo: {
1315 if (IsInfoMenu) {
1316 key = kNone; // nobody else needs to see this key
1318 }
1319 else if (!Menu) {
1320 IsInfoMenu = true;
1321 if (Control) {
1322 Control->Hide();
1323 Menu = Control->GetInfo();
1324 if (Menu)
1325 Menu->Show();
1326 else
1327 IsInfoMenu = false;
1328 }
1329 else {
1330 cRemote::Put(kOk, true);
1331 cRemote::Put(kSchedule, true);
1332 }
1333 key = kNone; // nobody else needs to see this key
1334 }
1335 }
1336 break;
1337 // Direct main menu functions:
1338 #define DirectMainFunction(function...)\
1339 { DELETE_MENU;\
1340 if (Control)\
1341 Control->Hide();\
1342 Menu = new cMenuMain(function);\
1343 key = kNone; } // nobody else needs to see this key
1346 case kTimers: DirectMainFunction(osTimers); break;
1350 case kSetup: DirectMainFunction(osSetup); break;
1352 case kUser0 ... kUser9: cRemote::PutMacro(key); key = kNone; break;
1353 case k_Plugin: {
1354 const char *PluginName = cRemote::GetPlugin();
1355 if (PluginName) {
1357 if (Control)
1358 Control->Hide();
1359 cPlugin *plugin = cPluginManager::GetPlugin(PluginName);
1360 if (plugin) {
1361 Menu = plugin->MainMenuAction();
1362 if (Menu)
1363 Menu->Show();
1364 }
1365 else
1366 esyslog("ERROR: unknown plugin '%s'", PluginName);
1367 }
1368 key = kNone; // nobody else needs to see these keys
1369 }
1370 break;
1371 // Channel up/down:
1372 case kChanUp|k_Repeat:
1373 case kChanUp:
1374 case kChanDn|k_Repeat:
1375 case kChanDn:
1376 if (!Interact) {
1377 Menu = new cDisplayChannel(NORMALKEY(key));
1378 continue;
1379 }
1380 else if (cDisplayChannel::IsOpen() || Control) {
1381 Interact->ProcessKey(key);
1382 continue;
1383 }
1384 else if (!cDevice::PrimaryDevice()->Replaying() || cDevice::PrimaryDevice()->Transferring())
1385 cDevice::SwitchChannel(NORMALKEY(key) == kChanUp ? 1 : -1);
1386 break;
1387 // Volume control:
1388 case kVolUp|k_Repeat:
1389 case kVolUp:
1390 case kVolDn|k_Repeat:
1391 case kVolDn:
1392 case kMute:
1393 if (key == kMute) {
1394 if (!cDevice::PrimaryDevice()->ToggleMute() && !Menu) {
1395 key = kNone; // nobody else needs to see these keys
1396 break; // no need to display "mute off"
1397 }
1398 }
1399 else
1401 if (!Menu && !cOsd::IsOpen())
1402 Menu = cDisplayVolume::Create();
1404 key = kNone; // nobody else needs to see these keys
1405 break;
1406 // Audio track control:
1407 case kAudio:
1408 if (Control)
1409 Control->Hide();
1410 if (!cDisplayTracks::IsOpen()) {
1412 Menu = cDisplayTracks::Create();
1413 }
1414 else
1416 key = kNone;
1417 break;
1418 // Subtitle track control:
1419 case kSubtitles:
1420 if (Control)
1421 Control->Hide();
1425 }
1426 else
1428 key = kNone;
1429 break;
1430 // Pausing live video:
1431 case kPlayPause:
1432 case kPause:
1433 if (!cReplayControl::NowReplaying() && !Control) {
1435 if (Setup.PauseKeyHandling) {
1436 if (Setup.PauseKeyHandling > 1 || Interface->Confirm(tr("Pause live video?"))) {
1438 Skins.QueueMessage(mtError, tr("No free DVB device to record!"));
1439 }
1440 }
1441 key = kNone; // nobody else needs to see this key
1442 }
1443 break;
1444 // Instant recording:
1445 case kRecord:
1446 if (!cReplayControl::NowReplaying() && !Control) {
1448 if (Setup.RecordKeyHandling > 1 || Interface->Confirm(tr("Start recording?"))) {
1450 Skins.QueueMessage(mtInfo, tr("Recording started"));
1451 }
1452 }
1453 key = kNone; // nobody else needs to see this key
1454 }
1455 break;
1456 // Power off:
1457 case kPower:
1458 isyslog("Power button pressed");
1460 // Check for activity, request power button again if active:
1461 if (!ShutdownHandler.ConfirmShutdown(false) && Skins.Message(mtWarning, tr("VDR will shut down later - press Power to force"), SHUTDOWNFORCEPROMPT) != kPower) {
1462 // Not pressed power - set VDR to be non-interactive and power down later:
1464 break;
1465 }
1466 // No activity or power button pressed twice - ask for confirmation:
1467 if (!ShutdownHandler.ConfirmShutdown(true)) {
1468 // Non-confirmed background activity - set VDR to be non-interactive and power down later:
1470 break;
1471 }
1472 // Ask the final question:
1473 if (!Interface->Confirm(tr("Press any key to cancel shutdown"), SHUTDOWNCANCELPROMPT, true))
1474 // If final question was canceled, continue to be active:
1475 break;
1476 // Ok, now call the shutdown script:
1478 // Set VDR to be non-interactive and power down again later:
1480 // Do not attempt to automatically shut down for a while:
1482 break;
1483 default: break;
1484 }
1485 Interact = Menu ? Menu : Control; // might have been closed in the mean time
1486 if (Interact) {
1487 LastInteract = Now;
1488 eOSState state = Interact->ProcessKey(key);
1489 if (state == osUnknown && Interact != Control) {
1490 if (ISMODELESSKEY(key) && Control) {
1491 state = Control->ProcessKey(key);
1492 if (state == osEnd) {
1493 // let's not close a menu when replay ends:
1494 Control = NULL;
1496 continue;
1497 }
1498 }
1499 else if (Now - cRemote::LastActivity() > MENUTIMEOUT)
1500 state = osEnd;
1501 }
1502 switch (state) {
1503 case osPause: DELETE_MENU;
1505 Skins.QueueMessage(mtError, tr("No free DVB device to record!"));
1506 break;
1507 case osRecord: DELETE_MENU;
1509 Skins.QueueMessage(mtInfo, tr("Recording started"));
1510 break;
1511 case osRecordings:
1513 Control = NULL;
1515 Menu = new cMenuMain(osRecordings, true);
1516 break;
1517 case osReplay: DELETE_MENU;
1518 Control = NULL;
1521 break;
1522 case osStopReplay:
1524 Control = NULL;
1526 break;
1527 case osPlugin: DELETE_MENU;
1529 if (Menu)
1530 Menu->Show();
1531 break;
1532 case osBack:
1533 case osEnd: if (Interact == Menu)
1535 else {
1536 Control = NULL;
1538 }
1539 break;
1540 default: ;
1541 }
1542 }
1543 else {
1544 // Key functions in "normal" viewing mode:
1545 if (key != kNone && KeyMacros.Get(key)) {
1546 cRemote::PutMacro(key);
1547 key = kNone;
1548 }
1549 switch (int(key)) {
1550 // Toggle channels:
1551 case kChanPrev:
1552 case k0: {
1553 if (PreviousChannel[PreviousChannelIndex ^ 1] == LastChannel || LastChannel != PreviousChannel[0] && LastChannel != PreviousChannel[1])
1554 PreviousChannelIndex ^= 1;
1556 Channels->SwitchTo(PreviousChannel[PreviousChannelIndex ^= 1]);
1557 break;
1558 }
1559 // Direct Channel Select:
1560 case k1 ... k9:
1561 // Left/Right rotates through channel groups:
1562 case kLeft|k_Repeat:
1563 case kLeft:
1564 case kRight|k_Repeat:
1565 case kRight:
1566 // Previous/Next rotates through channel groups:
1567 case kPrev|k_Repeat:
1568 case kPrev:
1569 case kNext|k_Repeat:
1570 case kNext:
1571 // Up/Down Channel Select:
1572 case kUp|k_Repeat:
1573 case kUp:
1574 case kDown|k_Repeat:
1575 case kDown:
1576 Menu = new cDisplayChannel(NORMALKEY(key));
1577 break;
1578 // Viewing Control:
1579 case kOk: LastChannel = -1; break; // forces channel display
1580 // Instant resume of the last viewed recording:
1581 case kPlay:
1583 Control = NULL;
1586 }
1587 else
1588 DirectMainFunction(osRecordings); // no last viewed recording, so enter the Recordings menu
1589 break;
1590 default: break;
1591 }
1592 }
1593
1594 // Advance the EIT scanner:
1595 if (!Menu)
1597
1598 // Check if recordings handler has finished:
1599 bool Error = false;
1601 if (Error)
1602 Skins.QueueMessage(mtError, tr("Editing process failed!"));
1603 else
1604 Skins.QueueMessage(mtInfo, tr("Editing process finished"));
1605 }
1606
1607 // Change primary device:
1608 int NewPrimaryDVB = Setup.PrimaryDVB;
1609 if (NewPrimaryDVB != OldPrimaryDVB) {
1611 Control = NULL;
1613 Skins.QueueMessage(mtInfo, tr("Switching primary DVB..."));
1615 cDevice::SetPrimaryDevice(NewPrimaryDVB);
1616 OldPrimaryDVB = NewPrimaryDVB;
1617 }
1618
1619 // SIGHUP shall cause a restart:
1620 if (LastSignal == SIGHUP) {
1621 if (ShutdownHandler.ConfirmRestart(true) && Interface->Confirm(tr("Press any key to cancel restart"), RESTARTCANCELPROMPT, true))
1622 EXIT(1);
1623 LastSignal = 0;
1624 }
1625
1626 // Update the shutdown countdown:
1628 if (!ShutdownHandler.ConfirmShutdown(false))
1630 }
1631
1633 // Shutdown:
1634 // Check whether VDR will be ready for shutdown in SHUTDOWNWAIT seconds:
1635 time_t Soon = Now + SHUTDOWNWAIT;
1638 // Time to shut down - start final countdown:
1639 ShutdownHandler.countdown.Start(tr("VDR will shut down in %s minutes"), SHUTDOWNWAIT); // the placeholder is really %s!
1640 // Dont try to shut down again for a while:
1642 }
1643 // Countdown run down to 0?
1645 // Timed out, now do a final check:
1648 // Do this again a bit later:
1650 }
1651 // Handle housekeeping tasks
1652 if ((Now - LastInteract) > ACTIVITYTIMEOUT) {
1653 // Disk housekeeping:
1657 // Plugins housekeeping:
1658 PluginManager.Housekeeping();
1659 // Memory cleanup:
1660 static time_t LastMemoryCleanup = 0;
1661 if ((Now - LastMemoryCleanup) > MEMCLEANUPDELTA) {
1662 malloc_trim(0);
1663 LastMemoryCleanup = Now;
1664 }
1665 }
1666 }
1667
1669
1671
1672 // Main thread hooks of plugins:
1673 PluginManager.MainThreadHook();
1674 }
1675
1677 esyslog("emergency exit requested - shutting down");
1678
1679Exit:
1680
1681 // Reset all signal handlers to default before Interface gets deleted:
1682 signal(SIGHUP, SIG_DFL);
1683 signal(SIGINT, SIG_DFL);
1684 signal(SIGTERM, SIG_DFL);
1685 signal(SIGPIPE, SIG_DFL);
1686 signal(SIGALRM, SIG_DFL);
1687
1691 PluginManager.StopPlugins();
1693 delete Menu;
1695 delete Interface;
1697 Remotes.Clear();
1698 Audios.Clear();
1699 Skins.Clear();
1701 if (ShutdownHandler.GetExitCode() != 2) {
1704 Setup.Save();
1705 }
1710 cSchedules::Cleanup(true);
1713 PluginManager.Shutdown(true);
1715 if (WatchdogTimeout > 0)
1716 dsyslog("max. latency time %d seconds", MaxLatencyTime);
1717 if (LastSignal)
1718 isyslog("caught signal %d", LastSignal);
1720 esyslog("emergency exit!");
1721 isyslog("exiting, exit code %d", ShutdownHandler.GetExitCode());
1722 if (SysLogLevel > 0)
1723 closelog();
1724 if (HasStdin)
1725 tcsetattr(STDIN_FILENO, TCSANOW, &savedTm);
1726#ifdef SDNOTIFY
1727 if (ShutdownHandler.GetExitCode() == 2)
1728 sd_notify(0, "STOPPING=1\nSTATUS=Startup failed, exiting");
1729 else
1730 sd_notify(0, "STOPPING=1\nSTATUS=Exiting");
1731#endif
1733}
cAudios Audios
Definition audio.c:27
#define CHANNELMOD_RETUNE
Definition channels.h:29
#define LOCK_CHANNELS_READ
Definition channels.h:277
cChannelCamRelations ChannelCamRelations
Definition ci.c:2960
cCamSlots CamSlots
Definition ci.c:2851
cCiResourceHandlers CiResourceHandlers
Definition ci.c:1777
bool CamResponsesLoad(const char *FileName, bool AllowComments, bool MustExist)
Definition ci.c:481
Definition args.h:17
int GetArgc(void) const
Definition args.h:30
cArgs(const char *Argv0)
Definition args.c:15
char ** GetArgv(void) const
Definition args.h:31
bool ReadDirectory(const char *Directory)
Definition args.c:39
bool WaitForAllCamSlotsReady(int Timeout=0)
Waits until all CAM slots have become ready, or the given Timeout (seconds) has expired.
Definition ci.c:2863
void Load(const char *FileName)
Definition ci.c:3056
void Save(void)
Definition ci.c:3090
int Vpid(void) const
Definition channels.h:154
int Number(void) const
Definition channels.h:187
int Dpid(int i) const
Definition channels.h:161
int Apid(int i) const
Definition channels.h:160
bool ModifiedByUser(int &State) const
Returns true if the channels have been modified by the user since the last call to this function with...
Definition channels.c:1099
static const cChannels * GetChannelsRead(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of channels for read access.
Definition channels.c:856
bool SwitchTo(int Number) const
Definition channels.c:1063
static bool Load(const char *FileName, bool AllowComments=false, bool MustExist=false)
Definition channels.c:885
static void SetSystemCharacterTable(const char *CharacterTable)
Definition tools.c:1053
bool Save(void) const
Definition config.h:179
bool Load(const char *FileName=NULL, bool AllowComments=false, bool MustExist=false)
Definition config.h:132
static cControl * Control(cMutexLock &MutexLock, bool Hidden=false, bool *LockedOtherwise=NULL)
Returns the current replay control (if any) in case it is currently visible.
Definition player.c:75
static void Shutdown(void)
Definition player.c:111
virtual cOsdObject * GetInfo(void)
Returns an OSD object that displays information about the currently played programme.
Definition player.c:58
static void Attach(void)
Definition player.c:98
static void Launch(cControl *Control)
Definition player.c:91
virtual void Hide(void)=0
bool Update(void)
Update status display of the countdown.
Definition shutdown.c:64
void Start(const char *Message, int Seconds)
Start the 5 minute shutdown warning countdown.
Definition shutdown.c:37
void Cancel(void)
Cancel the 5 minute shutdown warning countdown.
Definition shutdown.c:46
bool Done(void)
Check if countdown timer has run out without canceling.
Definition shutdown.c:55
static bool WaitForAllDevicesReady(int Timeout=0)
Waits until all devices have become ready, or the given Timeout (seconds) has expired.
Definition device.c:134
static cDevice * ActualDevice(void)
Returns the actual receiving device in case of Transfer Mode, or the primary device otherwise.
Definition device.c:229
static cDevice * PrimaryDevice(void)
Returns the primary device.
Definition device.h:148
static void SetUseDevice(int n)
Sets the 'useDevice' flag of the given device.
Definition device.c:150
static cDevice * GetDevice(int Index)
Gets the device with the given Index.
Definition device.c:237
static void Shutdown(void)
Closes down all devices.
Definition device.c:474
bool SwitchChannel(const cChannel *Channel, bool LiveView)
Switches the device to the given Channel, initiating transfer mode if necessary.
Definition device.c:847
int DeviceNumber(void) const
Returns the number of this device (0 ... numDevices - 1).
Definition device.c:168
static int CurrentChannel(void)
Returns the number of the current channel on the primary device.
Definition device.h:371
bool IsPrimaryDevice(bool CheckDecoder=true) const
Definition device.h:223
static bool SetPrimaryDevice(int n)
Sets the primary device to 'n'.
Definition device.c:201
void StopReplay(void)
Stops the current replay session (if any).
Definition device.c:1499
void SetVolume(int Volume, bool Absolute=false)
Sets the volume to the given value, either absolutely or relative to the current volume.
Definition device.c:1108
static int NumDevices(void)
Returns the total number of devices.
Definition device.h:129
virtual bool HasDecoder(void) const
Tells whether this device has an MPEG decoder.
Definition device.c:219
virtual bool HasProgramme(void) const
Returns true if the device is currently showing any programme to the user, either through replaying o...
Definition device.c:1048
static int CurrentVolume(void)
Definition device.h:654
virtual bool IsTunedToTransponder(const cChannel *Channel) const
Returns true if this device is currently tuned to the given Channel's transponder.
Definition device.c:827
static cDevice * GetDeviceForTransponder(const cChannel *Channel, int Priority)
Returns a device that is not currently "occupied" and can be tuned to the transponder of the given Ch...
Definition device.c:434
void SetOccupied(int Seconds, int Priority=MINPRIORITY, time_t From=0)
Sets the occupied timeout for this device to the given number of Seconds, This can be used to tune a ...
Definition device.c:1023
bool ToggleMute(void)
Turns the volume off or on and returns the new mute state.
Definition device.c:1079
bool Load(const char *FileName, bool AllowComments=false, bool MustExist=false)
Definition diseqc.c:441
static bool IsOpen(void)
Definition menu.h:150
cDisplayChannel(int Number, bool Switched)
Definition menu.c:5045
static void Process(eKeys Key)
Definition menu.c:5585
static bool IsOpen(void)
Definition menu.h:197
static cDisplaySubtitleTracks * Create(void)
Definition menu.c:5574
static cDisplayTracks * Create(void)
Definition menu.c:5456
static void Process(eKeys Key)
Definition menu.c:5467
static bool IsOpen(void)
Definition menu.h:179
static cDisplayVolume * Create(void)
Definition menu.c:5366
static void Process(eKeys Key)
Definition menu.c:5373
bool Load(const char *FileName)
Definition recording.c:3468
static bool BondDevices(const char *Bondings)
Bonds the devices as defined in the given Bondings string.
Definition dvbdevice.c:2052
static bool useDvbDevices
Definition dvbdevice.h:175
static bool Initialize(void)
Initializes the DVB devices.
Definition dvbdevice.c:1989
bool Active(void)
Definition eitscan.h:34
void Process(void)
Definition eitscan.c:144
void Activity(void)
Definition eitscan.c:134
cExternalAudio(const char *Command)
Definition audio.c:55
static cString GetFontFileName(const char *FontName)
Returns the actual font file name for the given FontName.
Definition font.c:482
bool Confirm(const char *s, int Seconds=10, bool WaitForTimeout=false)
Definition interface.c:59
void Interrupt(void)
Definition interface.h:24
eKeys GetKey(bool Wait=true)
Definition interface.c:31
void LearnKeys(void)
Definition interface.c:147
const cKeyMacro * Get(eKeys Key)
Definition keys.c:269
static void NewLircRemote(const char *Name)
Definition lirc.c:65
virtual void Clear(void)
Definition tools.c:2305
void SetSyncStateKey(cStateKey &StateKey)
When making changes to this list (while holding a write lock) that shall not affect some other code t...
Definition tools.h:618
void Purge(bool Force=false)
Definition tools.c:2187
const T * First(void) const
Returns the first element in this list, or NULL if the list is empty.
Definition tools.h:662
const T * Next(const T *Object) const
< Returns the element immediately before Object in this list, or NULL if Object is the first element ...
Definition tools.h:669
cMenuMain(eOSState State=osUnknown, bool OpenSubMenus=false)
Definition menu.c:4744
static cOsdObject * PluginOsdObject(void)
Definition menu.c:4780
static void SetRecording(const char *FileName)
Definition menu.c:3314
bool Load(const char *FileName)
Definition config.c:235
virtual bool NeedsFastResponse(void)
Definition osdbase.h:91
virtual eOSState ProcessKey(eKeys Key)
Definition osdbase.h:94
bool IsMenu(void) const
Definition osdbase.h:92
virtual void Show(void)
Definition osdbase.c:70
static bool OsdSizeChanged(int &State)
Checks if the OSD size has changed and a currently displayed OSD needs to be redrawn.
Definition osd.c:2365
static void Shutdown(void)
Shuts down the OSD provider facility by deleting the current OSD provider.
Definition osd.c:2425
static void UpdateOsdSize(bool Force=false)
Inquires the actual size of the video display and adjusts the OSD and font sizes accordingly.
Definition osd.c:2338
static int IsOpen(void)
Returns true if there is currently a level 0 OSD open.
Definition osd.c:1975
void StopPlugins(void)
Definition plugin.c:507
void MainThreadHook(void)
Definition plugin.c:413
bool StartPlugins(void)
Definition plugin.c:383
void SetDirectory(const char *Directory)
Definition plugin.c:325
bool InitializePlugins(void)
Definition plugin.c:370
void AddPlugin(const char *Args)
Definition plugin.c:331
static bool HasPlugins(void)
Definition plugin.c:459
bool LoadPlugins(bool Log=false)
Definition plugin.c:361
void Shutdown(bool Log=false)
Definition plugin.c:519
void Housekeeping(void)
Definition plugin.c:397
static cPlugin * GetPlugin(int Index)
Definition plugin.c:464
virtual const char * CommandLineHelp(void)
Definition plugin.c:49
virtual const char * Version(void)=0
const char * Name(void)
Definition plugin.h:36
static void SetCacheDirectory(const char *Dir)
Definition plugin.c:150
virtual cOsdObject * MainMenuAction(void)
Definition plugin.c:96
static void SetConfigDirectory(const char *Dir)
Definition plugin.c:136
static void SetResourceDirectory(const char *Dir)
Definition plugin.c:164
virtual const char * Description(void)=0
static cPositioner * GetPositioner(void)
Returns a previously created positioner.
Definition positioner.c:133
static void DestroyPositioner(void)
Destroys a previously created positioner.
Definition positioner.c:138
static void ChannelDataModified(const cChannel *Channel)
Definition menu.c:5943
static bool Process(cTimers *Timers, time_t t)
Definition menu.c:5928
static bool PauseLiveVideo(void)
Definition menu.c:5880
static void Shutdown(void)
Definition menu.c:5969
static bool Start(cTimers *Timers, cTimer *Timer, bool Pause=false)
Definition menu.c:5784
static bool Active(void)
Definition menu.c:5960
static void SetCommand(const char *Command)
Definition recording.h:499
void DelAll(void)
Deletes/terminates all operations.
Definition recording.c:2363
bool Finished(bool &Error)
Returns true if all operations in the list have been finished.
Definition recording.c:2409
static void Update(bool Wait=false)
Triggers an update of the list of recordings, which will run as a separate thread if Wait is false.
Definition recording.c:1783
static bool NeedsUpdate(void)
Definition recording.c:1775
static const char * GetPlugin(void)
Returns the name of the plugin that was set with a previous call to PutMacro() or CallPlugin().
Definition remote.c:168
bool Put(uint64_t Code, bool Repeat=false, bool Release=false)
Definition remote.c:130
static bool PutMacro(eKeys Key)
Definition remote.c:116
static time_t LastActivity(void)
Absolute time when last key was delivered by Get().
Definition remote.h:71
static const char * LastReplayed(void)
Definition menu.c:6131
static void DelTimeshiftTimer(void)
Definition menu.c:6058
static const char * NowReplaying(void)
Definition menu.c:6126
bool PresentSeenWithin(int Seconds) const
Definition epg.h:173
static const cSchedules * GetSchedulesRead(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of schedules for read access.
Definition epg.c:1291
static void SetEpgDataFileName(const char *FileName)
Definition epg.c:1301
static void Cleanup(bool Force=false)
Definition epg.c:1308
bool Load(const char *FileName, bool AllowComments=false, bool MustExist=false)
Definition diseqc.c:184
int SplitEditedFiles
Definition config.h:356
int CurrentVolume
Definition config.h:376
int CurrentChannel
Definition config.h:375
bool Save(void)
Definition config.c:742
char OSDTheme[MaxThemeName]
Definition config.h:272
char OSDSkin[MaxSkinName]
Definition config.h:271
int VpsMargin
Definition config.h:323
int ZapTimeout
Definition config.h:312
int RecordKeyHandling
Definition config.h:318
int PauseKeyHandling
Definition config.h:319
bool Load(const char *FileName)
Definition config.c:546
int OpenRecMenuAtLastReplayed
Definition config.h:383
int MenuKeyCloses
Definition config.h:278
int DiSEqC
Definition config.h:285
char FontOsd[MAXFONTNAME]
Definition config.h:346
int MaxVideoFileSize
Definition config.h:355
cString DeviceBondings
Definition config.h:387
int PrimaryDVB
Definition config.h:273
cString InitialChannel
Definition config.h:386
int InitialVolume
Definition config.h:380
void CheckManualStart(int ManualStart)
Check whether the next timer is in ManualStart time window.
Definition shutdown.c:115
void SetShutdownCommand(const char *ShutdownCommand)
Set the command string for shutdown command.
Definition shutdown.c:132
bool ConfirmShutdown(bool Ask)
Check for background activity that blocks shutdown.
Definition shutdown.c:168
bool EmergencyExitRequested(void)
Returns true if an emergency exit was requested.
Definition shutdown.h:61
void SetRetry(int Seconds)
Set shutdown retry so that VDR will not try to automatically shut down within Seconds.
Definition shutdown.h:93
bool Retry(time_t AtTime=0)
Check whether its time to re-try the shutdown.
Definition shutdown.h:88
bool IsUserInactive(time_t AtTime=0)
Check whether VDR is in interactive mode or non-interactive mode (waiting for shutdown).
Definition shutdown.h:72
bool DoShutdown(bool Force)
Call the shutdown script with data of the next pending timer.
Definition shutdown.c:242
bool ConfirmRestart(bool Ask)
Check for background activity that blocks restart.
Definition shutdown.c:219
void Exit(int ExitCode)
Set VDR exit code and initiate end of VDR main loop.
Definition shutdown.h:54
void SetUserInactiveTimeout(int Seconds=-1, bool Force=false)
Set the time in the future when VDR will switch into non-interactive mode or power down.
Definition shutdown.c:152
bool DoExit(void)
Check if an exit code was set, and VDR should exit.
Definition shutdown.h:57
cCountdown countdown
Definition shutdown.h:51
void SetUserInactive(void)
Set VDR manually into non-interactive mode from now on.
Definition shutdown.h:86
int GetExitCode(void)
Get the currently set exit code of VDR.
Definition shutdown.h:59
Definition skins.h:405
cTheme * Theme(void)
Definition skins.h:425
const char * Name(void)
Definition skins.h:424
bool SetCurrent(const char *Name=NULL)
Sets the current skin to the one indicated by name.
Definition skins.c:269
eKeys Message(eMessageType Type, const char *s, int Seconds=0)
Displays the given message, either through a currently visible display object that is capable of doin...
Definition skins.c:288
cSkin * Current(void)
Returns a pointer to the current skin.
Definition skins.h:471
void ProcessQueuedMessages(void)
Processes the first queued message, if any.
Definition skins.c:390
virtual void Clear(void) override
Free up all registered skins.
Definition skins.c:446
int QueueMessage(eMessageType Type, const char *s, int Seconds=0, int Timeout=0)
Like Message(), but this function may be called from a background thread.
Definition skins.c:334
static time_t lastSpinUpDiskCheck
Definition vdr.c:218
static void Check(time_t Now)
Definition vdr.c:231
cSpinUpDisk(void)
Definition vdr.c:221
static cSpinUpDisk spinUpDisk
Definition vdr.c:219
virtual void Action(void) override
A derived cThread class must implement the code it wants to execute as a separate thread in this func...
Definition vdr.c:220
void Remove(bool IncState=true)
Removes this key from the lock it was previously used with.
Definition thread.c:904
void Reset(void)
Resets the state of this key, so that the next call to a lock's Lock() function with this key will re...
Definition thread.c:899
bool StateChanged(void)
Returns true if this key is used for obtaining a write lock, and the lock's state differs from that o...
Definition thread.c:914
static void MsgChannelChange(const cChannel *Channel)
Definition status.c:33
static void SetThemesDirectory(const char *ThemesDirectory)
Definition themes.c:257
bool Load(const char *SkinName)
Definition themes.c:209
static void SetMainThreadId(void)
Definition thread.c:412
void bool Start(void)
Sets the description of this thread, which will be used when logging starting or stopping of the thre...
Definition thread.c:330
cThread(const char *Description=NULL, bool LowPriority=false)
Creates a new thread.
Definition thread.c:264
bool Active(void)
Checks whether the thread is still alive.
Definition thread.c:355
static tThreadId ThreadId(void)
Definition thread.c:399
static bool Load(const char *FileName)
Definition timers.c:1200
int GetMaxPriority(void) const
Returns the maximum priority of all local timers that are currently recording.
Definition timers.c:1295
static cTimers * GetTimersWrite(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of timers for write access.
Definition timers.c:1323
static const cTimers * GetTimersRead(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of timers for read access.
Definition timers.c:1318
const cTimer * GetMatch(time_t t) const
Definition timers.c:1244
bool SpawnPatternTimers(const cSchedules *Schedules)
Definition timers.c:1367
bool DeleteExpired(bool Force)
Definition timers.c:1393
bool SetEvents(const cSchedules *Schedules)
Definition timers.c:1357
bool AdjustSpawnedTimers(void)
Definition timers.c:1379
static void Destroy(void)
Definition videodir.c:50
static const char * Name(void)
Definition videodir.c:60
static void SetName(const char *Name)
Definition videodir.c:65
cNestedItemList Commands
Definition config.c:276
cSetup Setup
Definition config.c:373
cSVDRPhosts SVDRPhosts
Definition config.c:281
cNestedItemList Folders
Definition config.c:275
cNestedItemList RecordingCommands
Definition config.c:277
#define MINPRIORITY
Definition config.h:42
#define VDRVERSION
Definition config.h:25
#define APIVERSION
Definition config.h:30
#define LIVEPRIORITY
Definition config.h:43
bool CutRecording(const char *FileName)
Definition cutter.c:797
#define MAXDEVICES
Definition device.h:29
#define VOLUMEDELTA
Definition device.h:33
cDiseqcs Diseqcs
Definition diseqc.c:439
cScrs Scrs
Definition diseqc.c:182
cEITScanner EITScanner
Definition eitscan.c:104
cEpgHandlers EpgHandlers
Definition epg.c:1457
void ReportEpgBugFixStats(bool Force)
Definition epg.c:629
#define LOCK_SCHEDULES_READ
Definition epg.h:232
void I18nInitialize(const char *LocaleDir)
Detects all available locales and loads the language names and codes.
Definition i18n.c:156
#define tr(s)
Definition i18n.h:85
cInterface * Interface
Definition interface.c:20
cKeyMacros KeyMacros
Definition keys.c:267
cKeys Keys
Definition keys.c:156
#define ISMODELESSKEY(k)
Definition keys.h:80
#define ISREALKEY(k)
Definition keys.h:81
#define NORMALKEY(k)
Definition keys.h:79
eKeys
Definition keys.h:16
@ kPower
Definition keys.h:39
@ kRecord
Definition keys.h:34
@ kSchedule
Definition keys.h:48
@ kUser9
Definition keys.h:54
@ kPlayPause
Definition keys.h:30
@ kCommands
Definition keys.h:53
@ kRight
Definition keys.h:23
@ kRecordings
Definition keys.h:51
@ kPause
Definition keys.h:32
@ k9
Definition keys.h:28
@ kSetup
Definition keys.h:52
@ kUp
Definition keys.h:17
@ kChanUp
Definition keys.h:40
@ kNone
Definition keys.h:55
@ kPlay
Definition keys.h:31
@ kChanPrev
Definition keys.h:42
@ kDown
Definition keys.h:18
@ k1
Definition keys.h:28
@ kSubtitles
Definition keys.h:47
@ kLeft
Definition keys.h:22
@ k_Plugin
Definition keys.h:58
@ kAudio
Definition keys.h:46
@ kMute
Definition keys.h:45
@ kPrev
Definition keys.h:38
@ k0
Definition keys.h:28
@ kChannels
Definition keys.h:49
@ kTimers
Definition keys.h:50
@ kMenu
Definition keys.h:19
@ k_Repeat
Definition keys.h:61
@ kChanDn
Definition keys.h:41
@ kVolDn
Definition keys.h:44
@ kNext
Definition keys.h:37
@ kOk
Definition keys.h:20
@ kVolUp
Definition keys.h:43
@ kInfo
Definition keys.h:29
@ kUser0
Definition keys.h:54
cOsdObject * CamControl(void)
Definition menu.c:2540
bool CamMenuActive(void)
Definition menu.c:2549
bool SetSystemCharacterTable(const char *CharacterTable)
Definition si.c:339
bool SetOverrideCharacterTable(const char *CharacterTable)
Definition si.c:324
eOSState
Definition osdbase.h:18
@ osRecordings
Definition osdbase.h:23
@ osPause
Definition osdbase.h:29
@ osPlugin
Definition osdbase.h:26
@ osChannels
Definition osdbase.h:21
@ osStopReplay
Definition osdbase.h:33
@ osRecord
Definition osdbase.h:30
@ osEnd
Definition osdbase.h:36
@ osSetup
Definition osdbase.h:27
@ osTimers
Definition osdbase.h:22
@ osReplay
Definition osdbase.h:31
@ osUnknown
Definition osdbase.h:18
@ osSchedule
Definition osdbase.h:20
@ osCommands
Definition osdbase.h:28
@ osBack
Definition osdbase.h:35
static bool Error(const char *Fmt,...) __attribute__((format(printf
Definition pes2ts.c:68
bool Pes2Ts(const char *PesFileName, const char *TsFileName)
Definition pes2ts.c:1164
int DirectoryNameMax
Definition recording.c:75
void AssertFreeDiskSpace(int Priority, bool Force)
The special Priority value -1 means that we shall get rid of any deleted recordings faster than norma...
Definition recording.c:152
int DirectoryPathMax
Definition recording.c:74
bool GenerateIndex(const char *FileName)
Generates the index of the existing recording with the given FileName.
Definition recording.c:3273
int InstanceId
Definition recording.c:77
bool DirectoryEncoding
Definition recording.c:76
cDoneRecordings DoneRecordingsPattern
Definition recording.c:3466
cRecordingsHandler RecordingsHandler
Definition recording.c:2268
void RemoveDeletedRecordings(void)
Definition recording.c:135
#define MAXVIDEOFILESIZEDEFAULT
Definition recording.h:514
#define MAXVIDEOFILESIZETS
Definition recording.h:511
#define MINVIDEOFILESIZE
Definition recording.h:513
cRemotes Remotes
Definition remote.c:217
cShutdownHandler ShutdownHandler
Definition shutdown.c:27
cSkins Skins
Definition skins.c:257
@ mtWarning
Definition skins.h:37
@ mtInfo
Definition skins.h:37
@ mtError
Definition skins.h:37
cSourceParams SourceParams
cSources Sources
Definition sources.c:114
static tChannelID FromString(const char *s)
Definition channels.c:23
void StopSVDRPHandler(void)
Definition svdrp.c:2879
void SetSVDRPGrabImageDir(const char *GrabImageDir)
Definition svdrp.c:2779
void StartSVDRPHandler(void)
Definition svdrp.c:2863
void SetSVDRPPorts(int TcpPort, int UdpPort)
Definition svdrp.c:2773
cStateKey StateKeySVDRPRemoteTimersPoll
Controls whether a change to the local list of timers needs to result in sending a POLL to the remote...
#define LOCK_TIMERS_READ
Definition timers.h:277
@ tfActive
Definition timers.h:19
@ tfVps
Definition timers.h:21
bool SpinUpDisk(const char *FileName)
Definition tools.c:728
int SysLogLevel
Definition tools.c:31
bool DirectoryOk(const char *DirName, bool LogErrors)
Definition tools.c:524
bool isnumber(const char *s)
Definition tools.c:402
cString AddDirectory(const char *DirName, const char *FileName)
Definition tools.c:445
cListGarbageCollector ListGarbageCollector
Definition tools.c:2164
int64_t StrToNum(const char *s)
Converts the given string to a number.
Definition tools.c:413
#define MEGABYTE(n)
Definition tools.h:45
#define dsyslog(a...)
Definition tools.h:37
#define esyslog(a...)
Definition tools.h:35
#define isyslog(a...)
Definition tools.h:36
static bool SetUser(const char *User, bool UserDump)
Definition vdr.c:99
#define SHUTDOWNFORCEPROMPT
Definition vdr.c:82
int main(int argc, char *argv[])
Definition vdr.c:252
#define DEFAULTRESDIR
#define DEFAULTWATCHDOG
#define DEFAULTARGSDIR
#define MEMCLEANUPDELTA
Definition vdr.c:79
#define MANUALSTART
Definition vdr.c:85
#define DEFAULTLOCDIR
#define TIMERLOOKAHEADTIME
Definition vdr.c:91
#define DEFAULTPLUGINDIR
#define CHANNELSAVEDELTA
Definition vdr.c:86
#define SHUTDOWNCANCELPROMPT
Definition vdr.c:83
#define SHUTDOWNWAIT
Definition vdr.c:80
#define DEFAULTEPGDATAFILENAME
static void SignalHandler(int signum)
Definition vdr.c:172
#define DEFAULTCONFDIR
static bool SetKeepCaps(bool On)
Definition vdr.c:162
#define DEFAULTVIDEODIR
#define VPSLOOKAHEADTIME
Definition vdr.c:92
#define MINCHANNELWAIT
Definition vdr.c:77
#define TIMERDEVICETIMEOUT
Definition vdr.c:90
static bool DropCaps(void)
Definition vdr.c:129
#define SPINUPDISK_TIME
Definition vdr.c:229
#define MENUTIMEOUT
Definition vdr.c:88
static void Watchdog(int signum)
Definition vdr.c:190
#define RESTARTCANCELPROMPT
Definition vdr.c:84
#define EXIT(v)
Definition vdr.c:95
#define DEFAULTCACHEDIR
#define DEVICEREADYTIMEOUT
Definition vdr.c:87
#define TIMERCHECKDELTA
Definition vdr.c:89
#define ACTIVITYTIMEOUT
Definition vdr.c:78
#define VPSUPTODATETIME
Definition vdr.c:93
#define DELETE_MENU
#define SHUTDOWNRETRY
Definition vdr.c:81
#define EXITWATCHDOG
Definition vdr.c:188
static volatile sig_atomic_t LastSignal
Definition vdr.c:97
#define DEFAULTSVDRPPORT
#define DirectMainFunction(function...)