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