]> git.vomp.tv Git - vompclient.git/blob - main.cc
Fix black background for 16:9 live TV on 4:3 screen
[vompclient.git] / main.cc
1 /*
2     Copyright 2004-2020 Chris Tallon
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP 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 VOMP.  If not, see <https://www.gnu.org/licenses/>.
18 */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <signal.h>
24
25 #include <thread>
26 #include <string>
27 #include <chrono>
28 #include <iomanip>
29
30 #ifndef WIN32
31   #include <unistd.h>
32   #include <endian.h>
33 #endif
34
35 #include "defines.h"
36
37 #ifdef HANDLE_VT_SWITCHING
38   #include <sys/ioctl.h>
39   #include <linux/vt.h>
40 #endif
41
42 #include "log.h"
43 #include "timers.h"
44 #include "vdr.h"
45 #include "boxstack.h"
46 #include "command.h"
47 #include "inputman.h"
48 #include "wol.h"
49 #include "vsleeptimer.h"
50
51 #ifdef VOMP_PLATTFORM_NMT
52   #include "lednmt.h"
53   #include "osddirectfb.h"
54   #include "audionmt.h"
55   #include "videonmt.h"
56 #endif
57
58 #ifdef VOMP_PLATFORM_RASPBERRY
59   #include "ledraspberry.h"
60   #include "osdopenvg.h"
61   #include "audioomx.h"
62   #include "videoomx.h"
63 #endif
64
65
66
67 #ifndef WIN32 // FIXME do we need any if WIN32 stuff in here? windows has own winmain file
68 void threadSignalReceiverFunction();
69 #endif
70
71 ULLONG htonll(ULLONG);
72 ULLONG ntohll(ULLONG);
73 void shutdown(int code);
74
75 // Global variables --------------------------------------------------------------------------------------------------
76 Log* logger;
77 InputMan* inputMan;
78 Led* led;
79 Osd* osd;
80 Timers* timers;
81 BoxStack* boxstack;
82 Command* command;
83 VDR* vdr;
84 Video* video;
85 Audio* audio;
86 Wol* wol;
87 Sleeptimer* sleeptimer;
88
89 #ifdef HANDLE_VT_SWITCHING
90 int fdtty;
91 struct vt_mode old_vtmode;
92 #endif
93
94 // Linux main function and sighandler
95 #ifndef WIN32
96 int main(int argc, char** argv)
97 {
98   bool daemonize = true;
99   bool debugEnabled = false;
100   bool crashed = false;
101   char* setServer = NULL;
102   int c;
103
104   while ((c = getopt(argc, argv, "cdns:")) != -1)
105   {
106     switch (c)
107     {
108       case 'c':
109         crashed = true;
110         break;
111       case 'd':
112         debugEnabled = true; // and...
113         [[fallthrough]];
114       case 'n':
115         daemonize = false;
116         break;
117       case 's':
118         setServer = optarg;
119         break;
120       case '?':
121         printf("Unknown option\n");
122         return 1;
123       default:
124         printf("Option error\n");
125         return 1;
126     }
127   }
128
129   // Init global vars ------------------------------------------------------------------------------------------------
130   logger     = new Log();
131   timers     = new Timers();
132   vdr        = new VDR();
133   inputMan   = new InputMan();
134
135   led        = new Led_TYPE();
136   osd        = new Osd_TYPE();
137   audio      = new Audio_TYPE();
138   video      = new Video_TYPE();
139
140   boxstack   = new BoxStack();
141   command    = new Command();
142   wol        = new Wol();
143   sleeptimer = new Sleeptimer();
144
145   if (!logger || !timers || !inputMan || !led || !osd || !video || !audio || !boxstack || !command || !wol || !sleeptimer)
146   {
147     printf("Could not create objects. Memory problems?\n");
148     shutdown(1);
149   }
150
151   // Get logging module started --------------------------------------------------------------------------------------
152
153   if (!logger->init(Log::DEBUG, "dummy", debugEnabled ? 1 : 0))
154   {
155     printf("Could not initialise log object. Aborting.\n");
156     shutdown(1);
157   }
158
159   logger->log("Core", Log::INFO, "Starting up...");
160
161   // Daemonize if not -d
162
163   if (daemonize)
164   {
165     // Fork away
166     pid_t forkTest = fork();
167     if (forkTest == -1)
168     { printf("Cannot fork (1).\n"); exit(1); }
169     if (forkTest != 0) _exit(0); // PID returned, I am the parent
170     // otherwise, I am the child
171     setsid();
172     forkTest = fork();
173     if (forkTest == -1)
174     { printf("Cannot fork (2).\n"); exit(1); }
175     if (forkTest != 0) _exit(0); // PID returned, I am the parent
176     // otherwise, I am the child
177     close(0);
178     close(1);
179     close(2);
180   }
181
182   // Set up signal handling ------------------------------------------------------------------------------------------
183
184   // Block all signals
185   sigset_t set;
186   sigfillset(&set);
187   int sigBlockResult = pthread_sigmask(SIG_SETMASK, &set, NULL);
188   if (sigBlockResult)
189   {
190     logger->log("Core", Log::EMERG, "Could not block signals: %i", sigBlockResult);
191     shutdown(1);
192   }
193
194   // Start signal receiver thread
195   std::thread threadSignalReceiver(threadSignalReceiverFunction);
196   threadSignalReceiver.detach();
197
198   logger->log("Core", Log::INFO, "Signal handlers set up successfully");
199
200   // VT Switching -----------------------------------------------------------------------------------------------
201
202 #ifdef HANDLE_VT_SWITCHING
203   if (
204
205
206     (fdtty = open("/dev/tty", O_WRONLY),0) == -1   // FIXME. Why the ,0 ? Surely this kills the log line below
207
208
209   )
210   {
211     logger->log("Core", Log::EMERG, "Could not open /dev/tty. Please change permissions");
212   }
213   else
214   {
215     int free_vt;
216     if (ioctl(fdtty, VT_OPENQRY, &free_vt) == -1 || free_vt == -1)
217     {
218       logger->log("Core", Log::EMERG, "Could not retrieve free virtual console, please change permissions");
219     }
220     else
221     {
222       ioctl(fdtty, VT_ACTIVATE, free_vt);
223       ioctl(fdtty, VT_WAITACTIVE, free_vt);
224       ioctl(fdtty, VT_LOCKSWITCH, 1);
225     }
226   }
227 #endif
228
229   // Init modules ----------------------------------------------------------------------------------------------------
230   int success;
231
232   success = inputMan->init();
233
234   if (success)
235   {
236     logger->log("Core", Log::INFO, "InputMan module initialised");
237   }
238   else
239   {
240     logger->log("Core", Log::EMERG, "InputMan module failed to initialise");
241     shutdown(1);
242   }
243
244   success = led->init(-1);
245   if (success)
246   {
247     logger->log("Core", Log::INFO, "LED module initialised");
248   }
249   else
250   {
251     logger->log("Core", Log::EMERG, "LED module failed to initialise");
252     shutdown(1);
253   }
254
255   success = timers->init();
256   if (success)
257   {
258     logger->log("Core", Log::INFO, "Timers module initialised");
259   }
260   else
261   {
262     logger->log("Core", Log::EMERG, "Timers module failed to initialise");
263     shutdown(1);
264   }
265
266   UCHAR videoFormat = Video::PAL; // PALNTSC FIXME
267
268   success = video->init(videoFormat);
269   if (success)
270   {
271     logger->log("Core", Log::INFO, "Video module initialised");
272   }
273   else
274   {
275     logger->log("Core", Log::EMERG, "Video module failed to initialise");
276     shutdown(1);
277   }
278
279   success = osd->init();
280   if (success)
281   {
282     logger->log("Core", Log::INFO, "OSD module initialised");
283   }
284   else
285   {
286     logger->log("Core", Log::EMERG, "OSD module failed to initialise");
287     shutdown(1);
288   }
289
290   success = audio->init(Audio::MPEG2_PES);
291   if (success)
292   {
293     logger->log("Core", Log::INFO, "Audio module initialised");
294   }
295   else
296   {
297     logger->log("Core", Log::EMERG, "Audio module failed to initialise");
298     shutdown(1);
299   }
300
301   success = vdr->init();
302   if (success)
303   {
304     logger->log("Core", Log::INFO, "VDR module initialised");
305   }
306   else
307   {
308     logger->log("Core", Log::EMERG, "VDR module failed to initialise");
309     shutdown(1);
310   }
311
312   success = boxstack->init();
313   if (success)
314   {
315     logger->log("Core", Log::INFO, "BoxStack module initialised");
316   }
317   else
318   {
319     logger->log("Core", Log::EMERG, "BoxStack module failed to initialise");
320     shutdown(1);
321   }
322
323   success = command->init(crashed, setServer);
324   if (success)
325   {
326     logger->log("Core", Log::INFO, "Command module initialised");
327   }
328   else
329   {
330     logger->log("Core", Log::EMERG, "Command module failed to initialise");
331     shutdown(1);
332   }
333
334   // Other init ------------------------------------------------------------------------------------------------------
335
336   logger->log("Core", Log::NOTICE, "Startup successful");
337
338   // Run main loop ---------------------------------------------------------------------------------------------------
339
340   // Ok, all major device components and other bits are loaded and ready
341   command->run();
342
343   // When that returns quit ------------------------------------------------------------------------------------------
344   shutdown(0);
345   return 0;
346 }
347
348 // -------------------------------------------------------------------------------------------------------------------
349
350 void threadSignalReceiverFunction()
351 {
352   int sig;
353   sigset_t set;
354   sigfillset(&set);
355   while(1)
356   {
357     if(sigwait(&set, &sig))
358     {
359       logger->log("Core", Log::CRIT, "Sigwait returned fail - signal handler exiting");
360       return;
361     }
362
363     logger->log("Core", Log::NOTICE, "Signal received: %i", sig);
364
365     if ((sig == SIGINT) || (sig == SIGTERM)) command->stop();
366   }
367 }
368
369 #endif
370
371 // -------------------------------------------------------------------------------------------------------------------
372
373 void shutdown(int code)
374 {
375   if (boxstack)
376   {
377     boxstack->shutdown();
378     delete boxstack;
379     logger->log("Core", Log::NOTICE, "BoxStack module shut down");
380   }
381
382   // FIXME, send a del all to boxstack first, then get rid of it after command?
383   if (command) // shut down command here in case views have posted messages
384   {
385     command->shutdown();
386     delete command;
387     command = NULL;
388     logger->log("Core", Log::NOTICE, "Command module shut down");
389   }
390
391   if (vdr)
392   {
393     vdr->shutdown();
394     delete vdr;
395     logger->log("Core", Log::NOTICE, "VDR module shut down");
396   }
397
398   if (osd)
399   {
400     osd->shutdown();
401     delete osd;
402     logger->log("Core", Log::NOTICE, "OSD module shut down");
403   }
404
405   if (audio)
406   {
407     audio->shutdown();
408     delete audio;
409     logger->log("Core", Log::NOTICE, "Audio module shut down");
410   }
411
412   if (video)
413   {
414     video->shutdown();
415     delete video;
416     logger->log("Core", Log::NOTICE, "Video module shut down");
417   }
418
419   if (timers)
420   {
421     timers->shutdown();
422     delete timers;
423     logger->log("Core", Log::NOTICE, "Timers module shut down");
424   }
425
426   if (led)
427   {
428     led->shutdown();
429     delete led;
430     logger->log("Core", Log::NOTICE, "LED module shut down");
431   }
432
433   if (inputMan)
434   {
435     inputMan->shutdown();
436     delete inputMan;
437     logger->log("Core", Log::NOTICE, "InputMan module shut down");
438   }
439
440   if (wol)
441   {
442     delete wol;
443     logger->log("Core", Log::NOTICE, "WOL module shut down");
444   }
445
446   if (sleeptimer)
447   {
448     delete sleeptimer;
449     logger->log("Core", Log::NOTICE, "Sleeptimer module shut down");
450   }
451
452 #ifdef HANDLE_VT_SWITCHING
453   ioctl(fdtty, VT_UNLOCKSWITCH, 1);
454   close(fdtty);
455 #endif
456
457   if (logger)
458   {
459     logger->log("Core", Log::NOTICE, "Log module shutting down... bye!\n\n");
460     logger->shutdown();
461     delete logger;
462   }
463
464   exit(code);
465 }
466
467 // -------------------------------------------------------------------------------------------------------------------
468
469 ULLONG htonll(ULLONG a)
470 {
471   #if BYTE_ORDER == BIG_ENDIAN
472     return a;
473   #else
474     ULLONG b = 0;
475
476     b = ((a << 56) & 0xFF00000000000000ULL)
477       | ((a << 40) & 0x00FF000000000000ULL)
478       | ((a << 24) & 0x0000FF0000000000ULL)
479       | ((a <<  8) & 0x000000FF00000000ULL)
480       | ((a >>  8) & 0x00000000FF000000ULL)
481       | ((a >> 24) & 0x0000000000FF0000ULL)
482       | ((a >> 40) & 0x000000000000FF00ULL)
483       | ((a >> 56) & 0x00000000000000FFULL) ;
484
485     return b;
486   #endif
487 }
488
489 ULLONG ntohll(ULLONG a)
490 {
491   return htonll(a);
492 }
493
494 void MILLISLEEP(ULONG a)
495 {
496 #ifndef WIN32
497   struct timespec delayTime;
498   delayTime.tv_sec = a / 1000;
499   delayTime.tv_nsec = (a % 1000) * 1000000;
500   nanosleep(&delayTime, NULL);
501 #else
502   Sleep(a);
503 #endif
504 }
505
506 long long getTimeMS()
507 {
508   struct timespec ts;
509   clock_gettime(VOMP_LINUX_CLOCK, &ts);
510   return ts.tv_sec * 1000 + ts.tv_nsec / 1000000LL;
511 }
512
513 int getClockRealTime(struct timespec *tp) // FIXME - del if all goes chrono
514 {
515   return clock_gettime(CLOCK_REALTIME, tp);
516 }
517
518 int min(UINT a, int b)
519 {
520   if (a > b) return b;
521   else return a;
522 }
523
524 int max(int a, int b)
525 {
526   if (a > b) return a;
527   else return b;
528 }
529
530 std::string tp2str(const std::chrono::time_point<std::chrono::system_clock>& tp)
531 {
532   auto tms = std::chrono::time_point_cast<std::chrono::milliseconds>(tp);
533   std::chrono::milliseconds e = tms.time_since_epoch();
534   long long c = e.count();
535   time_t tt = c / 1000;
536   int ttm = c % 1000;
537   auto stm = std::localtime(&tt);
538   std::stringstream ss;
539   ss << std::put_time(stm, "%T") << "." << std::setfill('0') << std::setw(3) << ttm;
540   return ss.str();
541 }