1 /*
2  *  Copyright (C) 2005-2018 Team Kodi
3  *  This file is part of Kodi - https://kodi.tv
4  *
5  *  SPDX-License-Identifier: GPL-2.0-or-later
6  *  See LICENSES/README.md for more information.
7  */
8 
9 #pragma once
10 
11 #include "XBApplicationEx.h"
12 
13 #include "guilib/IMsgTargetCallback.h"
14 #include "windowing/Resolution.h"
15 #include "utils/GlobalsHandling.h"
16 #include "messaging/IMessageTarget.h"
17 #include "ServiceManager.h"
18 #include "ApplicationStackHelper.h"
19 
20 #include <atomic>
21 #include <deque>
22 #include <map>
23 #include <memory>
24 #include <string>
25 #include <vector>
26 
27 #include "cores/IPlayerCallback.h"
28 #include "settings/lib/ISettingsHandler.h"
29 #include "settings/lib/ISettingCallback.h"
30 #include "settings/ISubSettings.h"
31 #if !defined(TARGET_WINDOWS) && defined(HAS_DVD_DRIVE)
32 #include "storage/DetectDVDType.h"
33 #endif
34 #ifdef TARGET_WINDOWS
35 #include "powermanagement/WinIdleTimer.h"
36 #endif
37 #include "utils/Stopwatch.h"
38 #include "windowing/OSScreenSaver.h"
39 #include "windowing/XBMC_events.h"
40 #include "threads/SystemClock.h"
41 #include "threads/Thread.h"
42 
43 #include "ApplicationPlayer.h"
44 
45 class CAction;
46 class CFileItem;
47 class CFileItemList;
48 class CKey;
49 class CSeekHandler;
50 class CInertialScrollingHandler;
51 class CSplash;
52 class CBookmark;
53 class IActionListener;
54 class CGUIComponent;
55 class CAppInboundProtocol;
56 class CSettingsComponent;
57 
58 namespace ADDON
59 {
60   class CSkinInfo;
61   class IAddon;
62   typedef std::shared_ptr<IAddon> AddonPtr;
63 }
64 
65 namespace ANNOUNCEMENT
66 {
67   class CAnnouncementManager;
68 }
69 
70 namespace MEDIA_DETECT
71 {
72   class CAutorun;
73 }
74 
75 namespace PLAYLIST
76 {
77   class CPlayList;
78 }
79 
80 namespace ActiveAE
81 {
82   class CActiveAE;
83 }
84 
85 namespace VIDEO
86 {
87   class CVideoInfoScanner;
88 }
89 
90 namespace MUSIC_INFO
91 {
92   class CMusicInfoScanner;
93 }
94 
95 #define VOLUME_MINIMUM 0.0f        // -60dB
96 #define VOLUME_MAXIMUM 1.0f        // 0dB
97 #define VOLUME_DYNAMIC_RANGE 90.0f // 60dB
98 
99 // replay gain settings struct for quick access by the player multiple
100 // times per second (saves doing settings lookup)
101 struct ReplayGainSettings
102 {
103   int iPreAmp;
104   int iNoGainPreAmp;
105   int iType;
106   bool bAvoidClipping;
107 };
108 
109 enum StartupAction
110 {
111   STARTUP_ACTION_NONE = 0,
112   STARTUP_ACTION_PLAY_TV,
113   STARTUP_ACTION_PLAY_RADIO
114 };
115 
116 class CApplication : public CXBApplicationEx, public IPlayerCallback, public IMsgTargetCallback,
117                      public ISettingCallback, public ISettingsHandler, public ISubSettings,
118                      public KODI::MESSAGING::IMessageTarget
119 {
120 friend class CAppInboundProtocol;
121 
122 public:
123 
124   // If playback time of current item is greater than this value, ACTION_PREV_ITEM will seek to start
125   // of currently playing item, otherwise it will seek to start of the previous item in playlist
126   static const unsigned int ACTION_PREV_ITEM_THRESHOLD = 3; // seconds;
127 
128   enum ESERVERS
129   {
130     ES_WEBSERVER = 1,
131     ES_AIRPLAYSERVER,
132     ES_JSONRPCSERVER,
133     ES_UPNPRENDERER,
134     ES_UPNPSERVER,
135     ES_EVENTSERVER,
136     ES_ZEROCONF
137   };
138 
139   CApplication(void);
140   ~CApplication(void) override;
141   bool Initialize() override;
142   void FrameMove(bool processEvents, bool processGUI = true) override;
143   void Render() override;
144   virtual void Preflight();
145   bool Create(const CAppParamParser &params);
146   bool Cleanup() override;
147 
IsInitialized()148   bool IsInitialized() const { return !m_bInitializing; }
IsStopping()149   bool IsStopping() const { return m_bStop; }
150 
151   bool CreateGUI();
152   bool InitWindow(RESOLUTION res = RES_INVALID);
153   void StartServices();
154   void StopServices();
155 
156   bool StartServer(enum ESERVERS eServer, bool bStart, bool bWait = false);
157 
158   bool IsCurrentThread() const;
159   void Stop(int exitCode);
160   void UnloadSkin();
161   bool LoadCustomWindows();
162   void ReloadSkin(bool confirm = false);
163   const std::string& CurrentFile();
164   CFileItem& CurrentFileItem();
165   std::shared_ptr<CFileItem> CurrentFileItemPtr();
166   CFileItem& CurrentUnstackedItem();
167   bool OnMessage(CGUIMessage& message) override;
168   CApplicationPlayer& GetAppPlayer();
169   std::string GetCurrentPlayer();
170   CApplicationStackHelper& GetAppStackHelper();
171   void OnPlayBackEnded() override;
172   void OnPlayBackStarted(const CFileItem &file) override;
173   void OnPlayerCloseFile(const CFileItem &file, const CBookmark &bookmark) override;
174   void OnPlayBackPaused() override;
175   void OnPlayBackResumed() override;
176   void OnPlayBackStopped() override;
177   void OnPlayBackError() override;
178   void OnQueueNextItem() override;
179   void OnPlayBackSeek(int64_t iTime, int64_t seekOffset) override;
180   void OnPlayBackSeekChapter(int iChapter) override;
181   void OnPlayBackSpeedChanged(int iSpeed) override;
182   void OnAVChange() override;
183   void OnAVStarted(const CFileItem &file) override;
184   void RequestVideoSettings(const CFileItem &fileItem) override;
185   void StoreVideoSettings(const CFileItem &fileItem, CVideoSettings vs) override;
186 
187   int  GetMessageMask() override;
188   void OnApplicationMessage(KODI::MESSAGING::ThreadMessage* pMsg) override;
189 
190   bool PlayMedia(CFileItem& item, const std::string &player, int iPlaylist);
191   bool ProcessAndStartPlaylist(const std::string& strPlayList, PLAYLIST::CPlayList& playlist, int iPlaylist, int track=0);
192   bool PlayFile(CFileItem item, const std::string& player, bool bRestart = false);
193   void StopPlaying();
194   void Restart(bool bSamePosition = true);
195   void DelayedPlayerRestart();
196   void CheckDelayedPlayerRestart();
197   bool IsPlayingFullScreenVideo() const;
198   bool IsFullScreen();
199   bool OnAction(const CAction &action);
200   void CheckShutdown();
201   void InhibitIdleShutdown(bool inhibit);
202   bool IsIdleShutdownInhibited() const;
203   void InhibitScreenSaver(bool inhibit);
204   bool IsScreenSaverInhibited() const;
205   // Checks whether the screensaver and / or DPMS should become active.
206   void CheckScreenSaverAndDPMS();
207   void ActivateScreenSaver(bool forceType = false);
208   void CloseNetworkShares();
209 
210   void ConfigureAndEnableAddons();
211   void ShowAppMigrationMessage();
212   void Process() override;
213   void ProcessSlow();
214   void ResetScreenSaver();
215   float GetVolumePercent() const;
216   float GetVolumeRatio() const;
217   void SetVolume(float iValue, bool isPercentage = true);
218   bool IsMuted() const;
IsMutedInternal()219   bool IsMutedInternal() const { return m_muted; }
220   void ToggleMute(void);
221   void SetMute(bool mute);
222   void ShowVolumeBar(const CAction *action = NULL);
223   int GetSubtitleDelay();
224   int GetAudioDelay();
225   void ResetSystemIdleTimer();
226   void ResetScreenSaverTimer();
227   void StopScreenSaverTimer();
228   // Wakes up from the screensaver and / or DPMS. Returns true if woken up.
229   bool WakeUpScreenSaverAndDPMS(bool bPowerOffKeyPressed = false);
230   bool WakeUpScreenSaver(bool bPowerOffKeyPressed = false);
231   /*!
232    \brief Returns the total time in fractional seconds of the currently playing media
233 
234    Beware that this method returns fractional seconds whereas IPlayer::GetTotalTime() returns milliseconds.
235    */
236   double GetTotalTime() const;
237   /*!
238    \brief Returns the current time in fractional seconds of the currently playing media
239 
240    Beware that this method returns fractional seconds whereas IPlayer::GetTime() returns milliseconds.
241    */
242   double GetTime() const;
243   float GetPercentage() const;
244 
245   // Get the percentage of data currently cached/buffered (aq/vq + FileCache) from the input stream if applicable.
246   float GetCachePercentage() const;
247 
248   void SeekPercentage(float percent);
249   void SeekTime( double dTime = 0.0 );
250 
251   void StopShutdownTimer();
252   void ResetShutdownTimers();
253 
254   void StopVideoScan();
255   void StopMusicScan();
256   bool IsMusicScanning() const;
257   bool IsVideoScanning() const;
258 
259   /*!
260    \brief Starts a video library cleanup.
261    \param userInitiated Whether the action was initiated by the user (either via GUI or any other method) or not.  It is meant to hide or show dialogs.
262    \param content Content type to clean, blank for everything
263    \param strDirectory The path to clean or "" (empty string) for a global clean.
264    */
265   void StartVideoCleanup(bool userInitiated = true, const std::string& content = "", const std::string& strDirectory = "");
266 
267   /*!
268    \brief Starts a video library update.
269    \param path The path to scan or "" (empty string) for a global scan.
270    \param userInitiated Whether the action was initiated by the user (either via GUI or any other method) or not.  It is meant to hide or show dialogs.
271    \param scanAll Whether to scan everything not already scanned (regardless of whether the user normally doesn't want a folder scanned).
272    */
273   void StartVideoScan(const std::string &path, bool userInitiated = true, bool scanAll = false);
274 
275   /*!
276   \brief Starts a music library cleanup.
277   \param userInitiated Whether the action was initiated by the user (either via GUI or any other method) or not.  It is meant to hide or show dialogs.
278   */
279   void StartMusicCleanup(bool userInitiated = true);
280 
281   /*!
282    \brief Starts a music library update.
283    \param path The path to scan or "" (empty string) for a global scan.
284    \param userInitiated Whether the action was initiated by the user (either via GUI or any other method) or not.  It is meant to hide or show dialogs.
285    \param flags Flags for controlling the scanning process.  See xbmc/music/infoscanner/MusicInfoScanner.h for possible values.
286    */
287   void StartMusicScan(const std::string &path, bool userInitiated = true, int flags = 0);
288   void StartMusicAlbumScan(const std::string& strDirectory, bool refresh = false);
289   void StartMusicArtistScan(const std::string& strDirectory, bool refresh = false);
290 
291   void UpdateLibraries();
292 
293   void UpdateCurrentPlayArt();
294 
295   bool ExecuteXBMCAction(std::string action, const CGUIListItemPtr &item = NULL);
296 
297 #ifdef HAS_DVD_DRIVE
298   std::unique_ptr<MEDIA_DETECT::CAutorun> m_Autorun;
299 #endif
300 
301 #if !defined(TARGET_WINDOWS) && defined(HAS_DVD_DRIVE)
302   MEDIA_DETECT::CDetectDVDMedia m_DetectDVDType;
303 #endif
304 
IsInScreenSaver()305   inline bool IsInScreenSaver() { return m_screensaverActive; };
ScreensaverIdInUse()306   inline std::string ScreensaverIdInUse() { return m_screensaverIdInUse; }
307 
IsDPMSActive()308   inline bool IsDPMSActive() { return m_dpmsIsActive; };
309   int m_iScreenSaveLock = 0; // spiff: are we checking for a lock? if so, ignore the screensaver state, if -1 we have failed to input locks
310 
311   std::string m_strPlayListFile;
312 
313   int GlobalIdleTime();
314 
PlatformDirectoriesEnabled()315   bool PlatformDirectoriesEnabled() { return m_bPlatformDirectories; }
IsStandAlone()316   bool IsStandAlone() { return m_bStandalone; }
IsEnableTestMode()317   bool IsEnableTestMode() { return m_bTestMode; }
318 
IsAppFocused()319   bool IsAppFocused() const { return m_AppFocused; }
320 
321   void Minimize();
322   bool ToggleDPMS(bool manual);
323 
324   bool SwitchToFullScreen(bool force = false);
325 
GetRenderGUI()326   bool GetRenderGUI() const override { return m_renderGUI; };
327 
328   bool SetLanguage(const std::string &strLanguage);
329   bool LoadLanguage(bool reload);
330 
GetReplayGainSettings()331   ReplayGainSettings& GetReplayGainSettings() { return m_replayGainSettings; }
332 
333   void SetLoggingIn(bool switchingProfiles);
334 
335   /*!
336    \brief Register an action listener.
337    \param listener The listener to register
338    */
339   void RegisterActionListener(IActionListener *listener);
340   /*!
341    \brief Unregister an action listener.
342    \param listener The listener to unregister
343    */
344   void UnregisterActionListener(IActionListener *listener);
345 
346   std::unique_ptr<CServiceManager> m_ServiceManager;
347 
348   /*!
349   \brief Locks calls from outside kodi (e.g. python) until framemove is processed.
350   */
351   void LockFrameMoveGuard();
352 
353   /*!
354   \brief Unlocks calls from outside kodi (e.g. python).
355   */
356   void UnlockFrameMoveGuard();
357 
358   void SetRenderGUI(bool renderGUI);
359 
360 protected:
361   bool OnSettingsSaving() const override;
362   bool Load(const TiXmlNode *settings) override;
363   bool Save(TiXmlNode *settings) const override;
364   void OnSettingChanged(const std::shared_ptr<const CSetting>& setting) override;
365   void OnSettingAction(const std::shared_ptr<const CSetting>& setting) override;
366   bool OnSettingUpdate(const std::shared_ptr<CSetting>& setting,
367                        const char* oldSettingId,
368                        const TiXmlNode* oldSettingNode) override;
369 
370   bool LoadSkin(const std::string& skinID);
371 
372   void CheckOSScreenSaverInhibitionSetting();
373   void PlaybackCleanup();
374 
375   // inbound protocol
376   bool OnEvent(XBMC_Event& newEvent);
377 
378   /*!
379    \brief Delegates the action to all registered action handlers.
380    \param action The action
381    \return true, if the action was taken by one of the action listener.
382    */
383   bool NotifyActionListeners(const CAction &action) const;
384 
385   std::shared_ptr<ANNOUNCEMENT::CAnnouncementManager> m_pAnnouncementManager;
386   std::unique_ptr<CSettingsComponent> m_pSettingsComponent;
387   std::unique_ptr<CGUIComponent> m_pGUI;
388   std::unique_ptr<CWinSystemBase> m_pWinSystem;
389   std::unique_ptr<ActiveAE::CActiveAE> m_pActiveAE;
390   std::shared_ptr<CAppInboundProtocol> m_pAppPort;
391   std::deque<XBMC_Event> m_portEvents;
392   CCriticalSection m_portSection;
393 
394   bool m_confirmSkinChange = true;
395   bool m_ignoreSkinSettingChanges = false;
396 
397   bool m_saveSkinOnUnloading = true;
398 
399 #if defined(TARGET_DARWIN_IOS)
400   friend class CWinEventsIOS;
401 #endif
402 #if defined(TARGET_DARWIN_TVOS)
403   friend class CWinEventsTVOS;
404 #endif
405 #if defined(TARGET_ANDROID)
406   friend class CWinEventsAndroid;
407 #endif
408   // screensaver
409   bool m_screensaverActive = false;
410   std::string m_screensaverIdInUse;
411   ADDON::AddonPtr m_pythonScreenSaver; // @warning: Fallback for Python interface, for binaries not needed!
412   // OS screen saver inhibitor that is always active if user selected a Kodi screen saver
413   KODI::WINDOWING::COSScreenSaverInhibitor m_globalScreensaverInhibitor;
414   // Inhibitor that is active e.g. during video playback
415   KODI::WINDOWING::COSScreenSaverInhibitor m_screensaverInhibitor;
416 
417   // timer information
418 #ifdef TARGET_WINDOWS
419   CWinIdleTimer m_idleTimer;
420   CWinIdleTimer m_screenSaverTimer;
421 #else
422   CStopWatch m_idleTimer;
423   CStopWatch m_screenSaverTimer;
424 #endif
425   CStopWatch m_restartPlayerTimer;
426   CStopWatch m_frameTime;
427   CStopWatch m_navigationTimer;
428   CStopWatch m_slowTimer;
429   CStopWatch m_shutdownTimer;
430   XbmcThreads::EndTime m_guiRefreshTimer;
431 
432   bool m_bInhibitIdleShutdown = false;
433   bool m_bInhibitScreenSaver = false;
434 
435   bool m_dpmsIsActive = false;
436   bool m_dpmsIsManual = false;
437 
438   CFileItemPtr m_itemCurrentFile;
439 
440   std::string m_prevMedia;
441   std::thread::id m_threadID;       // application thread ID.  Used in applicationMessenger to know where we are firing a thread with delay from.
442   bool m_bInitializing = true;
443   bool m_bPlatformDirectories = true;
444 
445   int m_nextPlaylistItem = -1;
446 
447   unsigned int m_lastRenderTime = 0;
448   bool m_skipGuiRender = false;
449 
450   bool m_bStandalone = false;
451   bool m_bTestMode = false;
452   bool m_bSystemScreenSaverEnable = false;
453 
454   std::unique_ptr<MUSIC_INFO::CMusicInfoScanner> m_musicInfoScanner;
455 
456   bool m_muted = false;
457   float m_volumeLevel = VOLUME_MAXIMUM;
458 
459   void Mute();
460   void UnMute();
461 
462   void SetHardwareVolume(float hardwareVolume);
463 
464   void VolumeChanged();
465 
466   bool PlayStack(CFileItem& item, bool bRestart);
467 
468   float NavigationIdleTime();
469   void HandlePortEvents();
470 
471   /*! \brief Helper method to determine how to handle TMSG_SHUTDOWN
472   */
473   void HandleShutdownMessage();
474 
475   CInertialScrollingHandler *m_pInertialScrollingHandler;
476 
477   ReplayGainSettings m_replayGainSettings;
478   std::vector<IActionListener *> m_actionListeners;
479   std::vector<ADDON::AddonInfoPtr>
480       m_incompatibleAddons; /*!< Result of addon migration (incompatible addon infos) */
481 
482 private:
483   void ResetCurrentItem();
484 
485   mutable CCriticalSection m_critSection; /*!< critical section for all changes to this class, except for changes to triggers */
486 
487   CCriticalSection m_frameMoveGuard;              /*!< critical section for synchronizing GUI actions from inside and outside (python) */
488   std::atomic_uint m_WaitingExternalCalls;        /*!< counts threads wich are waiting to be processed in FrameMove */
489   unsigned int m_ProcessedExternalCalls = 0;          /*!< counts calls wich are processed during one "door open" cycle in FrameMove */
490   unsigned int m_ProcessedExternalDecay = 0;      /*!< counts to close door after a few frames of no python activity */
491   CApplicationPlayer m_appPlayer;
492   CEvent m_playerEvent;
493   CApplicationStackHelper m_stackHelper;
494   std::string m_windowing;
495 };
496 
497 XBMC_GLOBAL_REF(CApplication,g_application);
498 #define g_application XBMC_GLOBAL_USE(CApplication)
499